root/drivers/gpu/drm/pl111/pl111_versatile.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pl111_integrator_enable
  2. pl111_versatile_disable
  3. pl111_versatile_enable
  4. pl111_realview_clcd_disable
  5. pl111_realview_clcd_enable
  6. pl111_versatile_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 
   3 #include <linux/amba/clcd-regs.h>
   4 #include <linux/bitops.h>
   5 #include <linux/device.h>
   6 #include <linux/mfd/syscon.h>
   7 #include <linux/module.h>
   8 #include <linux/of.h>
   9 #include <linux/of_platform.h>
  10 #include <linux/regmap.h>
  11 
  12 #include "pl111_versatile.h"
  13 #include "pl111_vexpress.h"
  14 #include "pl111_drm.h"
  15 
  16 static struct regmap *versatile_syscon_map;
  17 
  18 /*
  19  * We detect the different syscon types from the compatible strings.
  20  */
  21 enum versatile_clcd {
  22         INTEGRATOR_CLCD_CM,
  23         VERSATILE_CLCD,
  24         REALVIEW_CLCD_EB,
  25         REALVIEW_CLCD_PB1176,
  26         REALVIEW_CLCD_PB11MP,
  27         REALVIEW_CLCD_PBA8,
  28         REALVIEW_CLCD_PBX,
  29         VEXPRESS_CLCD_V2M,
  30 };
  31 
  32 static const struct of_device_id versatile_clcd_of_match[] = {
  33         {
  34                 .compatible = "arm,core-module-integrator",
  35                 .data = (void *)INTEGRATOR_CLCD_CM,
  36         },
  37         {
  38                 .compatible = "arm,versatile-sysreg",
  39                 .data = (void *)VERSATILE_CLCD,
  40         },
  41         {
  42                 .compatible = "arm,realview-eb-syscon",
  43                 .data = (void *)REALVIEW_CLCD_EB,
  44         },
  45         {
  46                 .compatible = "arm,realview-pb1176-syscon",
  47                 .data = (void *)REALVIEW_CLCD_PB1176,
  48         },
  49         {
  50                 .compatible = "arm,realview-pb11mp-syscon",
  51                 .data = (void *)REALVIEW_CLCD_PB11MP,
  52         },
  53         {
  54                 .compatible = "arm,realview-pba8-syscon",
  55                 .data = (void *)REALVIEW_CLCD_PBA8,
  56         },
  57         {
  58                 .compatible = "arm,realview-pbx-syscon",
  59                 .data = (void *)REALVIEW_CLCD_PBX,
  60         },
  61         {
  62                 .compatible = "arm,vexpress-muxfpga",
  63                 .data = (void *)VEXPRESS_CLCD_V2M,
  64         },
  65         {},
  66 };
  67 
  68 /*
  69  * Core module CLCD control on the Integrator/CP, bits
  70  * 8 thru 19 of the CM_CONTROL register controls a bunch
  71  * of CLCD settings.
  72  */
  73 #define INTEGRATOR_HDR_CTRL_OFFSET      0x0C
  74 #define INTEGRATOR_CLCD_LCDBIASEN       BIT(8)
  75 #define INTEGRATOR_CLCD_LCDBIASUP       BIT(9)
  76 #define INTEGRATOR_CLCD_LCDBIASDN       BIT(10)
  77 /* Bits 11,12,13 controls the LCD or VGA bridge type */
  78 #define INTEGRATOR_CLCD_LCDMUX_LCD24    BIT(11)
  79 #define INTEGRATOR_CLCD_LCDMUX_SHARP    (BIT(11)|BIT(12))
  80 #define INTEGRATOR_CLCD_LCDMUX_VGA555   BIT(13)
  81 #define INTEGRATOR_CLCD_LCDMUX_VGA24    (BIT(11)|BIT(12)|BIT(13))
  82 #define INTEGRATOR_CLCD_LCD0_EN         BIT(14)
  83 #define INTEGRATOR_CLCD_LCD1_EN         BIT(15)
  84 /* R/L flip on Sharp */
  85 #define INTEGRATOR_CLCD_LCD_STATIC1     BIT(16)
  86 /* U/D flip on Sharp */
  87 #define INTEGRATOR_CLCD_LCD_STATIC2     BIT(17)
  88 /* No connection on Sharp */
  89 #define INTEGRATOR_CLCD_LCD_STATIC      BIT(18)
  90 /* 0 = 24bit VGA, 1 = 18bit VGA */
  91 #define INTEGRATOR_CLCD_LCD_N24BITEN    BIT(19)
  92 
  93 #define INTEGRATOR_CLCD_MASK            GENMASK(19, 8)
  94 
  95 static void pl111_integrator_enable(struct drm_device *drm, u32 format)
  96 {
  97         u32 val;
  98 
  99         dev_info(drm->dev, "enable Integrator CLCD connectors\n");
 100 
 101         /* FIXME: really needed? */
 102         val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
 103                 INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;
 104 
 105         switch (format) {
 106         case DRM_FORMAT_XBGR8888:
 107         case DRM_FORMAT_XRGB8888:
 108                 /* 24bit formats */
 109                 val |= INTEGRATOR_CLCD_LCDMUX_VGA24;
 110                 break;
 111         case DRM_FORMAT_XBGR1555:
 112         case DRM_FORMAT_XRGB1555:
 113                 /* Pseudocolor, RGB555, BGR555 */
 114                 val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
 115                 break;
 116         default:
 117                 dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n",
 118                         format);
 119                 break;
 120         }
 121 
 122         regmap_update_bits(versatile_syscon_map,
 123                            INTEGRATOR_HDR_CTRL_OFFSET,
 124                            INTEGRATOR_CLCD_MASK,
 125                            val);
 126 }
 127 
 128 /*
 129  * This configuration register in the Versatile and RealView
 130  * family is uniformly present but appears more and more
 131  * unutilized starting with the RealView series.
 132  */
 133 #define SYS_CLCD                        0x50
 134 #define SYS_CLCD_MODE_MASK              (BIT(0)|BIT(1))
 135 #define SYS_CLCD_MODE_888               0
 136 #define SYS_CLCD_MODE_5551              BIT(0)
 137 #define SYS_CLCD_MODE_565_R_LSB         BIT(1)
 138 #define SYS_CLCD_MODE_565_B_LSB         (BIT(0)|BIT(1))
 139 #define SYS_CLCD_CONNECTOR_MASK         (BIT(2)|BIT(3)|BIT(4)|BIT(5))
 140 #define SYS_CLCD_NLCDIOON               BIT(2)
 141 #define SYS_CLCD_VDDPOSSWITCH           BIT(3)
 142 #define SYS_CLCD_PWR3V5SWITCH           BIT(4)
 143 #define SYS_CLCD_VDDNEGSWITCH           BIT(5)
 144 
 145 static void pl111_versatile_disable(struct drm_device *drm)
 146 {
 147         dev_info(drm->dev, "disable Versatile CLCD connectors\n");
 148         regmap_update_bits(versatile_syscon_map,
 149                            SYS_CLCD,
 150                            SYS_CLCD_CONNECTOR_MASK,
 151                            0);
 152 }
 153 
 154 static void pl111_versatile_enable(struct drm_device *drm, u32 format)
 155 {
 156         u32 val = 0;
 157 
 158         dev_info(drm->dev, "enable Versatile CLCD connectors\n");
 159 
 160         switch (format) {
 161         case DRM_FORMAT_ABGR8888:
 162         case DRM_FORMAT_XBGR8888:
 163         case DRM_FORMAT_ARGB8888:
 164         case DRM_FORMAT_XRGB8888:
 165                 val |= SYS_CLCD_MODE_888;
 166                 break;
 167         case DRM_FORMAT_BGR565:
 168                 val |= SYS_CLCD_MODE_565_R_LSB;
 169                 break;
 170         case DRM_FORMAT_RGB565:
 171                 val |= SYS_CLCD_MODE_565_B_LSB;
 172                 break;
 173         case DRM_FORMAT_ABGR1555:
 174         case DRM_FORMAT_XBGR1555:
 175         case DRM_FORMAT_ARGB1555:
 176         case DRM_FORMAT_XRGB1555:
 177                 val |= SYS_CLCD_MODE_5551;
 178                 break;
 179         default:
 180                 dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n",
 181                         format);
 182                 break;
 183         }
 184 
 185         /* Set up the MUX */
 186         regmap_update_bits(versatile_syscon_map,
 187                            SYS_CLCD,
 188                            SYS_CLCD_MODE_MASK,
 189                            val);
 190 
 191         /* Then enable the display */
 192         regmap_update_bits(versatile_syscon_map,
 193                            SYS_CLCD,
 194                            SYS_CLCD_CONNECTOR_MASK,
 195                            SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
 196 }
 197 
 198 static void pl111_realview_clcd_disable(struct drm_device *drm)
 199 {
 200         dev_info(drm->dev, "disable RealView CLCD connectors\n");
 201         regmap_update_bits(versatile_syscon_map,
 202                            SYS_CLCD,
 203                            SYS_CLCD_CONNECTOR_MASK,
 204                            0);
 205 }
 206 
 207 static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format)
 208 {
 209         dev_info(drm->dev, "enable RealView CLCD connectors\n");
 210         regmap_update_bits(versatile_syscon_map,
 211                            SYS_CLCD,
 212                            SYS_CLCD_CONNECTOR_MASK,
 213                            SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
 214 }
 215 
 216 /* PL110 pixel formats for Integrator, vanilla PL110 */
 217 static const u32 pl110_integrator_pixel_formats[] = {
 218         DRM_FORMAT_ABGR8888,
 219         DRM_FORMAT_XBGR8888,
 220         DRM_FORMAT_ARGB8888,
 221         DRM_FORMAT_XRGB8888,
 222         DRM_FORMAT_ABGR1555,
 223         DRM_FORMAT_XBGR1555,
 224         DRM_FORMAT_ARGB1555,
 225         DRM_FORMAT_XRGB1555,
 226 };
 227 
 228 /* Extended PL110 pixel formats for Integrator and Versatile */
 229 static const u32 pl110_versatile_pixel_formats[] = {
 230         DRM_FORMAT_ABGR8888,
 231         DRM_FORMAT_XBGR8888,
 232         DRM_FORMAT_ARGB8888,
 233         DRM_FORMAT_XRGB8888,
 234         DRM_FORMAT_BGR565, /* Uses external PLD */
 235         DRM_FORMAT_RGB565, /* Uses external PLD */
 236         DRM_FORMAT_ABGR1555,
 237         DRM_FORMAT_XBGR1555,
 238         DRM_FORMAT_ARGB1555,
 239         DRM_FORMAT_XRGB1555,
 240 };
 241 
 242 static const u32 pl111_realview_pixel_formats[] = {
 243         DRM_FORMAT_ABGR8888,
 244         DRM_FORMAT_XBGR8888,
 245         DRM_FORMAT_ARGB8888,
 246         DRM_FORMAT_XRGB8888,
 247         DRM_FORMAT_BGR565,
 248         DRM_FORMAT_RGB565,
 249         DRM_FORMAT_ABGR1555,
 250         DRM_FORMAT_XBGR1555,
 251         DRM_FORMAT_ARGB1555,
 252         DRM_FORMAT_XRGB1555,
 253         DRM_FORMAT_ABGR4444,
 254         DRM_FORMAT_XBGR4444,
 255         DRM_FORMAT_ARGB4444,
 256         DRM_FORMAT_XRGB4444,
 257 };
 258 
 259 /*
 260  * The Integrator variant is a PL110 with a bunch of broken, or not
 261  * yet implemented features
 262  */
 263 static const struct pl111_variant_data pl110_integrator = {
 264         .name = "PL110 Integrator",
 265         .is_pl110 = true,
 266         .broken_clockdivider = true,
 267         .broken_vblank = true,
 268         .formats = pl110_integrator_pixel_formats,
 269         .nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),
 270         .fb_bpp = 16,
 271 };
 272 
 273 /*
 274  * This is the in-between PL110 variant found in the ARM Versatile,
 275  * supporting RGB565/BGR565
 276  */
 277 static const struct pl111_variant_data pl110_versatile = {
 278         .name = "PL110 Versatile",
 279         .is_pl110 = true,
 280         .external_bgr = true,
 281         .formats = pl110_versatile_pixel_formats,
 282         .nformats = ARRAY_SIZE(pl110_versatile_pixel_formats),
 283         .fb_bpp = 16,
 284 };
 285 
 286 /*
 287  * RealView PL111 variant, the only real difference from the vanilla
 288  * PL111 is that we select 16bpp framebuffer by default to be able
 289  * to get 1024x768 without saturating the memory bus.
 290  */
 291 static const struct pl111_variant_data pl111_realview = {
 292         .name = "PL111 RealView",
 293         .formats = pl111_realview_pixel_formats,
 294         .nformats = ARRAY_SIZE(pl111_realview_pixel_formats),
 295         .fb_bpp = 16,
 296 };
 297 
 298 /*
 299  * Versatile Express PL111 variant, again we just push the maximum
 300  * BPP to 16 to be able to get 1024x768 without saturating the memory
 301  * bus. The clockdivider also seems broken on the Versatile Express.
 302  */
 303 static const struct pl111_variant_data pl111_vexpress = {
 304         .name = "PL111 Versatile Express",
 305         .formats = pl111_realview_pixel_formats,
 306         .nformats = ARRAY_SIZE(pl111_realview_pixel_formats),
 307         .fb_bpp = 16,
 308         .broken_clockdivider = true,
 309 };
 310 
 311 int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
 312 {
 313         const struct of_device_id *clcd_id;
 314         enum versatile_clcd versatile_clcd_type;
 315         struct device_node *np;
 316         struct regmap *map;
 317         int ret;
 318 
 319         np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
 320                                              &clcd_id);
 321         if (!np) {
 322                 /* Non-ARM reference designs, just bail out */
 323                 return 0;
 324         }
 325         versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
 326 
 327         /* Versatile Express special handling */
 328         if (versatile_clcd_type == VEXPRESS_CLCD_V2M) {
 329                 struct platform_device *pdev;
 330 
 331                 /* Registers a driver for the muxfpga */
 332                 ret = vexpress_muxfpga_init();
 333                 if (ret) {
 334                         dev_err(dev, "unable to initialize muxfpga driver\n");
 335                         of_node_put(np);
 336                         return ret;
 337                 }
 338 
 339                 /* Call into deep Vexpress configuration API */
 340                 pdev = of_find_device_by_node(np);
 341                 if (!pdev) {
 342                         dev_err(dev, "can't find the sysreg device, deferring\n");
 343                         of_node_put(np);
 344                         return -EPROBE_DEFER;
 345                 }
 346                 map = dev_get_drvdata(&pdev->dev);
 347                 if (!map) {
 348                         dev_err(dev, "sysreg has not yet probed\n");
 349                         platform_device_put(pdev);
 350                         of_node_put(np);
 351                         return -EPROBE_DEFER;
 352                 }
 353         } else {
 354                 map = syscon_node_to_regmap(np);
 355         }
 356         of_node_put(np);
 357 
 358         if (IS_ERR(map)) {
 359                 dev_err(dev, "no Versatile syscon regmap\n");
 360                 return PTR_ERR(map);
 361         }
 362 
 363         switch (versatile_clcd_type) {
 364         case INTEGRATOR_CLCD_CM:
 365                 versatile_syscon_map = map;
 366                 priv->variant = &pl110_integrator;
 367                 priv->variant_display_enable = pl111_integrator_enable;
 368                 dev_info(dev, "set up callbacks for Integrator PL110\n");
 369                 break;
 370         case VERSATILE_CLCD:
 371                 versatile_syscon_map = map;
 372                 /* This can do RGB565 with external PLD */
 373                 priv->variant = &pl110_versatile;
 374                 priv->variant_display_enable = pl111_versatile_enable;
 375                 priv->variant_display_disable = pl111_versatile_disable;
 376                 /*
 377                  * The Versatile has a variant halfway between PL110
 378                  * and PL111 where these two registers have already been
 379                  * swapped.
 380                  */
 381                 priv->ienb = CLCD_PL111_IENB;
 382                 priv->ctrl = CLCD_PL111_CNTL;
 383                 dev_info(dev, "set up callbacks for Versatile PL110\n");
 384                 break;
 385         case REALVIEW_CLCD_EB:
 386         case REALVIEW_CLCD_PB1176:
 387         case REALVIEW_CLCD_PB11MP:
 388         case REALVIEW_CLCD_PBA8:
 389         case REALVIEW_CLCD_PBX:
 390                 versatile_syscon_map = map;
 391                 priv->variant = &pl111_realview;
 392                 priv->variant_display_enable = pl111_realview_clcd_enable;
 393                 priv->variant_display_disable = pl111_realview_clcd_disable;
 394                 dev_info(dev, "set up callbacks for RealView PL111\n");
 395                 break;
 396         case VEXPRESS_CLCD_V2M:
 397                 priv->variant = &pl111_vexpress;
 398                 dev_info(dev, "initializing Versatile Express PL111\n");
 399                 ret = pl111_vexpress_clcd_init(dev, priv, map);
 400                 if (ret)
 401                         return ret;
 402                 break;
 403         default:
 404                 dev_info(dev, "unknown Versatile system controller\n");
 405                 break;
 406         }
 407 
 408         return 0;
 409 }
 410 EXPORT_SYMBOL_GPL(pl111_versatile_init);

/* [<][>][^][v][top][bottom][index][help] */