diff options
author | Rob Herring <robh@kernel.org> | 2015-05-15 14:41:05 -0500 |
---|---|---|
committer | Rob Herring <robh@kernel.org> | 2015-09-15 17:29:50 -0500 |
commit | e5083787fa10f4cb26bf87e8b2cfedd05ff69709 (patch) | |
tree | f05751022e02fa09b0327b75d833c7ab3c8012f5 | |
parent | 3085ce76c0b98628604bb6bbb28592637172f4e0 (diff) |
clk: pxa1928: add display clocks
The display domain power on and reset needs some work.
Signed-off-by: Rob Herring <robh@kernel.org>
-rw-r--r-- | drivers/clk/mmp/clk-of-pxa1928.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/drivers/clk/mmp/clk-of-pxa1928.c b/drivers/clk/mmp/clk-of-pxa1928.c index 433a5ae1eae0..414a71d7d603 100644 --- a/drivers/clk/mmp/clk-of-pxa1928.c +++ b/drivers/clk/mmp/clk-of-pxa1928.c @@ -13,6 +13,7 @@ * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> +#include <linux/delay.h> #include <linux/io.h> #include <linux/of_address.h> #include <linux/slab.h> @@ -37,6 +38,8 @@ static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { {0, "clk32", NULL, CLK_IS_ROOT, 32768}, {0, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, {0, "pll1_624", NULL, CLK_IS_ROOT, 624000000}, + {PXA1928_CLK_PLL3, "pll3", NULL, CLK_IS_ROOT, 0}, + {PXA1928_CLK_PLL6, "pll6", NULL, CLK_IS_ROOT, 0}, {0, "pll5p", NULL, CLK_IS_ROOT, 832000000}, {0, "pll5", NULL, CLK_IS_ROOT, 1248000000}, {0, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, @@ -144,19 +147,38 @@ static DEFINE_SPINLOCK(sdh1_lock); static DEFINE_SPINLOCK(sdh2_lock); static DEFINE_SPINLOCK(sdh3_lock); static DEFINE_SPINLOCK(sdh4_lock); +static DEFINE_SPINLOCK(disp_lock); static const char *sdh_parent_names[] = {"pll1_624", "pll5p", "pll5", "pll1_416"}; +static const char *disp_axi_parent_names[] = {"pll1_d2", "pll1_416", "pll1_624", "", "", "", "pll5"}; +static const char *disp_parent_names[] = {"pll1_624", "pll1_416", "pll5", "", "", "", "pll5p"}; +static const char *dsi_esc_parent_names[] = {"pll1_d12", "pll1_d16", "pll1_d20", "vctcxo"}; static DEFINE_SPINLOCK(usb_lock); static struct mmp_param_mux_clk apmu_mux_clks[] = { {0, "sdh_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_SDH0 * 4, 8, 2, 0, &sdh0_lock}, + {0, "vdma_mux", disp_axi_parent_names, ARRAY_SIZE(disp_axi_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_DISP0 * 4, 28, 3, 0, &disp_lock}, + {0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_DISP0 * 4, 12, 3, 0, &disp_lock}, + {0, "disp1_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_DISP0 * 4, 20, 3, 0, &disp_lock}, + {0, "disp_axi_mux", disp_axi_parent_names, ARRAY_SIZE(disp_axi_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_DISP1 * 4, 4, 3, 0, &disp_lock}, + {PXA1928_CLK_DSI_ESC, "dsi_esc_mux", dsi_esc_parent_names, ARRAY_SIZE(dsi_esc_parent_names), CLK_SET_RATE_PARENT, PXA1928_CLK_DISP0 * 4, 5, 2, 0, &disp_lock}, }; static struct mmp_param_div_clk apmu_div_clks[] = { {0, "sdh_div", "sdh_mux", 0, PXA1928_CLK_SDH0 * 4, 10, 4, CLK_DIVIDER_ONE_BASED, &sdh0_lock}, + {0, "vdma_div", "vdma_mux", 0, PXA1928_CLK_DISP0 * 4, 24, 3, CLK_DIVIDER_ONE_BASED, &disp_lock}, + {0, "disp0_div", "disp0_mux", 0, PXA1928_CLK_DISP0 * 4, 8, 3, CLK_DIVIDER_ONE_BASED, &disp_lock}, + {0, "disp1_div", "disp1_mux", 0, PXA1928_CLK_DISP0 * 4, 16, 3, CLK_DIVIDER_ONE_BASED, &disp_lock}, + {0, "disp_axi_div", "disp_axi_mux", 0, PXA1928_CLK_DISP1 * 4, 0, 3, CLK_DIVIDER_ONE_BASED, &disp_lock}, }; static struct mmp_param_gate_clk apmu_gate_clks[] = { + {PXA1928_CLK_VDMA, "vdma", "vdma_div", CLK_SET_RATE_PARENT, PXA1928_CLK_DISP0 * 4, BIT(27), BIT(27), 0, 0, &disp_lock}, + {PXA1928_CLK_DISP0, "disp0", "disp0_div", CLK_SET_RATE_PARENT, PXA1928_CLK_DISP0 * 4, BIT(15), BIT(15), 0, 0, &disp_lock}, + {PXA1928_CLK_DISP1, "disp1", "disp1_div", CLK_SET_RATE_PARENT, PXA1928_CLK_DISP0 * 4, BIT(23), BIT(23), 0, 0, &disp_lock}, + {PXA1928_CLK_DISP_AXI, "disp_axi", "disp_axi_div", CLK_SET_RATE_PARENT, PXA1928_CLK_DISP1 * 4, BIT(7), BIT(7), 0, 0, &disp_lock}, + {PXA1928_CLK_DSI_ESC, "dsi_esc", "dsi_esc_mux", CLK_SET_RATE_PARENT, PXA1928_CLK_DISP1 * 4, BIT(4), BIT(4), 0, 0, &disp_lock}, + {PXA1928_CLK_USB, "usb_clk", "usb_pll", 0, PXA1928_CLK_USB * 4, 0x9, 0x9, 0x0, 0, &usb_lock}, {PXA1928_CLK_HSIC, "hsic_clk", "usb_pll", 0, PXA1928_CLK_HSIC * 4, 0x9, 0x9, 0x0, 0, &usb_lock}, /* The gate clocks has mux parent. */ @@ -205,6 +227,92 @@ static void pxa1928_clk_reset_init(struct device_node *np, mmp_clk_reset_register(np, cells, nr_resets); } +#define HWMODE_EN (1 << 0) +#define INT_MASK (1 << 7) +#define PWRUP (1 << 1) +#define INT_STATUS (1 << 8) +#define INT_CLR (1 << 6) +static void pxa1928_clk_media_power_up(void __iomem *pwr_ctrl) +{ + u32 val; + int count = 0; + + val = readl_relaxed(pwr_ctrl) | HWMODE_EN; + writel_relaxed(val, pwr_ctrl); + val &= ~INT_MASK; + writel_relaxed(val, pwr_ctrl); + val |= PWRUP; + writel_relaxed(val, pwr_ctrl); + + while (!(readl_relaxed(pwr_ctrl) & INT_STATUS)) { + count++; + if (count > 1000) { + pr_err("Timeout for polling active interrupt\n"); + return; + } + } + + val = readl_relaxed(pwr_ctrl) | INT_MASK | INT_CLR; + writel_relaxed(val, pwr_ctrl); +} + +#define DMMY_CLK (1 << 4) + +#define DISP_RST_CTRL (0x180) +#define DISP_PWR_CTRL (0x204) +#define ISLD_LCD_CTRL (0x1ac) +#define CIU_FABRIC1_CKGT (0x464) +static int pxa1928_clk_disp_rst_enable(void __iomem *base) +{ + u32 val; + + /* 1. clock enable, in prepare process */ + writel_relaxed(0x04, base + PXA1928_CLK_DISP1*4); + writel_relaxed(0x09010110, base + PXA1928_CLK_DISP0*4); + + /* 2. disable fabric x2h dynamical clock gating */ + val = readl_relaxed(base + CIU_FABRIC1_CKGT) | 1; + writel_relaxed(val, base + CIU_FABRIC1_CKGT); + + /* 3. power up */ + pxa1928_clk_media_power_up(base + DISP_PWR_CTRL); + + /* 4. dummy clock for SRAM access */ + val = readl_relaxed(base + ISLD_LCD_CTRL) | DMMY_CLK; + writel_relaxed(val, base + ISLD_LCD_CTRL); + /* wait for 500ns */ + udelay(2); + + val = readl_relaxed(base + ISLD_LCD_CTRL); + val &= ~DMMY_CLK; + writel_relaxed(val, base + ISLD_LCD_CTRL); + + /* 5. release from reset */ + val = readl_relaxed(base + DISP_RST_CTRL); + val |= (1 << 1) | (1 << 2); + writel_relaxed(val, base + DISP_RST_CTRL); + /* wait for 500ns */ + udelay(2); + + val = readl_relaxed(base + DISP_RST_CTRL); + val |= (1 << 3) | (1 << 4) | (1 << 5); + writel_relaxed(val, base + DISP_RST_CTRL); + /* wait for 500ns */ + udelay(2); + + val = readl_relaxed(base + DISP_RST_CTRL); + val |= 1; + writel_relaxed(val, base + DISP_RST_CTRL); + /* wait for 500ns */ + udelay(2); + + /* 6. enable fabric x2h dynamical clock gating */ + val = readl_relaxed(base + CIU_FABRIC1_CKGT) & (~1); + writel_relaxed(val, base + CIU_FABRIC1_CKGT); + + return 0; +} + static void __init pxa1928_mpmu_clk_init(struct device_node *np) { struct pxa1928_clk_unit *pxa_unit; @@ -219,12 +327,15 @@ static void __init pxa1928_mpmu_clk_init(struct device_node *np) return; } + mmp_clk_init(np, &pxa_unit->unit, PXA1928_MPMU_NR_CLKS); + pxa1928_pll_init(pxa_unit); } CLK_OF_DECLARE(pxa1928_mpmu_clk, "marvell,pxa1928-mpmu", pxa1928_mpmu_clk_init); static void __init pxa1928_apmu_clk_init(struct device_node *np) { + struct clk *clk; struct pxa1928_clk_unit *pxa_unit; pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL); @@ -237,6 +348,8 @@ static void __init pxa1928_apmu_clk_init(struct device_node *np) return; } + pxa1928_clk_disp_rst_enable(pxa_unit->apmu_base); + mmp_clk_init(np, &pxa_unit->unit, PXA1928_APMU_NR_CLKS); pxa1928_axi_periph_clk_init(pxa_unit); |