diff options
Diffstat (limited to 'drivers/video/fbdev/omap2/dss')
-rw-r--r-- | drivers/video/fbdev/omap2/dss/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/dispc.c | 54 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/dpi.c | 26 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/dsi.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/dss.c | 219 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/dss.h | 22 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/dss_features.c | 3 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/hdmi5.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/hdmi_phy.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/hdmi_pll.c | 6 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/omapdss-boot-init.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/pll.c | 10 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/dss/video-pll.c | 211 |
13 files changed, 547 insertions, 10 deletions
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile index 2ea9d382354c..b5136d3d4b77 100644 --- a/drivers/video/fbdev/omap2/dss/Makefile +++ b/drivers/video/fbdev/omap2/dss/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o obj-$(CONFIG_OMAP2_DSS) += omapdss.o # Core DSS files omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - output.o dss-of.o pll.o + output.o dss-of.o pll.o video-pll.o # DSS compat layer files omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ dispc-compat.o display-sysfs.o diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c index 9850d9ef9a9d..31b743c70272 100644 --- a/drivers/video/fbdev/omap2/dss/dispc.c +++ b/drivers/video/fbdev/omap2/dss/dispc.c @@ -36,6 +36,9 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/sizes.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/of.h> #include <video/omapdss.h> @@ -117,6 +120,9 @@ static struct { const struct dispc_features *feat; bool is_enabled; + + struct regmap *syscon_pol; + u32 syscon_pol_offset; } dispc; enum omap_color_component { @@ -2958,6 +2964,25 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, FLD_VAL(vsync_level, 12, 12); dispc_write_reg(DISPC_POL_FREQ(channel), l); + + if (dispc.syscon_pol) { + const int shifts[] = { + [OMAP_DSS_CHANNEL_LCD] = 0, + [OMAP_DSS_CHANNEL_LCD2] = 1, + [OMAP_DSS_CHANNEL_LCD3] = 2, + }; + + u32 mask, val; + + mask = (1 << 0) | (1 << 3) | (1 << 6); + val = (rf << 0) | (ipc << 3) | (onoff << 6); + + mask <<= 16 + shifts[channel]; + val <<= 16 + shifts[channel]; + + regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset, + mask, val); + } } /* change name to mode? */ @@ -3037,10 +3062,16 @@ unsigned long dispc_fclk_rate(void) break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: pll = dss_pll_find("dsi0"); + if (!pll) + pll = dss_pll_find("video0"); + r = pll->cinfo.clkout[0]; break; case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: pll = dss_pll_find("dsi1"); + if (!pll) + pll = dss_pll_find("video1"); + r = pll->cinfo.clkout[0]; break; default: @@ -3069,10 +3100,16 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) break; case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: pll = dss_pll_find("dsi0"); + if (!pll) + pll = dss_pll_find("video0"); + r = pll->cinfo.clkout[0]; break; case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: pll = dss_pll_find("dsi1"); + if (!pll) + pll = dss_pll_find("video1"); + r = pll->cinfo.clkout[0]; break; default: @@ -3668,6 +3705,7 @@ static int __init dispc_init_features(struct platform_device *pdev) break; case OMAPDSS_VER_OMAP5: + case OMAPDSS_VER_DRA7xx: src = &omap54xx_dispc_feats; break; @@ -3728,6 +3766,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) u32 rev; int r = 0; struct resource *dispc_mem; + struct device_node *np = pdev->dev.of_node; dispc.pdev = pdev; @@ -3754,6 +3793,20 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) return -ENODEV; } + if (np && of_property_read_bool(np, "syscon-pol")) { + dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol"); + if (IS_ERR(dispc.syscon_pol)) { + dev_err(&pdev->dev, "failed to get syscon-pol regmap\n"); + return PTR_ERR(dispc.syscon_pol); + } + + if (of_property_read_u32_index(np, "syscon-pol", 1, + &dispc.syscon_pol_offset)) { + dev_err(&pdev->dev, "failed to get syscon-pol offset\n"); + return -EINVAL; + } + } + pm_runtime_enable(&pdev->dev); r = dispc_runtime_get(); @@ -3832,6 +3885,7 @@ static const struct of_device_id dispc_of_match[] = { { .compatible = "ti,omap3-dispc", }, { .compatible = "ti,omap4-dispc", }, { .compatible = "ti,omap5-dispc", }, + { .compatible = "ti,dra7-dispc", }, {}, }; diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c index 9a2f8c3b102d..f83e7b030249 100644 --- a/drivers/video/fbdev/omap2/dss/dpi.c +++ b/drivers/video/fbdev/omap2/dss/dpi.c @@ -106,6 +106,17 @@ static struct dss_pll *dpi_get_pll(enum omap_channel channel) return NULL; } + case OMAPDSS_VER_DRA7xx: + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + case OMAP_DSS_CHANNEL_LCD2: + return dss_pll_find("video0"); + case OMAP_DSS_CHANNEL_LCD3: + return dss_pll_find("video1"); + default: + return NULL; + } + default: return NULL; } @@ -590,6 +601,10 @@ static void dpi_init_pll(struct dpi_data *dpi) if (!pll) return; + /* On DRA7 we need to set a mux to use the PLL */ + if (omapdss_get_version() == OMAPDSS_VER_DRA7xx) + dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel); + if (dpi_verify_dsi_pll(pll)) { DSSWARN("DSI PLL not operational\n"); return; @@ -615,6 +630,17 @@ static enum omap_channel dpi_get_channel(int port_num) case OMAPDSS_VER_AM43xx: return OMAP_DSS_CHANNEL_LCD; + case OMAPDSS_VER_DRA7xx: + switch (port_num) { + case 2: + return OMAP_DSS_CHANNEL_LCD3; + case 1: + return OMAP_DSS_CHANNEL_LCD2; + case 0: + default: + return OMAP_DSS_CHANNEL_LCD; + } + case OMAPDSS_VER_OMAP4430_ES1: case OMAPDSS_VER_OMAP4430_ES2: case OMAPDSS_VER_OMAP4: diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c index 3e44c580b1f8..5081f6fb1737 100644 --- a/drivers/video/fbdev/omap2/dss/dsi.c +++ b/drivers/video/fbdev/omap2/dss/dsi.c @@ -5238,6 +5238,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev) } pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1"; + pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2; pll->clkin = clk; pll->base = dsi->pll_base; diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c index 9987154d50b4..a6d10d4279f3 100644 --- a/drivers/video/fbdev/omap2/dss/dss.c +++ b/drivers/video/fbdev/omap2/dss/dss.c @@ -34,7 +34,10 @@ #include <linux/pm_runtime.h> #include <linux/gfp.h> #include <linux/sizes.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> #include <linux/of.h> +#include <linux/regulator/consumer.h> #include <video/omapdss.h> @@ -63,14 +66,11 @@ struct dss_reg { #define REG_FLD_MOD(idx, val, start, end) \ dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) -static int dss_runtime_get(void); -static void dss_runtime_put(void); - struct dss_features { u8 fck_div_max; u8 dss_fck_multiplier; const char *parent_clk_name; - enum omap_display_type *ports; + const enum omap_display_type *ports; int num_ports; int (*dpi_select_source)(int port, enum omap_channel channel); }; @@ -78,6 +78,8 @@ struct dss_features { static struct { struct platform_device *pdev; void __iomem *base; + struct regmap *syscon_pll_ctrl; + u32 syscon_pll_ctrl_offset; struct clk *parent_clk; struct clk *dss_clk; @@ -95,6 +97,9 @@ static struct { u32 ctx[DSS_SZ_REGS / sizeof(u32)]; const struct dss_features *feat; + + struct dss_pll *video1_pll; + struct dss_pll *video2_pll; } dss; static const char * const dss_generic_clk_source_names[] = { @@ -158,6 +163,99 @@ static void dss_restore_context(void) #undef SR #undef RR +void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable) +{ + unsigned shift; + unsigned val; + + if (!dss.syscon_pll_ctrl) + return; + + val = !enable; + + switch (pll_id) { + case DSS_PLL_VIDEO1: + shift = 0; + break; + case DSS_PLL_VIDEO2: + shift = 1; + break; + case DSS_PLL_HDMI: + shift = 2; + break; + default: + DSSERR("illegal DSS PLL ID %d\n", pll_id); + return; + } + + regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset, + 1 << shift, val << shift); +} + +void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id, + enum omap_channel channel) +{ + unsigned shift, val; + + if (!dss.syscon_pll_ctrl) + return; + + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + shift = 3; + + switch (pll_id) { + case DSS_PLL_VIDEO1: + val = 0; break; + case DSS_PLL_HDMI: + val = 1; break; + default: + DSSERR("error in PLL mux config for LCD\n"); + return; + } + + break; + case OMAP_DSS_CHANNEL_LCD2: + shift = 5; + + switch (pll_id) { + case DSS_PLL_VIDEO1: + val = 0; break; + case DSS_PLL_VIDEO2: + val = 1; break; + case DSS_PLL_HDMI: + val = 2; break; + default: + DSSERR("error in PLL mux config for LCD2\n"); + return; + } + + break; + case OMAP_DSS_CHANNEL_LCD3: + shift = 7; + + switch (pll_id) { + case DSS_PLL_VIDEO1: + val = 1; break; + case DSS_PLL_VIDEO2: + val = 0; break; + case DSS_PLL_HDMI: + val = 2; break; + default: + DSSERR("error in PLL mux config for LCD3\n"); + return; + } + + break; + default: + DSSERR("error in PLL mux config\n"); + return; + } + + regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset, + 0x3 << shift, val << shift); +} + void dss_sdi_init(int datapairs) { u32 l; @@ -605,6 +703,26 @@ static int dss_dpi_select_source_omap5(int port, enum omap_channel channel) return 0; } +static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel) +{ + switch (port) { + case 0: + return dss_dpi_select_source_omap5(port, channel); + case 1: + if (channel != OMAP_DSS_CHANNEL_LCD2) + return -EINVAL; + break; + case 2: + if (channel != OMAP_DSS_CHANNEL_LCD3) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + int dss_dpi_select_source(int port, enum omap_channel channel) { return dss.feat->dpi_select_source(port, channel); @@ -643,7 +761,7 @@ static void dss_put_clocks(void) clk_put(dss.parent_clk); } -static int dss_runtime_get(void) +int dss_runtime_get(void) { int r; @@ -654,7 +772,7 @@ static int dss_runtime_get(void) return r < 0 ? r : 0; } -static void dss_runtime_put(void) +void dss_runtime_put(void) { int r; @@ -677,15 +795,21 @@ void dss_debug_dump_clocks(struct seq_file *s) #endif -static enum omap_display_type omap2plus_ports[] = { +static const enum omap_display_type omap2plus_ports[] = { OMAP_DISPLAY_TYPE_DPI, }; -static enum omap_display_type omap34xx_ports[] = { +static const enum omap_display_type omap34xx_ports[] = { OMAP_DISPLAY_TYPE_DPI, OMAP_DISPLAY_TYPE_SDI, }; +static const enum omap_display_type dra7xx_ports[] = { + OMAP_DISPLAY_TYPE_DPI, + OMAP_DISPLAY_TYPE_DPI, + OMAP_DISPLAY_TYPE_DPI, +}; + static const struct dss_features omap24xx_dss_feats __initconst = { /* * fck div max is really 16, but the divider range has gaps. The range @@ -744,6 +868,15 @@ static const struct dss_features am43xx_dss_feats __initconst = { .num_ports = ARRAY_SIZE(omap2plus_ports), }; +static const struct dss_features dra7xx_dss_feats __initconst = { + .fck_div_max = 64, + .dss_fck_multiplier = 1, + .parent_clk_name = "dpll_per_x2_ck", + .dpi_select_source = &dss_dpi_select_source_dra7xx, + .ports = dra7xx_ports, + .num_ports = ARRAY_SIZE(dra7xx_ports), +}; + static int __init dss_init_features(struct platform_device *pdev) { const struct dss_features *src; @@ -784,6 +917,10 @@ static int __init dss_init_features(struct platform_device *pdev) src = &am43xx_dss_feats; break; + case OMAPDSS_VER_DRA7xx: + src = &dra7xx_dss_feats; + break; + default: return -ENODEV; } @@ -884,8 +1021,10 @@ static void __exit dss_uninit_ports(struct platform_device *pdev) static int __init omap_dsshw_probe(struct platform_device *pdev) { struct resource *dss_mem; + struct device_node *np = pdev->dev.of_node; u32 rev; int r; + struct regulator *pll_regulator; dss.pdev = pdev; @@ -940,6 +1079,57 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss_init_ports(pdev); + if (np && of_property_read_bool(np, "syscon-pll-ctrl")) { + dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np, + "syscon-pll-ctrl"); + if (IS_ERR(dss.syscon_pll_ctrl)) { + dev_err(&pdev->dev, + "failed to get syscon-pll-ctrl regmap\n"); + return PTR_ERR(dss.syscon_pll_ctrl); + } + + if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1, + &dss.syscon_pll_ctrl_offset)) { + dev_err(&pdev->dev, + "failed to get syscon-pll-ctrl offset\n"); + return -EINVAL; + } + } + + pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video"); + if (IS_ERR(pll_regulator)) { + r = PTR_ERR(pll_regulator); + + switch (r) { + case -ENOENT: + pll_regulator = NULL; + break; + + case -EPROBE_DEFER: + return -EPROBE_DEFER; + + default: + DSSERR("can't get DPLL VDDA regulator\n"); + return r; + } + } + + if (of_property_match_string(np, "reg-names", "pll1") >= 0) { + dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator); + if (IS_ERR(dss.video1_pll)) { + r = PTR_ERR(dss.video1_pll); + goto err_pll_init; + } + } + + if (of_property_match_string(np, "reg-names", "pll2") >= 0) { + dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator); + if (IS_ERR(dss.video2_pll)) { + r = PTR_ERR(dss.video2_pll); + goto err_pll_init; + } + } + rev = dss_read_reg(DSS_REVISION); printk(KERN_INFO "OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); @@ -950,6 +1140,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) return 0; +err_pll_init: + if (dss.video1_pll) + dss_video_pll_uninit(dss.video1_pll); + + if (dss.video2_pll) + dss_video_pll_uninit(dss.video2_pll); err_runtime_get: pm_runtime_disable(&pdev->dev); err_setup_clocks: @@ -959,6 +1155,12 @@ err_setup_clocks: static int __exit omap_dsshw_remove(struct platform_device *pdev) { + if (dss.video1_pll) + dss_video_pll_uninit(dss.video1_pll); + + if (dss.video2_pll) + dss_video_pll_uninit(dss.video2_pll); + dss_uninit_ports(pdev); pm_runtime_disable(&pdev->dev); @@ -1003,6 +1205,7 @@ static const struct of_device_id dss_of_match[] = { { .compatible = "ti,omap3-dss", }, { .compatible = "ti,omap4-dss", }, { .compatible = "ti,omap5-dss", }, + { .compatible = "ti,dra7-dss", }, {}, }; diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h index 14fb0c23f4a2..4812eee2622a 100644 --- a/drivers/video/fbdev/omap2/dss/dss.h +++ b/drivers/video/fbdev/omap2/dss/dss.h @@ -100,6 +100,14 @@ enum dss_writeback_channel { DSS_WB_LCD3_MGR = 7, }; +enum dss_pll_id { + DSS_PLL_DSI1, + DSS_PLL_DSI2, + DSS_PLL_HDMI, + DSS_PLL_VIDEO1, + DSS_PLL_VIDEO2, +}; + struct dss_pll; #define DSS_PLL_MAX_HSDIVS 4 @@ -150,6 +158,7 @@ struct dss_pll_hw { struct dss_pll { const char *name; + enum dss_pll_id id; struct clk *clkin; struct regulator *regulator; @@ -250,6 +259,9 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl); int dss_init_platform_driver(void) __init; void dss_uninit_platform_driver(void); +int dss_runtime_get(void); +void dss_runtime_put(void); + unsigned long dss_get_dispc_clk_rate(void); int dss_dpi_select_source(int port, enum omap_channel channel); void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); @@ -257,6 +269,11 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); void dss_dump_clocks(struct seq_file *s); +/* DSS VIDEO PLL */ +struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, + struct regulator *regulator); +void dss_video_pll_uninit(struct dss_pll *pll); + /* dss-of */ struct device_node *dss_of_port_get_parent_device(struct device_node *port); u32 dss_of_port_get_port_number(struct device_node *port); @@ -265,6 +282,10 @@ u32 dss_of_port_get_port_number(struct device_node *port); void dss_debug_dump_clocks(struct seq_file *s); #endif +void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable); +void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id, + enum omap_channel channel); + void dss_sdi_init(int datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); @@ -446,5 +467,6 @@ int dss_pll_write_config_type_a(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo); int dss_pll_write_config_type_b(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo); +int dss_pll_wait_reset_done(struct dss_pll *pll); #endif diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c index 0e3da809473c..376270b777f8 100644 --- a/drivers/video/fbdev/omap2/dss/dss_features.c +++ b/drivers/video/fbdev/omap2/dss/dss_features.c @@ -223,7 +223,7 @@ static const enum omap_dss_output_id omap5_dss_supported_outputs[] = { OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2, /* OMAP_DSS_CHANNEL_DIGIT */ - OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI, + OMAP_DSS_OUTPUT_HDMI, /* OMAP_DSS_CHANNEL_LCD2 */ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | @@ -943,6 +943,7 @@ void dss_features_init(enum omapdss_version version) break; case OMAPDSS_VER_OMAP5: + case OMAPDSS_VER_DRA7xx: omap_current_dss_features = &omap5_dss_features; break; diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c index 39aae3aa7136..3f0b34a7031a 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5.c @@ -787,6 +787,7 @@ static const struct dev_pm_ops hdmi_pm_ops = { static const struct of_device_id hdmi_of_match[] = { { .compatible = "ti,omap5-hdmi", }, + { .compatible = "ti,dra7-hdmi", }, {}, }; diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c index bc9e07d2afbe..1f5d19c119ce 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c @@ -208,6 +208,7 @@ static int hdmi_phy_init_features(struct platform_device *pdev) break; case OMAPDSS_VER_OMAP5: + case OMAPDSS_VER_DRA7xx: src = &omap54xx_phy_feats; break; diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c index ac83ef5cfd7d..06e23a7c432c 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c @@ -104,6 +104,8 @@ static int hdmi_pll_enable(struct dss_pll *dsspll) struct hdmi_wp_data *wp = pll->wp; u16 r = 0; + dss_ctrl_pll_enable(DSS_PLL_HDMI, true); + r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); if (r) return r; @@ -117,6 +119,8 @@ static void hdmi_pll_disable(struct dss_pll *dsspll) struct hdmi_wp_data *wp = pll->wp; hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); + + dss_ctrl_pll_enable(DSS_PLL_HDMI, false); } static const struct dss_pll_ops dsi_pll_ops = { @@ -185,6 +189,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data } pll->name = "hdmi"; + pll->id = DSS_PLL_HDMI; pll->base = hpll->base; pll->clkin = clk; @@ -196,6 +201,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data break; case OMAPDSS_VER_OMAP5: + case OMAPDSS_VER_DRA7xx: pll->hw = &dss_omap5_hdmi_pll_hw; break; diff --git a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c index 2f0822ee3ff9..42b87f95267c 100644 --- a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c +++ b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c @@ -186,6 +186,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = { { .compatible = "ti,omap3-dss", }, { .compatible = "ti,omap4-dss", }, { .compatible = "ti,omap5-dss", }, + { .compatible = "ti,dra7-dss", }, {}, }; diff --git a/drivers/video/fbdev/omap2/dss/pll.c b/drivers/video/fbdev/omap2/dss/pll.c index 335ffac224b9..f974ddcd3b6e 100644 --- a/drivers/video/fbdev/omap2/dss/pll.c +++ b/drivers/video/fbdev/omap2/dss/pll.c @@ -222,6 +222,16 @@ static int wait_for_bit_change(void __iomem *reg, int bitnum, int value) return !value; } +int dss_pll_wait_reset_done(struct dss_pll *pll) +{ + void __iomem *base = pll->base; + + if (wait_for_bit_change(base + PLL_STATUS, 0, 1) != 1) + return -ETIMEDOUT; + else + return 0; +} + static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask) { int t = 100; diff --git a/drivers/video/fbdev/omap2/dss/video-pll.c b/drivers/video/fbdev/omap2/dss/video-pll.c new file mode 100644 index 000000000000..b1ec59e42940 --- /dev/null +++ b/drivers/video/fbdev/omap2/dss/video-pll.c @@ -0,0 +1,211 @@ +/* +* Copyright (C) 2014 Texas Instruments Ltd +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 as published by +* the Free Software Foundation. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/sched.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +struct dss_video_pll { + struct dss_pll pll; + + struct device *dev; + + void __iomem *clkctrl_base; +}; + +#define REG_MOD(reg, val, start, end) \ + writel_relaxed(FLD_MOD(readl_relaxed(reg), val, start, end), reg) + +static void dss_dpll_enable_scp_clk(struct dss_video_pll *vpll) +{ + REG_MOD(vpll->clkctrl_base, 1, 14, 14); /* CIO_CLK_ICG */ +} + +static void dss_dpll_disable_scp_clk(struct dss_video_pll *vpll) +{ + REG_MOD(vpll->clkctrl_base, 0, 14, 14); /* CIO_CLK_ICG */ +} + +static void dss_dpll_power_enable(struct dss_video_pll *vpll) +{ + REG_MOD(vpll->clkctrl_base, 2, 31, 30); /* PLL_POWER_ON_ALL */ + + /* + * DRA7x PLL CTRL's PLL_PWR_STATUS seems to always return 0, + * so we have to use fixed delay here. + */ + msleep(1); +} + +static void dss_dpll_power_disable(struct dss_video_pll *vpll) +{ + REG_MOD(vpll->clkctrl_base, 0, 31, 30); /* PLL_POWER_OFF */ +} + +static int dss_video_pll_enable(struct dss_pll *pll) +{ + struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll); + int r; + + r = dss_runtime_get(); + if (r) + return r; + + dss_ctrl_pll_enable(pll->id, true); + + dss_dpll_enable_scp_clk(vpll); + + r = dss_pll_wait_reset_done(pll); + if (r) + goto err_reset; + + dss_dpll_power_enable(vpll); + + return 0; + +err_reset: + dss_dpll_disable_scp_clk(vpll); + dss_ctrl_pll_enable(pll->id, false); + dss_runtime_put(); + + return r; +} + +static void dss_video_pll_disable(struct dss_pll *pll) +{ + struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll); + + dss_dpll_power_disable(vpll); + + dss_dpll_disable_scp_clk(vpll); + + dss_ctrl_pll_enable(pll->id, false); + + dss_runtime_put(); +} + +static const struct dss_pll_ops dss_pll_ops = { + .enable = dss_video_pll_enable, + .disable = dss_video_pll_disable, + .set_config = dss_pll_write_config_type_a, +}; + +static const struct dss_pll_hw dss_dra7_video_pll_hw = { + .n_max = (1 << 8) - 1, + .m_max = (1 << 12) - 1, + .mX_max = (1 << 5) - 1, + .fint_min = 500000, + .fint_max = 2500000, + .clkdco_max = 1800000000, + + .n_msb = 8, + .n_lsb = 1, + .m_msb = 20, + .m_lsb = 9, + + .mX_msb[0] = 25, + .mX_lsb[0] = 21, + .mX_msb[1] = 30, + .mX_lsb[1] = 26, + + .has_refsel = true, +}; + +struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, + struct regulator *regulator) +{ + const char * const reg_name[] = { "pll1", "pll2" }; + const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" }; + const char * const clkin_name[] = { "video1_clk", "video2_clk" }; + + struct resource *res; + struct dss_video_pll *vpll; + void __iomem *pll_base, *clkctrl_base; + struct clk *clk; + struct dss_pll *pll; + int r; + + /* PLL CONTROL */ + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name[id]); + if (!res) { + dev_err(&pdev->dev, + "missing platform resource data for pll%d\n", id); + return ERR_PTR(-ENODEV); + } + + pll_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pll_base)) { + dev_err(&pdev->dev, "failed to ioremap pll%d reg_name\n", id); + return ERR_CAST(pll_base); + } + + /* CLOCK CONTROL */ + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + clkctrl_name[id]); + if (!res) { + dev_err(&pdev->dev, + "missing platform resource data for pll%d\n", id); + return ERR_PTR(-ENODEV); + } + + clkctrl_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(clkctrl_base)) { + dev_err(&pdev->dev, "failed to ioremap pll%d clkctrl\n", id); + return ERR_CAST(clkctrl_base); + } + + /* CLKIN */ + + clk = devm_clk_get(&pdev->dev, clkin_name[id]); + if (IS_ERR(clk)) { + DSSERR("can't get video pll clkin\n"); + return ERR_CAST(clk); + } + + vpll = devm_kzalloc(&pdev->dev, sizeof(*vpll), GFP_KERNEL); + if (!vpll) + return ERR_PTR(-ENOMEM); + + vpll->dev = &pdev->dev; + vpll->clkctrl_base = clkctrl_base; + + pll = &vpll->pll; + + pll->name = id == 0 ? "video0" : "video1"; + pll->id = id == 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2; + pll->clkin = clk; + pll->regulator = regulator; + pll->base = pll_base; + pll->hw = &dss_dra7_video_pll_hw; + pll->ops = &dss_pll_ops; + + r = dss_pll_register(pll); + if (r) + return ERR_PTR(r); + + return pll; +} + +void dss_video_pll_uninit(struct dss_pll *pll) +{ + dss_pll_unregister(pll); +} |