9
0
Fork 0

ARM: i.MX6: Add video clocks

This adds the IPU, LVDS and HDMI clocks. As these are many, depend
on the IPU driver being compiled in.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2014-03-13 10:34:00 +01:00
parent 6d610de61c
commit ce6755ca1c
3 changed files with 158 additions and 4 deletions

View File

@ -19,6 +19,8 @@
#include <linux/clkdev.h>
#include <linux/err.h>
#include <mach/imx6-regs.h>
#include <mach/revision.h>
#include <mach/imx6.h>
#include "clk.h"
@ -84,8 +86,10 @@ enum mx6q_clks {
usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg,
pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg,
ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5,
sata_ref, pcie_ref, sata_ref_100m, pcie_ref_125m, enet_ref,
clk_max
sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate,
usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow,
spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div,
lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max
};
static struct clk *clks[clk_max];
@ -171,6 +175,62 @@ static const char *cko1_sels[] = {
"pll4_audio",
};
static const char *ipu_sels[] = {
"mmdc_ch0_axi_podf",
"pll2_pfd2_396m",
"pll3_120m",
"pll3_pfd1_540m",
};
static const char *ldb_di_sels[] = {
"pll5_video_div",
"pll2_pfd0_352m",
"pll2_pfd2_396m",
"mmdc_ch1_axi_podf",
"pll3_usb_otg",
};
static const char *ipu_di_pre_sels[] = {
"mmdc_ch0_axi",
"pll3_usb_otg",
"pll5_video_div",
"pll2_pfd0_352m",
"pll2_pfd2_396m",
"pll3_pfd1_540m",
};
static const char *ipu1_di0_sels[] = {
"ipu1_di0_pre",
"dummy",
"dummy",
"ldb_di0_podf",
"ldb_di1_podf",
};
static const char *ipu1_di1_sels[] = {
"ipu1_di1_pre",
"dummy",
"dummy",
"ldb_di0_podf",
"ldb_di1_podf",
};
static const char *ipu2_di0_sels[] = {
"ipu2_di0_pre",
"dummy",
"dummy",
"ldb_di0_podf",
"ldb_di1_podf",
};
static const char *ipu2_di1_sels[] = {
"ipu2_di1_pre",
"dummy",
"dummy",
"ldb_di0_podf",
"ldb_di1_podf",
};
static struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
{ .val = 1, .div = 10, },
@ -179,6 +239,86 @@ static struct clk_div_table clk_enet_ref_table[] = {
{ },
};
static struct clk_div_table post_div_table[] = {
{ .val = 2, .div = 1, },
{ .val = 1, .div = 2, },
{ .val = 0, .div = 4, },
{ /* sentinel */ }
};
static struct clk_div_table video_div_table[] = {
{ .val = 0, .div = 1, },
{ .val = 1, .div = 2, },
{ .val = 2, .div = 1, },
{ .val = 3, .div = 4, },
{ /* sentinel */ }
};
static void imx6_add_video_clks(void __iomem *anab, void __iomem *cb)
{
clks[pll5_post_div] = imx_clk_divider_table("pll5_post_div", "pll5_video", anab + 0xa0, 19, 2, post_div_table);
clks[pll5_video_div] = imx_clk_divider_table("pll5_video_div", "pll5_post_div", anab + 0x170, 30, 2, video_div_table);
clks[ipu1_sel] = imx_clk_mux("ipu1_sel", cb + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
clks[ipu2_sel] = imx_clk_mux("ipu2_sel", cb + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
clks[ldb_di0_sel] = imx_clk_mux_p("ldb_di0_sel", cb + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
clks[ldb_di1_sel] = imx_clk_mux_p("ldb_di1_sel", cb + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
clks[ipu1_di0_pre_sel] = imx_clk_mux_p("ipu1_di0_pre_sel", cb + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels));
clks[ipu1_di1_pre_sel] = imx_clk_mux_p("ipu1_di1_pre_sel", cb + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels));
clks[ipu2_di0_pre_sel] = imx_clk_mux_p("ipu2_di0_pre_sel", cb + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels));
clks[ipu2_di1_pre_sel] = imx_clk_mux_p("ipu2_di1_pre_sel", cb + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels));
clks[ipu1_di0_sel] = imx_clk_mux_p("ipu1_di0_sel", cb + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels));
clks[ipu1_di1_sel] = imx_clk_mux_p("ipu1_di1_sel", cb + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels));
clks[ipu2_di0_sel] = imx_clk_mux_p("ipu2_di0_sel", cb + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels));
clks[ipu2_di1_sel] = imx_clk_mux_p("ipu2_di1_sel", cb + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels));
clks[ipu1_podf] = imx_clk_divider("ipu1_podf", "ipu1_sel", cb + 0x3c, 11, 3);
clks[ipu2_podf] = imx_clk_divider("ipu2_podf", "ipu2_sel", cb + 0x3c, 16, 3);
clks[ldb_di0_div_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
clks[ldb_di0_podf] = imx_clk_divider("ldb_di0_podf", "ldb_di0_div_3_5", cb + 0x20, 10, 1);
clks[ldb_di1_div_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
clks[ldb_di1_podf] = imx_clk_divider("ldb_di1_podf", "ldb_di1_div_3_5", cb + 0x20, 11, 1);
clks[ipu1_di0_pre] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", cb + 0x34, 3, 3);
clks[ipu1_di1_pre] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", cb + 0x34, 12, 3);
clks[ipu2_di0_pre] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", cb + 0x38, 3, 3);
clks[ipu2_di1_pre] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", cb + 0x38, 12, 3);
clkdev_add_physbase(clks[ipu1_podf], MX6_IPU1_BASE_ADDR, "bus");
clkdev_add_physbase(clks[ipu1_di0_sel], MX6_IPU1_BASE_ADDR, "di0");
clkdev_add_physbase(clks[ipu1_di1_sel], MX6_IPU1_BASE_ADDR, "di1");
clkdev_add_physbase(clks[ipu2_podf], MX6_IPU2_BASE_ADDR, "bus");
clkdev_add_physbase(clks[ipu2_di0_sel], MX6_IPU2_BASE_ADDR, "di0");
clkdev_add_physbase(clks[ipu2_di1_sel], MX6_IPU2_BASE_ADDR, "di1");
clkdev_add_physbase(clks[ldb_di0_sel], 0x020e0008, "di0_pll");
clkdev_add_physbase(clks[ldb_di1_sel], 0x020e0008, "di1_pll");
clkdev_add_physbase(clks[ipu1_di0_sel], 0x020e0008, "di0_sel");
clkdev_add_physbase(clks[ipu1_di1_sel], 0x020e0008, "di1_sel");
clkdev_add_physbase(clks[ipu2_di0_sel], 0x020e0008, "di2_sel");
clkdev_add_physbase(clks[ipu2_di1_sel], 0x020e0008, "di3_sel");
clkdev_add_physbase(clks[ldb_di0], 0x020e0008, "di0");
clkdev_add_physbase(clks[ldb_di1], 0x020e0008, "di1");
clkdev_add_physbase(clks[ahb], 0x00120000, "iahb");
clkdev_add_physbase(clks[pll3_pfd1_540m], 0x00120000, "isfr");
clk_set_parent(clks[ipu1_di0_sel], clks[ipu1_di0_pre]);
clk_set_parent(clks[ipu1_di1_sel], clks[ipu1_di1_pre]);
clk_set_parent(clks[ipu2_di0_sel], clks[ipu2_di0_pre]);
clk_set_parent(clks[ipu2_di1_sel], clks[ipu2_di1_pre]);
clk_set_parent(clks[ipu1_di0_pre_sel], clks[pll5_video_div]);
clk_set_parent(clks[ipu1_di1_pre_sel], clks[pll5_video_div]);
clk_set_parent(clks[ipu2_di0_pre_sel], clks[pll5_video_div]);
clk_set_parent(clks[ipu2_di1_pre_sel], clks[pll5_video_div]);
if ((imx_silicon_revision() != IMX_CHIP_REV_1_0) ||
cpu_is_mx6dl()) {
clk_set_parent(clks[ldb_di0_sel], clks[pll5_video_div]);
clk_set_parent(clks[ldb_di1_sel], clks[pll5_video_div]);
}
}
static int imx6_ccm_probe(struct device_d *dev)
{
void __iomem *base, *anatop_base, *ccm_base;
@ -281,7 +421,6 @@ static int imx6_ccm_probe(struct device_d *dev)
clks[arm] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
clks[ahb] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
clkdev_add_physbase(clks[uart_serial_podf], MX6_UART1_BASE_ADDR, NULL);
clkdev_add_physbase(clks[uart_serial_podf], MX6_UART2_BASE_ADDR, NULL);
clkdev_add_physbase(clks[uart_serial_podf], MX6_UART3_BASE_ADDR, NULL);
@ -310,10 +449,16 @@ static int imx6_ccm_probe(struct device_d *dev)
clkdev_add_physbase(clks[ipg_per], MX6_PWM3_BASE_ADDR, "per");
clkdev_add_physbase(clks[ipg_per], MX6_PWM4_BASE_ADDR, "per");
if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3))
imx6_add_video_clks(anatop_base, ccm_base);
writel(0xffffffff, ccm_base + CCGR0);
writel(0xf0ffffff, ccm_base + CCGR1); /* gate GPU3D, GPU2D */
writel(0xffffffff, ccm_base + CCGR2);
writel(0x3fff0000, ccm_base + CCGR3); /* gate OpenVG, LDB, IPU1, IPU2 */
if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3))
writel(0xffffffff, ccm_base + CCGR3); /* gate OpenVG */
else
writel(0x3fffffff, ccm_base + CCGR3); /* gate OpenVG, LDB, IPU1, IPU2 */
writel(0xffffffff, ccm_base + CCGR4);
writel(0xffffffff, ccm_base + CCGR5);
writel(0xffff3fff, ccm_base + CCGR6); /* gate VPU */

View File

@ -27,6 +27,12 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
return clk_mux(name, reg, shift, width, parents, num_parents, 0);
}
static inline struct clk *imx_clk_mux_p(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, u8 num_parents)
{
return clk_mux(name, reg, shift, width, parents, num_parents, CLK_SET_RATE_PARENT);
}
static inline struct clk *imx_clk_gate(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{

View File

@ -26,6 +26,9 @@
#define MX6_SPBA_BASE_ADDR (MX6_ATZ1_BASE_ADDR + 0x3C000)
#define MX6_VPU_BASE_ADDR (MX6_ATZ1_BASE_ADDR + 0x40000)
#define MX6_IPU1_BASE_ADDR 0x02400000
#define MX6_IPU2_BASE_ADDR 0x02800000
/* ATZ#1- On Platform */
#define MX6_AIPS1_ON_BASE_ADDR (MX6_ATZ1_BASE_ADDR + 0x7C000)