static int rkclk_set_pll(struct rk3288_cru *cru, enum rk_clk_id clk_id, const struct pll_div *div) { int pll_id = rk_pll_id(clk_id); struct rk3288_pll *pll = &cru->pll[pll_id]; /* All PLLs have same VCO and output frequency range restrictions. */ uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000; uint output_hz = vco_hz / div->no; debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz); assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ && (div->no == 1 || !(div->no % 2))); /* enter reset */ rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT); rk_clrsetreg(&pll->con0, CLKR_MASK << CLKR_SHIFT | PLL_OD_MASK, ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1)); rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1); rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1); udelay(10); /* return from reset */ rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT); return 0; }
static int rkclk_set_pll(struct rk3036_cru *cru, enum rk_clk_id clk_id, const struct pll_div *div) { int pll_id = rk_pll_id(clk_id); struct rk3036_pll *pll = &cru->pll[pll_id]; /* All PLLs have same VCO and output frequency range restrictions. */ uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000; uint output_hz = vco_hz / div->postdiv1 / div->postdiv2; debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, postdiv2=%d,\ vco=%u Hz, output=%u Hz\n", pll, div->fbdiv, div->refdiv, div->postdiv1, div->postdiv2, vco_hz, output_hz); assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ); /* use integer mode */ rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); rk_clrsetreg(&pll->con0, PLL_POSTDIV1_MASK | PLL_FBDIV_MASK, (div->postdiv1 << PLL_POSTDIV1_SHIFT) | div->fbdiv); rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, (div->postdiv2 << PLL_POSTDIV2_SHIFT | div->refdiv << PLL_REFDIV_SHIFT)); /* waiting for pll lock */ while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) udelay(1); return 0; }
int board_early_init_f(void) { const uintptr_t GRF_SOC_CON0 = 0xff770244; const uintptr_t GRF_SOC_CON2 = 0xff77024c; struct udevice *dev; int ret; /* * This init is done in SPL, but when chain-loading U-Boot SPL will * have been skipped. Allow the clock driver to check if it needs * setting up. */ ret = rockchip_get_clk(&dev); if (ret) { debug("CLK init failed: %d\n", ret); return ret; } rk_setreg(GRF_SOC_CON2, 1 << 0); /* * Disable JTAG on sdmmc0 IO. The SDMMC won't work until this bit is * cleared */ rk_clrreg(GRF_SOC_CON0, 1 << 12); return 0; }
static void rk3288_set_io_vsel(struct udevice *dev) { struct rk3288_grf *grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); /* lcdc(vop) iodomain select 1.8V */ rk_setreg(&grf->io_vsel, 1 << 0); }
static void setup_iodomain(void) { const u32 GRF_IO_VSEL_GPIO4CD_SHIFT = 3; struct rk3399_grf_regs *grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); /* * Set bit 3 in GRF_IO_VSEL so PCIE_RST# works (pin GPIO4_C6). * Linux assumes that PCIE_RST# works out of the box as it probes * PCIe before loading the iodomain driver. */ rk_setreg(&grf->io_vsel, 1 << GRF_IO_VSEL_GPIO4CD_SHIFT); }
static int rockchip_reset_assert(struct reset_ctl *reset_ctl) { struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev); int bank = reset_ctl->id / ROCKCHIP_RESET_NUM_IN_REG; int offset = reset_ctl->id % ROCKCHIP_RESET_NUM_IN_REG; debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_addr=%p)\n", __func__, reset_ctl, reset_ctl->dev, reset_ctl->id, priv->base + (bank * 4)); rk_setreg(priv->base + (bank * 4), BIT(offset)); return 0; }
static int rk3288_hdmi_enable(struct udevice *dev, int panel_bpp, const struct display_timing *edid) { struct rk_hdmi_priv *priv = dev_get_priv(dev); struct display_plat *uc_plat = dev_get_uclass_platdata(dev); int vop_id = uc_plat->source_id; struct rk3288_grf *grf = priv->grf; /* hdmi source select hdmi controller */ rk_setreg(&grf->soc_con6, 1 << 15); /* hdmi data from vop id */ rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0); return 0; }
int rk_lvds_enable(struct udevice *dev, int panel_bpp, const struct display_timing *edid) { struct rk_lvds_priv *priv = dev_get_priv(dev); struct display_plat *uc_plat = dev_get_uclass_platdata(dev); int ret = 0; unsigned int val = 0; ret = panel_enable_backlight(priv->panel); if (ret) { debug("%s: backlight error: %d\n", __func__, ret); return ret; } /* Select the video source */ if (uc_plat->source_id) val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT | (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16); else val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16; rk_setreg(&priv->grf->soc_con6, val); /* Select data transfer format */ val = priv->format; if (priv->output == LVDS_OUTPUT_DUAL) val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN; else if (priv->output == LVDS_OUTPUT_SINGLE) val |= LVDS_CH0_EN; else if (priv->output == LVDS_OUTPUT_RGB) val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN; val |= (0xffff << 16); rk_setreg(&priv->grf->soc_con7, val); /* Enable LVDS PHY */ if (priv->output == LVDS_OUTPUT_RGB) { lvds_writel(priv, RK3288_LVDS_CH0_REG0, RK3288_LVDS_CH0_REG0_TTL_EN | RK3288_LVDS_CH0_REG0_LANECK_EN | RK3288_LVDS_CH0_REG0_LANE4_EN | RK3288_LVDS_CH0_REG0_LANE3_EN | RK3288_LVDS_CH0_REG0_LANE2_EN | RK3288_LVDS_CH0_REG0_LANE1_EN | RK3288_LVDS_CH0_REG0_LANE0_EN); lvds_writel(priv, RK3288_LVDS_CH0_REG2, RK3288_LVDS_PLL_FBDIV_REG2(0x46)); lvds_writel(priv, RK3288_LVDS_CH0_REG3, RK3288_LVDS_PLL_FBDIV_REG3(0x46)); lvds_writel(priv, RK3288_LVDS_CH0_REG4, RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE | RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE | RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE | RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE | RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE | RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE); lvds_writel(priv, RK3288_LVDS_CH0_REG5, RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA | RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA | RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA | RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA | RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA | RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA); lvds_writel(priv, RK3288_LVDS_CH0_REGD, RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); lvds_writel(priv, RK3288_LVDS_CH0_REG20, RK3288_LVDS_CH0_REG20_LSB); } else { lvds_writel(priv, RK3288_LVDS_CH0_REG0, RK3288_LVDS_CH0_REG0_LVDS_EN | RK3288_LVDS_CH0_REG0_LANECK_EN | RK3288_LVDS_CH0_REG0_LANE4_EN | RK3288_LVDS_CH0_REG0_LANE3_EN | RK3288_LVDS_CH0_REG0_LANE2_EN | RK3288_LVDS_CH0_REG0_LANE1_EN | RK3288_LVDS_CH0_REG0_LANE0_EN); lvds_writel(priv, RK3288_LVDS_CH0_REG1, RK3288_LVDS_CH0_REG1_LANECK_BIAS | RK3288_LVDS_CH0_REG1_LANE4_BIAS | RK3288_LVDS_CH0_REG1_LANE3_BIAS | RK3288_LVDS_CH0_REG1_LANE2_BIAS | RK3288_LVDS_CH0_REG1_LANE1_BIAS | RK3288_LVDS_CH0_REG1_LANE0_BIAS); lvds_writel(priv, RK3288_LVDS_CH0_REG2, RK3288_LVDS_CH0_REG2_RESERVE_ON | RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE | RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE | RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE | RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE | RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE | RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE | RK3288_LVDS_PLL_FBDIV_REG2(0x46)); lvds_writel(priv, RK3288_LVDS_CH0_REG3, RK3288_LVDS_PLL_FBDIV_REG3(0x46)); lvds_writel(priv, RK3288_LVDS_CH0_REG4, 0x00); lvds_writel(priv, RK3288_LVDS_CH0_REG5, 0x00); lvds_writel(priv, RK3288_LVDS_CH0_REGD, RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); lvds_writel(priv, RK3288_LVDS_CH0_REG20, RK3288_LVDS_CH0_REG20_LSB); } /* Power on */ writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE, priv->regs + RK3288_LVDS_CFG_REGC); writel(RK3288_LVDS_CFG_REG21_TX_ENABLE, priv->regs + RK3288_LVDS_CFG_REG21); return 0; }
static int rk_vop_probe(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); const void *blob = gd->fdt_blob; struct rk_vop_priv *priv = dev_get_priv(dev); struct udevice *reg; int ret, port, node; /* Before relocation we don't need to do anything */ if (!(gd->flags & GD_FLG_RELOC)) return 0; priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); priv->regs = (struct rk3288_vop *)dev_get_addr(dev); /* lcdc(vop) iodomain select 1.8V */ rk_setreg(&priv->grf->io_vsel, 1 << 0); /* * Try some common regulators. We should really get these from the * device tree somehow. */ ret = regulator_autoset_by_name("vcc18_lcd", ®); if (ret) debug("%s: Cannot autoset regulator vcc18_lcd\n", __func__); ret = regulator_autoset_by_name("VCC18_LCD", ®); if (ret) debug("%s: Cannot autoset regulator VCC18_LCD\n", __func__); ret = regulator_autoset_by_name("vdd10_lcd_pwren_h", ®); if (ret) { debug("%s: Cannot autoset regulator vdd10_lcd_pwren_h\n", __func__); } ret = regulator_autoset_by_name("vdd10_lcd", ®); if (ret) { debug("%s: Cannot autoset regulator vdd10_lcd\n", __func__); } ret = regulator_autoset_by_name("VDD10_LCD", ®); if (ret) { debug("%s: Cannot autoset regulator VDD10_LCD\n", __func__); } ret = regulator_autoset_by_name("vcc33_lcd", ®); if (ret) debug("%s: Cannot autoset regulator vcc33_lcd\n", __func__); /* * Try all the ports until we find one that works. In practice this * tries EDP first if available, then HDMI. */ port = fdt_subnode_offset(blob, dev->of_offset, "port"); if (port < 0) return -EINVAL; for (node = fdt_first_subnode(blob, port); node > 0; node = fdt_next_subnode(blob, node)) { ret = rk_display_init(dev, plat->base, VIDEO_BPP16, node); if (ret) debug("Device failed: ret=%d\n", ret); if (!ret) break; } return ret; }