static void set_display_intf(struct mdp5_kms *mdp5_kms, struct mdp5_interface *intf) { unsigned long flags; u32 intf_sel; spin_lock_irqsave(&mdp5_kms->resource_lock, flags); intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL); switch (intf->num) { case 0: intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK; intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf->type); break; case 1: intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK; intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf->type); break; case 2: intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK; intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf->type); break; case 3: intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK; intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf->type); break; default: BUG(); break; } mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel); spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags); }
static inline u32 ctl_read(struct mdp5_ctl *ctl, u32 reg) { struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm); (void)ctl->reg_offset; /* TODO use this instead of mdp5_write */ return mdp5_read(mdp5_kms, reg); }
static void mdp5_irq_mdp(struct mdp_kms *mdp_kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); struct drm_device *dev = mdp5_kms->dev; struct msm_drm_private *priv = dev->dev_private; unsigned int id; uint32_t status, enable; enable = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_EN(0)); status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0)) & enable; mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), status); VERB("status=%08x", status); mdp_dispatch_irqs(mdp_kms, status); for (id = 0; id < priv->num_crtcs; id++) if (status & mdp5_crtc_vblank(priv->crtcs[id])) drm_handle_vblank(dev, id); }
static void read_hw_revision(struct mdp5_kms *mdp5_kms, uint32_t *major, uint32_t *minor) { uint32_t version; mdp5_enable(mdp5_kms); version = mdp5_read(mdp5_kms, REG_MDSS_HW_VERSION); mdp5_disable(mdp5_kms); *major = FIELD(version, MDSS_HW_VERSION_MAJOR); *minor = FIELD(version, MDSS_HW_VERSION_MINOR); DBG("MDP5 version v%d.%d", *major, *minor); }
static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms, u32 *major, u32 *minor) { struct device *dev = &mdp5_kms->pdev->dev; u32 version; pm_runtime_get_sync(dev); version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION); pm_runtime_put_sync(dev); *major = FIELD(version, MDP5_HW_VERSION_MAJOR); *minor = FIELD(version, MDP5_HW_VERSION_MINOR); dev_info(dev, "MDP5 version v%d.%d", *major, *minor); }
irqreturn_t mdp5_irq(struct msm_kms *kms) { struct mdp_kms *mdp_kms = to_mdp_kms(kms); struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); uint32_t intr; intr = mdp5_read(mdp5_kms, REG_MDSS_HW_INTR_STATUS); VERB("intr=%08x", intr); if (intr & MDSS_HW_INTR_STATUS_INTR_MDP) { mdp5_irq_mdp(mdp_kms); intr &= ~MDSS_HW_INTR_STATUS_INTR_MDP; } while (intr) { irq_hw_number_t hwirq = fls(intr) - 1; generic_handle_irq(irq_find_mapping( mdp5_kms->irqcontroller.domain, hwirq)); intr &= ~(1 << hwirq); } return IRQ_HANDLED; }
static int mdp5_hw_init(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct drm_device *dev = mdp5_kms->dev; uint32_t version, major, minor; int ret = 0; pm_runtime_get_sync(dev->dev); mdp5_enable(mdp5_kms); version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION); mdp5_disable(mdp5_kms); major = FIELD(version, MDP5_MDP_VERSION_MAJOR); minor = FIELD(version, MDP5_MDP_VERSION_MINOR); DBG("found MDP5 version v%d.%d", major, minor); if ((major != 1) || ((minor != 0) && (minor != 2))) { dev_err(dev->dev, "unexpected MDP version: v%d.%d\n", major, minor); ret = -ENXIO; goto out; } mdp5_kms->rev = minor; /* Magic unknown register writes: * * W VBIF:0x004 00000001 (mdss_mdp.c:839) * W MDP5:0x2e0 0xe9 (mdss_mdp.c:839) * W MDP5:0x2e4 0x55 (mdss_mdp.c:839) * W MDP5:0x3ac 0xc0000ccc (mdss_mdp.c:839) * W MDP5:0x3b4 0xc0000ccc (mdss_mdp.c:839) * W MDP5:0x3bc 0xcccccc (mdss_mdp.c:839) * W MDP5:0x4a8 0xcccc0c0 (mdss_mdp.c:839) * W MDP5:0x4b0 0xccccc0c0 (mdss_mdp.c:839) * W MDP5:0x4b8 0xccccc000 (mdss_mdp.c:839) * * Downstream fbdev driver gets these register offsets/values * from DT.. not really sure what these registers are or if * different values for different boards/SoC's, etc. I guess * they are the golden registers. * * Not setting these does not seem to cause any problem. But * we may be getting lucky with the bootloader initializing * them for us. OTOH, if we can always count on the bootloader * setting the golden registers, then perhaps we don't need to * care. */ mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0); mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(0), 0); mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(1), 0); mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(2), 0); mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(3), 0); out: pm_runtime_put_sync(dev->dev); return ret; }