diff options
| author | Dave Airlie <airlied@redhat.com> | 2015-02-11 00:34:02 -0500 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2015-02-11 00:34:02 -0500 |
| commit | 79a44c16b155b799421f5497ae888985a5d7f80c (patch) | |
| tree | 5c3cef9c504703a5eda86160a227fe367b944329 | |
| parent | ae6d57d12ab3bc833a1a9ca252cc49280713181b (diff) | |
| parent | cffe1e89dc9bf541a39d9287ced7c5addff07084 (diff) | |
Merge branch 'drm-sti-next-2015-02-04' of git://git.linaro.org/people/benjamin.gaignard/kernel into drm-next
Those patches improve audio info frame management, add pixel formats
support and fix minor issues.
* 'drm-sti-next-2015-02-04' of git://git.linaro.org/people/benjamin.gaignard/kernel:
drm: sti: HDMI add audio infoframe
drm: sti: add support of XBGR8888 for gdp plane
drm: sti: add support of ABGR8888 for gdp plane
drm: sti: fix static checker warning in sti_awg_utils
drm: sti: fix check for clk_pix_main
| -rw-r--r-- | drivers/gpu/drm/sti/sti_awg_utils.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_gdp.c | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_hdmi.c | 179 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_hqvdp.c | 2 |
4 files changed, 149 insertions, 45 deletions
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c index 9fde3ee8b1a5..6029a2e3db1d 100644 --- a/drivers/gpu/drm/sti/sti_awg_utils.c +++ b/drivers/gpu/drm/sti/sti_awg_utils.c | |||
| @@ -60,8 +60,6 @@ static int awg_generate_instr(enum opcode opcode, | |||
| 60 | * pixel. So we transform SKIP into SET | 60 | * pixel. So we transform SKIP into SET |
| 61 | * instruction */ | 61 | * instruction */ |
| 62 | opcode = SET; | 62 | opcode = SET; |
| 63 | arg = (arg << 24) >> 24; | ||
| 64 | arg &= (0x0ff); | ||
| 65 | break; | 63 | break; |
| 66 | } | 64 | } |
| 67 | 65 | ||
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 32448d1d1e8f..087906fd8846 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c | |||
| @@ -14,15 +14,19 @@ | |||
| 14 | #include "sti_layer.h" | 14 | #include "sti_layer.h" |
| 15 | #include "sti_vtg.h" | 15 | #include "sti_vtg.h" |
| 16 | 16 | ||
| 17 | #define ALPHASWITCH BIT(6) | ||
| 17 | #define ENA_COLOR_FILL BIT(8) | 18 | #define ENA_COLOR_FILL BIT(8) |
| 19 | #define BIGNOTLITTLE BIT(23) | ||
| 18 | #define WAIT_NEXT_VSYNC BIT(31) | 20 | #define WAIT_NEXT_VSYNC BIT(31) |
| 19 | 21 | ||
| 20 | /* GDP color formats */ | 22 | /* GDP color formats */ |
| 21 | #define GDP_RGB565 0x00 | 23 | #define GDP_RGB565 0x00 |
| 22 | #define GDP_RGB888 0x01 | 24 | #define GDP_RGB888 0x01 |
| 23 | #define GDP_RGB888_32 0x02 | 25 | #define GDP_RGB888_32 0x02 |
| 26 | #define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH) | ||
| 24 | #define GDP_ARGB8565 0x04 | 27 | #define GDP_ARGB8565 0x04 |
| 25 | #define GDP_ARGB8888 0x05 | 28 | #define GDP_ARGB8888 0x05 |
| 29 | #define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) | ||
| 26 | #define GDP_ARGB1555 0x06 | 30 | #define GDP_ARGB1555 0x06 |
| 27 | #define GDP_ARGB4444 0x07 | 31 | #define GDP_ARGB4444 0x07 |
| 28 | #define GDP_CLUT8 0x0B | 32 | #define GDP_CLUT8 0x0B |
| @@ -103,7 +107,9 @@ struct sti_gdp { | |||
| 103 | 107 | ||
| 104 | static const uint32_t gdp_supported_formats[] = { | 108 | static const uint32_t gdp_supported_formats[] = { |
| 105 | DRM_FORMAT_XRGB8888, | 109 | DRM_FORMAT_XRGB8888, |
| 110 | DRM_FORMAT_XBGR8888, | ||
| 106 | DRM_FORMAT_ARGB8888, | 111 | DRM_FORMAT_ARGB8888, |
| 112 | DRM_FORMAT_ABGR8888, | ||
| 107 | DRM_FORMAT_ARGB4444, | 113 | DRM_FORMAT_ARGB4444, |
| 108 | DRM_FORMAT_ARGB1555, | 114 | DRM_FORMAT_ARGB1555, |
| 109 | DRM_FORMAT_RGB565, | 115 | DRM_FORMAT_RGB565, |
| @@ -129,8 +135,12 @@ static int sti_gdp_fourcc2format(int fourcc) | |||
| 129 | switch (fourcc) { | 135 | switch (fourcc) { |
| 130 | case DRM_FORMAT_XRGB8888: | 136 | case DRM_FORMAT_XRGB8888: |
| 131 | return GDP_RGB888_32; | 137 | return GDP_RGB888_32; |
| 138 | case DRM_FORMAT_XBGR8888: | ||
| 139 | return GDP_XBGR8888; | ||
| 132 | case DRM_FORMAT_ARGB8888: | 140 | case DRM_FORMAT_ARGB8888: |
| 133 | return GDP_ARGB8888; | 141 | return GDP_ARGB8888; |
| 142 | case DRM_FORMAT_ABGR8888: | ||
| 143 | return GDP_ABGR8888; | ||
| 134 | case DRM_FORMAT_ARGB4444: | 144 | case DRM_FORMAT_ARGB4444: |
| 135 | return GDP_ARGB4444; | 145 | return GDP_ARGB4444; |
| 136 | case DRM_FORMAT_ARGB1555: | 146 | case DRM_FORMAT_ARGB1555: |
| @@ -157,6 +167,7 @@ static int sti_gdp_get_alpharange(int format) | |||
| 157 | case GDP_ARGB8565: | 167 | case GDP_ARGB8565: |
| 158 | case GDP_ARGB8888: | 168 | case GDP_ARGB8888: |
| 159 | case GDP_AYCBR8888: | 169 | case GDP_AYCBR8888: |
| 170 | case GDP_ABGR8888: | ||
| 160 | return GAM_GDP_ALPHARANGE_255; | 171 | return GAM_GDP_ALPHARANGE_255; |
| 161 | } | 172 | } |
| 162 | return 0; | 173 | return 0; |
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index e840ca5de401..1485ade98710 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c | |||
| @@ -42,8 +42,17 @@ | |||
| 42 | #define HDMI_SW_DI_1_PKT_WORD5 0x0228 | 42 | #define HDMI_SW_DI_1_PKT_WORD5 0x0228 |
| 43 | #define HDMI_SW_DI_1_PKT_WORD6 0x022C | 43 | #define HDMI_SW_DI_1_PKT_WORD6 0x022C |
| 44 | #define HDMI_SW_DI_CFG 0x0230 | 44 | #define HDMI_SW_DI_CFG 0x0230 |
| 45 | #define HDMI_SW_DI_2_HEAD_WORD 0x0600 | ||
| 46 | #define HDMI_SW_DI_2_PKT_WORD0 0x0604 | ||
| 47 | #define HDMI_SW_DI_2_PKT_WORD1 0x0608 | ||
| 48 | #define HDMI_SW_DI_2_PKT_WORD2 0x060C | ||
| 49 | #define HDMI_SW_DI_2_PKT_WORD3 0x0610 | ||
| 50 | #define HDMI_SW_DI_2_PKT_WORD4 0x0614 | ||
| 51 | #define HDMI_SW_DI_2_PKT_WORD5 0x0618 | ||
| 52 | #define HDMI_SW_DI_2_PKT_WORD6 0x061C | ||
| 45 | 53 | ||
| 46 | #define HDMI_IFRAME_SLOT_AVI 1 | 54 | #define HDMI_IFRAME_SLOT_AVI 1 |
| 55 | #define HDMI_IFRAME_SLOT_AUDIO 2 | ||
| 47 | 56 | ||
| 48 | #define XCAT(prefix, x, suffix) prefix ## x ## suffix | 57 | #define XCAT(prefix, x, suffix) prefix ## x ## suffix |
| 49 | #define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD) | 58 | #define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD) |
| @@ -99,6 +108,10 @@ | |||
| 99 | 108 | ||
| 100 | #define HDMI_STA_SW_RST BIT(1) | 109 | #define HDMI_STA_SW_RST BIT(1) |
| 101 | 110 | ||
| 111 | #define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0) | ||
| 112 | #define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) | ||
| 113 | #define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16) | ||
| 114 | |||
| 102 | struct sti_hdmi_connector { | 115 | struct sti_hdmi_connector { |
| 103 | struct drm_connector drm_connector; | 116 | struct drm_connector drm_connector; |
| 104 | struct drm_encoder *encoder; | 117 | struct drm_encoder *encoder; |
| @@ -228,6 +241,90 @@ static void hdmi_config(struct sti_hdmi *hdmi) | |||
| 228 | } | 241 | } |
| 229 | 242 | ||
| 230 | /** | 243 | /** |
| 244 | * Helper to concatenate infoframe in 32 bits word | ||
| 245 | * | ||
| 246 | * @ptr: pointer on the hdmi internal structure | ||
| 247 | * @data: infoframe to write | ||
| 248 | * @size: size to write | ||
| 249 | */ | ||
| 250 | static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size) | ||
| 251 | { | ||
| 252 | unsigned long value = 0; | ||
| 253 | size_t i; | ||
| 254 | |||
| 255 | for (i = size; i > 0; i--) | ||
| 256 | value = (value << 8) | ptr[i - 1]; | ||
| 257 | |||
| 258 | return value; | ||
| 259 | } | ||
| 260 | |||
| 261 | /** | ||
| 262 | * Helper to write info frame | ||
| 263 | * | ||
| 264 | * @hdmi: pointer on the hdmi internal structure | ||
| 265 | * @data: infoframe to write | ||
| 266 | * @size: size to write | ||
| 267 | */ | ||
| 268 | static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data) | ||
| 269 | { | ||
| 270 | const u8 *ptr = data; | ||
| 271 | u32 val, slot, mode, i; | ||
| 272 | u32 head_offset, pack_offset; | ||
| 273 | size_t size; | ||
| 274 | |||
| 275 | switch (*ptr) { | ||
| 276 | case HDMI_INFOFRAME_TYPE_AVI: | ||
| 277 | slot = HDMI_IFRAME_SLOT_AVI; | ||
| 278 | mode = HDMI_IFRAME_FIELD; | ||
| 279 | head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI); | ||
| 280 | pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI); | ||
| 281 | size = HDMI_AVI_INFOFRAME_SIZE; | ||
| 282 | break; | ||
| 283 | |||
| 284 | case HDMI_INFOFRAME_TYPE_AUDIO: | ||
| 285 | slot = HDMI_IFRAME_SLOT_AUDIO; | ||
| 286 | mode = HDMI_IFRAME_FRAME; | ||
| 287 | head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO); | ||
| 288 | pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO); | ||
| 289 | size = HDMI_AUDIO_INFOFRAME_SIZE; | ||
| 290 | break; | ||
| 291 | |||
| 292 | default: | ||
| 293 | DRM_ERROR("unsupported infoframe type: %#x\n", *ptr); | ||
| 294 | return; | ||
| 295 | } | ||
| 296 | |||
| 297 | /* Disable transmission slot for updated infoframe */ | ||
| 298 | val = hdmi_read(hdmi, HDMI_SW_DI_CFG); | ||
| 299 | val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot); | ||
| 300 | hdmi_write(hdmi, val, HDMI_SW_DI_CFG); | ||
| 301 | |||
| 302 | val = HDMI_INFOFRAME_HEADER_TYPE(*ptr++); | ||
| 303 | val |= HDMI_INFOFRAME_HEADER_VERSION(*ptr++); | ||
| 304 | val |= HDMI_INFOFRAME_HEADER_LEN(*ptr++); | ||
| 305 | writel(val, hdmi->regs + head_offset); | ||
| 306 | |||
| 307 | /* | ||
| 308 | * Each subpack contains 4 bytes | ||
| 309 | * The First Bytes of the first subpacket must contain the checksum | ||
| 310 | * Packet size in increase by one. | ||
| 311 | */ | ||
| 312 | for (i = 0; i < size; i += sizeof(u32)) { | ||
| 313 | size_t num; | ||
| 314 | |||
| 315 | num = min_t(size_t, size - i, sizeof(u32)); | ||
| 316 | val = hdmi_infoframe_subpack(ptr, num); | ||
| 317 | ptr += sizeof(u32); | ||
| 318 | writel(val, hdmi->regs + pack_offset + i); | ||
| 319 | } | ||
| 320 | |||
| 321 | /* Enable transmission slot for updated infoframe */ | ||
| 322 | val = hdmi_read(hdmi, HDMI_SW_DI_CFG); | ||
| 323 | val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, slot); | ||
| 324 | hdmi_write(hdmi, val, HDMI_SW_DI_CFG); | ||
| 325 | } | ||
| 326 | |||
| 327 | /** | ||
| 231 | * Prepare and configure the AVI infoframe | 328 | * Prepare and configure the AVI infoframe |
| 232 | * | 329 | * |
| 233 | * AVI infoframe are transmitted at least once per two video field and | 330 | * AVI infoframe are transmitted at least once per two video field and |
| @@ -243,8 +340,6 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) | |||
| 243 | struct drm_display_mode *mode = &hdmi->mode; | 340 | struct drm_display_mode *mode = &hdmi->mode; |
| 244 | struct hdmi_avi_infoframe infoframe; | 341 | struct hdmi_avi_infoframe infoframe; |
| 245 | u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; | 342 | u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; |
| 246 | u8 *frame = buffer + HDMI_INFOFRAME_HEADER_SIZE; | ||
| 247 | u32 val; | ||
| 248 | int ret; | 343 | int ret; |
| 249 | 344 | ||
| 250 | DRM_DEBUG_DRIVER("\n"); | 345 | DRM_DEBUG_DRIVER("\n"); |
| @@ -266,47 +361,43 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) | |||
| 266 | return ret; | 361 | return ret; |
| 267 | } | 362 | } |
| 268 | 363 | ||
| 269 | /* Disable transmission slot for AVI infoframe */ | 364 | hdmi_infoframe_write_infopack(hdmi, buffer); |
| 270 | val = hdmi_read(hdmi, HDMI_SW_DI_CFG); | ||
| 271 | val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, HDMI_IFRAME_SLOT_AVI); | ||
| 272 | hdmi_write(hdmi, val, HDMI_SW_DI_CFG); | ||
| 273 | 365 | ||
| 274 | /* Infoframe header */ | 366 | return 0; |
| 275 | val = buffer[0]; | 367 | } |
| 276 | val |= buffer[1] << 8; | 368 | |
| 277 | val |= buffer[2] << 16; | 369 | /** |
| 278 | hdmi_write(hdmi, val, HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI)); | 370 | * Prepare and configure the AUDIO infoframe |
| 279 | 371 | * | |
| 280 | /* Infoframe packet bytes */ | 372 | * AUDIO infoframe are transmitted once per frame and |
| 281 | val = buffer[3]; | 373 | * contains information about HDMI transmission mode such as audio codec, |
| 282 | val |= *(frame++) << 8; | 374 | * sample size, ... |
| 283 | val |= *(frame++) << 16; | 375 | * |
| 284 | val |= *(frame++) << 24; | 376 | * @hdmi: pointer on the hdmi internal structure |
| 285 | hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI)); | 377 | * |
| 286 | 378 | * Return negative value if error occurs | |
| 287 | val = *(frame++); | 379 | */ |
| 288 | val |= *(frame++) << 8; | 380 | static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi) |
| 289 | val |= *(frame++) << 16; | 381 | { |
| 290 | val |= *(frame++) << 24; | 382 | struct hdmi_audio_infoframe infofame; |
| 291 | hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD1(HDMI_IFRAME_SLOT_AVI)); | 383 | u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)]; |
| 292 | 384 | int ret; | |
| 293 | val = *(frame++); | 385 | |
| 294 | val |= *(frame++) << 8; | 386 | ret = hdmi_audio_infoframe_init(&infofame); |
| 295 | val |= *(frame++) << 16; | 387 | if (ret < 0) { |
| 296 | val |= *(frame++) << 24; | 388 | DRM_ERROR("failed to setup audio infoframe: %d\n", ret); |
| 297 | hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD2(HDMI_IFRAME_SLOT_AVI)); | 389 | return ret; |
| 298 | 390 | } | |
| 299 | val = *(frame++); | 391 | |
| 300 | val |= *(frame) << 8; | 392 | infofame.channels = 2; |
| 301 | hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD3(HDMI_IFRAME_SLOT_AVI)); | 393 | |
| 302 | 394 | ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer)); | |
| 303 | /* Enable transmission slot for AVI infoframe | 395 | if (ret < 0) { |
| 304 | * According to the hdmi specification, AVI infoframe should be | 396 | DRM_ERROR("failed to pack audio infoframe: %d\n", ret); |
| 305 | * transmitted at least once per two video fields | 397 | return ret; |
| 306 | */ | 398 | } |
| 307 | val = hdmi_read(hdmi, HDMI_SW_DI_CFG); | 399 | |
| 308 | val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, HDMI_IFRAME_SLOT_AVI); | 400 | hdmi_infoframe_write_infopack(hdmi, buffer); |
| 309 | hdmi_write(hdmi, val, HDMI_SW_DI_CFG); | ||
| 310 | 401 | ||
| 311 | return 0; | 402 | return 0; |
| 312 | } | 403 | } |
| @@ -427,6 +518,10 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge) | |||
| 427 | if (hdmi_avi_infoframe_config(hdmi)) | 518 | if (hdmi_avi_infoframe_config(hdmi)) |
| 428 | DRM_ERROR("Unable to configure AVI infoframe\n"); | 519 | DRM_ERROR("Unable to configure AVI infoframe\n"); |
| 429 | 520 | ||
| 521 | /* Program AUDIO infoframe */ | ||
| 522 | if (hdmi_audio_infoframe_config(hdmi)) | ||
| 523 | DRM_ERROR("Unable to configure AUDIO infoframe\n"); | ||
| 524 | |||
| 430 | /* Sw reset */ | 525 | /* Sw reset */ |
| 431 | hdmi_swreset(hdmi); | 526 | hdmi_swreset(hdmi); |
| 432 | } | 527 | } |
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index f3db05dab0ab..b0eb62de1b2e 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c | |||
| @@ -1025,7 +1025,7 @@ static int sti_hqvdp_probe(struct platform_device *pdev) | |||
| 1025 | /* Get clock resources */ | 1025 | /* Get clock resources */ |
| 1026 | hqvdp->clk = devm_clk_get(dev, "hqvdp"); | 1026 | hqvdp->clk = devm_clk_get(dev, "hqvdp"); |
| 1027 | hqvdp->clk_pix_main = devm_clk_get(dev, "pix_main"); | 1027 | hqvdp->clk_pix_main = devm_clk_get(dev, "pix_main"); |
| 1028 | if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk)) { | 1028 | if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk_pix_main)) { |
| 1029 | DRM_ERROR("Cannot get clocks\n"); | 1029 | DRM_ERROR("Cannot get clocks\n"); |
| 1030 | return -ENXIO; | 1030 | return -ENXIO; |
| 1031 | } | 1031 | } |
