Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/pl111: Support Nomadik LCDC variant

The Nomadik has a variant of the PL110 known as "Color LCD
Controller" LCDC. This variant has the same bit ordering as
the DRM subsystem (in difference from the other variants)
and adds a few bits for the control of 5551, 565 etc in the
control register. Notably it also adds a packed RGB888
24BPP mode.

We add support by detecting this variant and also adding a
small plug-in that will mux the LCDC out if the ASIC happens
to be muxed to the other graphics controller (they are
mutually exclusive).

Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20180621184450.25377-1-linus.walleij@linaro.org

+145 -13
+1
drivers/gpu/drm/pl111/Makefile
··· 4 4 pl111_drv.o 5 5 6 6 pl111_drm-$(CONFIG_ARCH_VEXPRESS) += pl111_vexpress.o 7 + pl111_drm-$(CONFIG_ARCH_NOMADIK) += pl111_nomadik.o 7 8 pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o 8 9 9 10 obj-$(CONFIG_DRM_PL111) += pl111_drm.o
+45 -9
drivers/gpu/drm/pl111/pl111_display.c
··· 223 223 224 224 /* Hard-code TFT panel */ 225 225 cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDVCOMP(1); 226 + /* On the ST Micro variant, assume all 24 bits are connected */ 227 + if (priv->variant->st_bitmux_control) 228 + cntl |= CNTL_ST_CDWID_24; 226 229 227 - /* Note that the the hardware's format reader takes 'r' from 230 + /* 231 + * Note that the the ARM hardware's format reader takes 'r' from 228 232 * the low bit, while DRM formats list channels from high bit 229 - * to low bit as you read left to right. 233 + * to low bit as you read left to right. The ST Micro version of 234 + * the PL110 (LCDC) however uses the standard DRM format. 230 235 */ 231 236 switch (fb->format->format) { 237 + case DRM_FORMAT_BGR888: 238 + /* Only supported on the ST Micro variant */ 239 + if (priv->variant->st_bitmux_control) 240 + cntl |= CNTL_ST_LCDBPP24_PACKED | CNTL_BGR; 241 + break; 242 + case DRM_FORMAT_RGB888: 243 + /* Only supported on the ST Micro variant */ 244 + if (priv->variant->st_bitmux_control) 245 + cntl |= CNTL_ST_LCDBPP24_PACKED; 246 + break; 232 247 case DRM_FORMAT_ABGR8888: 233 248 case DRM_FORMAT_XBGR8888: 234 - cntl |= CNTL_LCDBPP24; 249 + if (priv->variant->st_bitmux_control) 250 + cntl |= CNTL_LCDBPP24 | CNTL_BGR; 251 + else 252 + cntl |= CNTL_LCDBPP24; 235 253 break; 236 254 case DRM_FORMAT_ARGB8888: 237 255 case DRM_FORMAT_XRGB8888: 238 - cntl |= CNTL_LCDBPP24 | CNTL_BGR; 256 + if (priv->variant->st_bitmux_control) 257 + cntl |= CNTL_LCDBPP24; 258 + else 259 + cntl |= CNTL_LCDBPP24 | CNTL_BGR; 239 260 break; 240 261 case DRM_FORMAT_BGR565: 241 262 if (priv->variant->is_pl110) 242 263 cntl |= CNTL_LCDBPP16; 264 + else if (priv->variant->st_bitmux_control) 265 + cntl |= CNTL_LCDBPP16 | CNTL_ST_1XBPP_565 | CNTL_BGR; 243 266 else 244 267 cntl |= CNTL_LCDBPP16_565; 245 268 break; 246 269 case DRM_FORMAT_RGB565: 247 270 if (priv->variant->is_pl110) 248 - cntl |= CNTL_LCDBPP16; 271 + cntl |= CNTL_LCDBPP16 | CNTL_BGR; 272 + else if (priv->variant->st_bitmux_control) 273 + cntl |= CNTL_LCDBPP16 | CNTL_ST_1XBPP_565; 249 274 else 250 - cntl |= CNTL_LCDBPP16_565; 251 - cntl |= CNTL_BGR; 275 + cntl |= CNTL_LCDBPP16_565 | CNTL_BGR; 252 276 break; 253 277 case DRM_FORMAT_ABGR1555: 254 278 case DRM_FORMAT_XBGR1555: 255 279 cntl |= CNTL_LCDBPP16; 280 + if (priv->variant->st_bitmux_control) 281 + cntl |= CNTL_ST_1XBPP_5551 | CNTL_BGR; 256 282 break; 257 283 case DRM_FORMAT_ARGB1555: 258 284 case DRM_FORMAT_XRGB1555: 259 - cntl |= CNTL_LCDBPP16 | CNTL_BGR; 285 + cntl |= CNTL_LCDBPP16; 286 + if (priv->variant->st_bitmux_control) 287 + cntl |= CNTL_ST_1XBPP_5551; 288 + else 289 + cntl |= CNTL_BGR; 260 290 break; 261 291 case DRM_FORMAT_ABGR4444: 262 292 case DRM_FORMAT_XBGR4444: 263 293 cntl |= CNTL_LCDBPP16_444; 294 + if (priv->variant->st_bitmux_control) 295 + cntl |= CNTL_ST_1XBPP_444 | CNTL_BGR; 264 296 break; 265 297 case DRM_FORMAT_ARGB4444: 266 298 case DRM_FORMAT_XRGB4444: 267 - cntl |= CNTL_LCDBPP16_444 | CNTL_BGR; 299 + cntl |= CNTL_LCDBPP16_444; 300 + if (priv->variant->st_bitmux_control) 301 + cntl |= CNTL_ST_1XBPP_444; 302 + else 303 + cntl |= CNTL_BGR; 268 304 break; 269 305 default: 270 306 WARN_ONCE(true, "Unknown FB format 0x%08x\n",
+5
drivers/gpu/drm/pl111/pl111_drm.h
··· 36 36 * struct pl111_variant_data - encodes IP differences 37 37 * @name: the name of this variant 38 38 * @is_pl110: this is the early PL110 variant 39 + * @is_lcdc: this is the ST Microelectronics Nomadik LCDC variant 39 40 * @external_bgr: this is the Versatile Pl110 variant with external 40 41 * BGR/RGB routing 41 42 * @broken_clockdivider: the clock divider is broken and we need to 42 43 * use the supplied clock directly 43 44 * @broken_vblank: the vblank IRQ is broken on this variant 45 + * @st_bitmux_control: this variant is using the ST Micro bitmux 46 + * extensions to the control register 44 47 * @formats: array of supported pixel formats on this variant 45 48 * @nformats: the length of the array of supported pixel formats 46 49 * @fb_bpp: desired bits per pixel on the default framebuffer ··· 51 48 struct pl111_variant_data { 52 49 const char *name; 53 50 bool is_pl110; 51 + bool is_lcdc; 54 52 bool external_bgr; 55 53 bool broken_clockdivider; 56 54 bool broken_vblank; 55 + bool st_bitmux_control; 57 56 const u32 *formats; 58 57 unsigned int nformats; 59 58 unsigned int fb_bpp;
+40 -4
drivers/gpu/drm/pl111/pl111_drv.c
··· 75 75 76 76 #include "pl111_drm.h" 77 77 #include "pl111_versatile.h" 78 + #include "pl111_nomadik.h" 78 79 79 80 #define DRIVER_DESC "DRM module for PL111" 80 81 ··· 289 288 priv->memory_bw = 0; 290 289 } 291 290 292 - /* The two variants swap this register */ 293 - if (variant->is_pl110) { 291 + /* The two main variants swap this register */ 292 + if (variant->is_pl110 || variant->is_lcdc) { 294 293 priv->ienb = CLCD_PL110_IENB; 295 294 priv->ctrl = CLCD_PL110_CNTL; 296 295 } else { ··· 309 308 ret = pl111_versatile_init(dev, priv); 310 309 if (ret) 311 310 goto dev_unref; 311 + pl111_nomadik_init(dev); 312 312 313 313 /* turn off interrupts before requesting the irq */ 314 314 writel(0, priv->regs + priv->ienb); ··· 402 400 .fb_bpp = 32, 403 401 }; 404 402 403 + static const u32 pl110_nomadik_pixel_formats[] = { 404 + DRM_FORMAT_RGB888, 405 + DRM_FORMAT_BGR888, 406 + DRM_FORMAT_ABGR8888, 407 + DRM_FORMAT_XBGR8888, 408 + DRM_FORMAT_ARGB8888, 409 + DRM_FORMAT_XRGB8888, 410 + DRM_FORMAT_BGR565, 411 + DRM_FORMAT_RGB565, 412 + DRM_FORMAT_ABGR1555, 413 + DRM_FORMAT_XBGR1555, 414 + DRM_FORMAT_ARGB1555, 415 + DRM_FORMAT_XRGB1555, 416 + DRM_FORMAT_ABGR4444, 417 + DRM_FORMAT_XBGR4444, 418 + DRM_FORMAT_ARGB4444, 419 + DRM_FORMAT_XRGB4444, 420 + }; 421 + 422 + static const struct pl111_variant_data pl110_nomadik_variant = { 423 + .name = "LCDC (PL110 Nomadik)", 424 + .formats = pl110_nomadik_pixel_formats, 425 + .nformats = ARRAY_SIZE(pl110_nomadik_pixel_formats), 426 + .is_lcdc = true, 427 + .st_bitmux_control = true, 428 + .broken_vblank = true, 429 + .fb_bpp = 16, 430 + }; 431 + 405 432 static const struct amba_id pl111_id_table[] = { 406 433 { 407 434 .id = 0x00041110, 408 435 .mask = 0x000fffff, 409 - .data = (void*)&pl110_variant, 436 + .data = (void *)&pl110_variant, 437 + }, 438 + { 439 + .id = 0x00180110, 440 + .mask = 0x00fffffe, 441 + .data = (void *)&pl110_nomadik_variant, 410 442 }, 411 443 { 412 444 .id = 0x00041111, 413 445 .mask = 0x000fffff, 414 - .data = (void*)&pl111_variant, 446 + .data = (void *)&pl111_variant, 415 447 }, 416 448 {0, 0}, 417 449 };
+36
drivers/gpu/drm/pl111/pl111_nomadik.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + #include <linux/device.h> 3 + #include <linux/regmap.h> 4 + #include <linux/mfd/syscon.h> 5 + #include <linux/bitops.h> 6 + #include <linux/module.h> 7 + #include "pl111_nomadik.h" 8 + 9 + #define PMU_CTRL_OFFSET 0x0000 10 + #define PMU_CTRL_LCDNDIF BIT(26) 11 + 12 + void pl111_nomadik_init(struct device *dev) 13 + { 14 + struct regmap *pmu_regmap; 15 + 16 + /* 17 + * Just bail out of this is not found, we could be running 18 + * multiplatform on something else than Nomadik. 19 + */ 20 + pmu_regmap = 21 + syscon_regmap_lookup_by_compatible("stericsson,nomadik-pmu"); 22 + if (IS_ERR(pmu_regmap)) 23 + return; 24 + 25 + /* 26 + * This bit in the PMU controller multiplexes the two graphics 27 + * blocks found in the Nomadik STn8815. The other one is called 28 + * MDIF (Master Display Interface) and gets muxed out here. 29 + */ 30 + regmap_update_bits(pmu_regmap, 31 + PMU_CTRL_OFFSET, 32 + PMU_CTRL_LCDNDIF, 33 + 0); 34 + dev_info(dev, "set Nomadik PMU mux to CLCD mode\n"); 35 + } 36 + EXPORT_SYMBOL_GPL(pl111_nomadik_init);
+18
drivers/gpu/drm/pl111/pl111_nomadik.h
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + #include <linux/device.h> 3 + 4 + #ifndef PL111_NOMADIK_H 5 + #define PL111_NOMADIK_H 6 + #endif 7 + 8 + #ifdef CONFIG_ARCH_NOMADIK 9 + 10 + void pl111_nomadik_init(struct device *dev); 11 + 12 + #else 13 + 14 + static inline void pl111_nomadik_init(struct device *dev) 15 + { 16 + } 17 + 18 + #endif