aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Herring <robh@kernel.org>2015-05-15 14:41:05 -0500
committerRob Herring <robh@kernel.org>2015-09-15 17:29:50 -0500
commite5083787fa10f4cb26bf87e8b2cfedd05ff69709 (patch)
treef05751022e02fa09b0327b75d833c7ab3c8012f5
parent3085ce76c0b98628604bb6bbb28592637172f4e0 (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.c113
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);