uboot/drivers/video/mali_dp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2016-2018 ARM Ltd.
   4 * Author: Liviu Dudau <liviu.dudau@foss.arm.com>
   5 *
   6 */
   7#define DEBUG
   8#include <common.h>
   9#include <malloc.h>
  10#include <video.h>
  11#include <dm.h>
  12#ifdef CONFIG_DISPLAY
  13#include <display.h>
  14#endif
  15#include <fdtdec.h>
  16#include <asm/io.h>
  17#include <os.h>
  18#include <fdt_support.h>
  19#include <clk.h>
  20#include <dm/device_compat.h>
  21#include <linux/delay.h>
  22#include <linux/sizes.h>
  23
  24#define MALIDP_CORE_ID          0x0018
  25#define MALIDP_REG_BG_COLOR     0x0044
  26#define MALIDP_LAYER_LV1        0x0100
  27#define MALIDP_DC_STATUS        0xc000
  28#define MALIDP_DC_CONTROL       0xc010
  29#define MALIDP_DC_CFG_VALID     0xc014
  30
  31/* offsets inside the modesetting register block */
  32#define MALIDP_H_INTERVALS      0x0000
  33#define MALIDP_V_INTERVALS      0x0004
  34#define MALIDP_SYNC_CONTROL     0x0008
  35#define MALIDP_HV_ACTIVESIZE    0x000c
  36#define MALIDP_OUTPUT_DEPTH     0x001c
  37
  38/* offsets inside the layer register block */
  39#define MALIDP_LAYER_FORMAT     0x0000
  40#define MALIDP_LAYER_CONTROL    0x0004
  41#define MALIDP_LAYER_IN_SIZE    0x000c
  42#define MALIDP_LAYER_CMP_SIZE   0x0010
  43#define MALIDP_LAYER_STRIDE     0x0018
  44#define MALIDP_LAYER_PTR_LOW    0x0024
  45#define MALIDP_LAYER_PTR_HIGH   0x0028
  46
  47/* offsets inside the IRQ control blocks */
  48#define MALIDP_REG_MASKIRQ      0x0008
  49#define MALIDP_REG_CLEARIRQ     0x000c
  50
  51#define M1BITS  0x0001
  52#define M2BITS  0x0003
  53#define M4BITS  0x000f
  54#define M8BITS  0x00ff
  55#define M10BITS 0x03ff
  56#define M12BITS 0x0fff
  57#define M13BITS 0x1fff
  58#define M16BITS 0xffff
  59#define M17BITS 0x1ffff
  60
  61#define MALIDP_H_FRONTPORCH(x)  (((x) & M12BITS) << 0)
  62#define MALIDP_H_BACKPORCH(x)   (((x) & M10BITS) << 16)
  63#define MALIDP_V_FRONTPORCH(x)  (((x) & M12BITS) << 0)
  64#define MALIDP_V_BACKPORCH(x)   (((x) & M8BITS) << 16)
  65#define MALIDP_H_SYNCWIDTH(x)   (((x) & M10BITS) << 0)
  66#define MALIDP_V_SYNCWIDTH(x)   (((x) & M8BITS) << 16)
  67#define MALIDP_H_ACTIVE(x)      (((x) & M13BITS) << 0)
  68#define MALIDP_V_ACTIVE(x)      (((x) & M13BITS) << 16)
  69
  70#define MALIDP_CMP_V_SIZE(x)    (((x) & M13BITS) << 16)
  71#define MALIDP_CMP_H_SIZE(x)    (((x) & M13BITS) << 0)
  72
  73#define MALIDP_IN_V_SIZE(x)     (((x) & M13BITS) << 16)
  74#define MALIDP_IN_H_SIZE(x)     (((x) & M13BITS) << 0)
  75
  76#define MALIDP_DC_CM_CONTROL(x) ((x) & M1BITS) << 16, 1 << 16
  77#define MALIDP_DC_STATUS_GET_CM(reg) (((reg) >> 16) & M1BITS)
  78
  79#define MALIDP_FORMAT_ARGB8888  0x08
  80#define MALIDP_DEFAULT_BG_R 0x0
  81#define MALIDP_DEFAULT_BG_G 0x0
  82#define MALIDP_DEFAULT_BG_B 0x0
  83
  84#define MALIDP_PRODUCT_ID(core_id)      ((u32)(core_id) >> 16)
  85
  86#define MALIDP500       0x500
  87
  88DECLARE_GLOBAL_DATA_PTR;
  89
  90struct malidp_priv {
  91        phys_addr_t base_addr;
  92        phys_addr_t dc_status_addr;
  93        phys_addr_t dc_control_addr;
  94        phys_addr_t cval_addr;
  95        struct udevice *display;        /* display device attached */
  96        struct clk aclk;
  97        struct clk pxlclk;
  98        u16 modeset_regs_offset;
  99        u8 config_bit_shift;
 100        u8 clear_irq;                   /* offset for IRQ clear register */
 101};
 102
 103static const struct video_ops malidp_ops = {
 104};
 105
 106static int malidp_get_hwid(phys_addr_t base_addr)
 107{
 108        int hwid;
 109
 110        /*
 111         * reading from the old CORE_ID offset will always
 112         * return 0x5000000 on DP500
 113         */
 114        hwid = readl(base_addr + MALIDP_CORE_ID);
 115        if (MALIDP_PRODUCT_ID(hwid) == MALIDP500)
 116                return hwid;
 117        /* otherwise try the other gen CORE_ID offset */
 118        hwid = readl(base_addr + MALIDP_DC_STATUS + MALIDP_CORE_ID);
 119
 120        return hwid;
 121}
 122
 123/*
 124 * wait for config mode bit setup to be acted upon by the hardware
 125 */
 126static int malidp_wait_configdone(struct malidp_priv *malidp)
 127{
 128        u32 status, tries = 300;
 129
 130        while (tries--) {
 131                status = readl(malidp->dc_status_addr);
 132                if ((status >> malidp->config_bit_shift) & 1)
 133                        break;
 134                udelay(500);
 135        }
 136
 137        if (!tries)
 138                return -ETIMEDOUT;
 139
 140        return 0;
 141}
 142
 143/*
 144 * signal the hardware to enter configuration mode
 145 */
 146static int malidp_enter_config(struct malidp_priv *malidp)
 147{
 148        setbits_le32(malidp->dc_control_addr, 1 << malidp->config_bit_shift);
 149        return malidp_wait_configdone(malidp);
 150}
 151
 152/*
 153 * signal the hardware to exit configuration mode
 154 */
 155static int malidp_leave_config(struct malidp_priv *malidp)
 156{
 157        clrbits_le32(malidp->dc_control_addr, 1 << malidp->config_bit_shift);
 158        return malidp_wait_configdone(malidp);
 159}
 160
 161static void malidp_setup_timings(struct malidp_priv *malidp,
 162                                 struct display_timing *timings)
 163{
 164        u32 val = MALIDP_H_SYNCWIDTH(timings->hsync_len.typ) |
 165                  MALIDP_V_SYNCWIDTH(timings->vsync_len.typ);
 166        writel(val, malidp->base_addr + malidp->modeset_regs_offset +
 167               MALIDP_SYNC_CONTROL);
 168        val = MALIDP_H_BACKPORCH(timings->hback_porch.typ) |
 169                MALIDP_H_FRONTPORCH(timings->hfront_porch.typ);
 170        writel(val, malidp->base_addr + malidp->modeset_regs_offset +
 171               MALIDP_H_INTERVALS);
 172        val = MALIDP_V_BACKPORCH(timings->vback_porch.typ) |
 173                MALIDP_V_FRONTPORCH(timings->vfront_porch.typ);
 174        writel(val, malidp->base_addr + malidp->modeset_regs_offset +
 175               MALIDP_V_INTERVALS);
 176        val = MALIDP_H_ACTIVE(timings->hactive.typ) |
 177                MALIDP_V_ACTIVE(timings->vactive.typ);
 178        writel(val, malidp->base_addr + malidp->modeset_regs_offset +
 179               MALIDP_HV_ACTIVESIZE);
 180        /* default output bit-depth per colour is 8 bits */
 181        writel(0x080808, malidp->base_addr + malidp->modeset_regs_offset +
 182               MALIDP_OUTPUT_DEPTH);
 183}
 184
 185static int malidp_setup_mode(struct malidp_priv *malidp,
 186                             struct display_timing *timings)
 187{
 188        int err;
 189
 190        if (clk_set_rate(&malidp->pxlclk, timings->pixelclock.typ) == 0)
 191                return -EIO;
 192
 193        malidp_setup_timings(malidp, timings);
 194
 195        err = display_enable(malidp->display, 8, timings);
 196        if (err)
 197                printf("display_enable failed with %d\n", err);
 198
 199        return err;
 200}
 201
 202static void malidp_setup_layer(struct malidp_priv *malidp,
 203                               struct display_timing *timings,
 204                               u32 layer_offset, phys_addr_t fb_addr)
 205{
 206        u32 val;
 207
 208        /* setup the base layer's pixel format to A8R8G8B8 */
 209        writel(MALIDP_FORMAT_ARGB8888, malidp->base_addr + layer_offset +
 210               MALIDP_LAYER_FORMAT);
 211        /* setup layer composition size */
 212        val = MALIDP_CMP_V_SIZE(timings->vactive.typ) |
 213                MALIDP_CMP_H_SIZE(timings->hactive.typ);
 214        writel(val, malidp->base_addr + layer_offset +
 215               MALIDP_LAYER_CMP_SIZE);
 216        /* setup layer input size */
 217        val = MALIDP_IN_V_SIZE(timings->vactive.typ) |
 218                MALIDP_IN_H_SIZE(timings->hactive.typ);
 219        writel(val, malidp->base_addr + layer_offset + MALIDP_LAYER_IN_SIZE);
 220        /* setup layer stride in bytes */
 221        writel(timings->hactive.typ << 2, malidp->base_addr + layer_offset +
 222               MALIDP_LAYER_STRIDE);
 223        /* set framebuffer address */
 224        writel(lower_32_bits(fb_addr), malidp->base_addr + layer_offset +
 225               MALIDP_LAYER_PTR_LOW);
 226        writel(upper_32_bits(fb_addr), malidp->base_addr + layer_offset +
 227               MALIDP_LAYER_PTR_HIGH);
 228        /* enable layer */
 229        setbits_le32(malidp->base_addr + layer_offset +
 230                     MALIDP_LAYER_CONTROL, 1);
 231}
 232
 233static void malidp_set_configvalid(struct malidp_priv *malidp)
 234{
 235        setbits_le32(malidp->cval_addr, 1);
 236}
 237
 238static int malidp_update_timings_from_edid(struct udevice *dev,
 239                                           struct display_timing *timings)
 240{
 241#ifdef CONFIG_DISPLAY
 242        struct malidp_priv *priv = dev_get_priv(dev);
 243        struct udevice *disp_dev;
 244        int err;
 245
 246        err = uclass_first_device(UCLASS_DISPLAY, &disp_dev);
 247        if (err)
 248                return err;
 249
 250        priv->display = disp_dev;
 251
 252        err = display_read_timing(disp_dev, timings);
 253        if (err)
 254                return err;
 255
 256#endif
 257        return 0;
 258}
 259
 260static int malidp_probe(struct udevice *dev)
 261{
 262        struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 263        struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
 264        ofnode framebuffer = ofnode_find_subnode(dev_ofnode(dev), "framebuffer");
 265        struct malidp_priv *priv = dev_get_priv(dev);
 266        struct display_timing timings;
 267        phys_addr_t fb_base, fb_size;
 268        const char *format;
 269        u32 value;
 270        int err;
 271
 272        if (!ofnode_valid(framebuffer))
 273                return -EINVAL;
 274
 275        err = clk_get_by_name(dev, "pxlclk", &priv->pxlclk);
 276        if (err) {
 277                dev_err(dev, "failed to get pixel clock\n");
 278                return err;
 279        }
 280        err = clk_get_by_name(dev, "aclk", &priv->aclk);
 281        if (err) {
 282                dev_err(dev, "failed to get AXI clock\n");
 283                goto fail_aclk;
 284        }
 285
 286        err = ofnode_decode_display_timing(dev_ofnode(dev), 1, &timings);
 287        if (err) {
 288                dev_err(dev, "failed to get any display timings\n");
 289                goto fail_timings;
 290        }
 291
 292        err = malidp_update_timings_from_edid(dev, &timings);
 293        if (err) {
 294                printf("malidp_update_timings_from_edid failed: %d\n", err);
 295                goto fail_timings;
 296        }
 297
 298        fb_base = ofnode_get_addr_size(framebuffer, "reg", &fb_size);
 299        if (fb_base != FDT_ADDR_T_NONE) {
 300                uc_plat->base = fb_base;
 301                uc_plat->size = fb_size;
 302        } else {
 303                printf("cannot get address size for framebuffer\n");
 304        }
 305
 306        err = ofnode_read_u32(framebuffer, "width", &value);
 307        if (err)
 308                goto fail_timings;
 309        uc_priv->xsize = (ushort)value;
 310
 311        err = ofnode_read_u32(framebuffer, "height", &value);
 312        if (err)
 313                goto fail_timings;
 314        uc_priv->ysize = (ushort)value;
 315
 316        format = ofnode_read_string(framebuffer, "format");
 317        if (!format) {
 318                err = -EINVAL;
 319                goto fail_timings;
 320        } else if (!strncmp(format, "a8r8g8b8", 8)) {
 321                uc_priv->bpix = VIDEO_BPP32;
 322        }
 323
 324        uc_priv->rot = 0;
 325        priv->base_addr = (phys_addr_t)dev_read_addr(dev);
 326
 327        clk_enable(&priv->pxlclk);
 328        clk_enable(&priv->aclk);
 329
 330        value = malidp_get_hwid(priv->base_addr);
 331        printf("Display: Arm Mali DP%3x r%dp%d\n", MALIDP_PRODUCT_ID(value),
 332               (value >> 12) & 0xf, (value >> 8) & 0xf);
 333
 334        if (MALIDP_PRODUCT_ID(value) == MALIDP500) {
 335                /* DP500 is special */
 336                priv->modeset_regs_offset = 0x28;
 337                priv->dc_status_addr = priv->base_addr;
 338                priv->dc_control_addr = priv->base_addr + 0xc;
 339                priv->cval_addr = priv->base_addr + 0xf00;
 340                priv->config_bit_shift = 17;
 341                priv->clear_irq = 0;
 342        } else {
 343                priv->modeset_regs_offset = 0x30;
 344                priv->dc_status_addr = priv->base_addr + MALIDP_DC_STATUS;
 345                priv->dc_control_addr = priv->base_addr + MALIDP_DC_CONTROL;
 346                priv->cval_addr = priv->base_addr + MALIDP_DC_CFG_VALID;
 347                priv->config_bit_shift = 16;
 348                priv->clear_irq = MALIDP_REG_CLEARIRQ;
 349        }
 350
 351        /* enter config mode */
 352        err  = malidp_enter_config(priv);
 353        if (err)
 354                return err;
 355
 356        /* disable interrupts */
 357        writel(0, priv->dc_status_addr + MALIDP_REG_MASKIRQ);
 358        writel(0xffffffff, priv->dc_status_addr + priv->clear_irq);
 359
 360        err = malidp_setup_mode(priv, &timings);
 361        if (err)
 362                goto fail_timings;
 363
 364        malidp_setup_layer(priv, &timings, MALIDP_LAYER_LV1,
 365                           (phys_addr_t)uc_plat->base);
 366
 367        err = malidp_leave_config(priv);
 368        if (err)
 369                goto fail_timings;
 370
 371        malidp_set_configvalid(priv);
 372
 373        return 0;
 374
 375fail_timings:
 376        clk_free(&priv->aclk);
 377fail_aclk:
 378        clk_free(&priv->pxlclk);
 379
 380        return err;
 381}
 382
 383static int malidp_bind(struct udevice *dev)
 384{
 385        struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
 386
 387        /* choose max possible size: 2K x 2K, XRGB888 framebuffer */
 388        uc_plat->size = 4 * 2048 * 2048;
 389
 390        return 0;
 391}
 392
 393static const struct udevice_id malidp_ids[] = {
 394        { .compatible = "arm,mali-dp500" },
 395        { .compatible = "arm,mali-dp550" },
 396        { .compatible = "arm,mali-dp650" },
 397        { }
 398};
 399
 400U_BOOT_DRIVER(mali_dp) = {
 401        .name           = "mali_dp",
 402        .id             = UCLASS_VIDEO,
 403        .of_match       = malidp_ids,
 404        .bind           = malidp_bind,
 405        .probe          = malidp_probe,
 406        .priv_auto_alloc_size   = sizeof(struct malidp_priv),
 407        .ops            = &malidp_ops,
 408};
 409