Merge branch '4.8/omapdrm-pll' (omapdrm PLL work)

Merge omapdrm PLL work, which makes it possible to use the DSS PLLs in a
versatile manner, for example, HDMI PLL can be used for LCDs.
This commit is contained in:
Tomi Valkeinen
2016-06-06 10:16:51 +03:00
16 changed files with 509 additions and 373 deletions

View File

@@ -76,6 +76,8 @@ struct dss_features {
const enum omap_display_type *ports;
int num_ports;
int (*dpi_select_source)(int port, enum omap_channel channel);
int (*select_lcd_source)(enum omap_channel channel,
enum dss_clk_source clk_src);
};
static struct {
@@ -92,9 +94,9 @@ static struct {
unsigned long cache_prate;
struct dispc_clock_info cache_dispc_cinfo;
enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
enum omap_dss_clk_source dispc_clk_source;
enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
enum dss_clk_source dsi_clk_source[MAX_NUM_DSI];
enum dss_clk_source dispc_clk_source;
enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
bool ctx_valid;
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
@@ -106,11 +108,14 @@ static struct {
} dss;
static const char * const dss_generic_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC",
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI",
[DSS_CLK_SRC_FCK] = "FCK",
[DSS_CLK_SRC_PLL1_1] = "PLL1:1",
[DSS_CLK_SRC_PLL1_2] = "PLL1:2",
[DSS_CLK_SRC_PLL1_3] = "PLL1:3",
[DSS_CLK_SRC_PLL2_1] = "PLL2:1",
[DSS_CLK_SRC_PLL2_2] = "PLL2:2",
[DSS_CLK_SRC_PLL2_3] = "PLL2:3",
[DSS_CLK_SRC_HDMI_PLL] = "HDMI PLL",
};
static bool dss_initialized;
@@ -203,68 +208,70 @@ void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable)
1 << shift, val << shift);
}
void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src,
enum omap_channel channel)
{
unsigned shift, val;
if (!dss.syscon_pll_ctrl)
return;
return -EINVAL;
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
shift = 3;
switch (pll_id) {
case DSS_PLL_VIDEO1:
switch (clk_src) {
case DSS_CLK_SRC_PLL1_1:
val = 0; break;
case DSS_PLL_HDMI:
case DSS_CLK_SRC_HDMI_PLL:
val = 1; break;
default:
DSSERR("error in PLL mux config for LCD\n");
return;
return -EINVAL;
}
break;
case OMAP_DSS_CHANNEL_LCD2:
shift = 5;
switch (pll_id) {
case DSS_PLL_VIDEO1:
switch (clk_src) {
case DSS_CLK_SRC_PLL1_3:
val = 0; break;
case DSS_PLL_VIDEO2:
case DSS_CLK_SRC_PLL2_3:
val = 1; break;
case DSS_PLL_HDMI:
case DSS_CLK_SRC_HDMI_PLL:
val = 2; break;
default:
DSSERR("error in PLL mux config for LCD2\n");
return;
return -EINVAL;
}
break;
case OMAP_DSS_CHANNEL_LCD3:
shift = 7;
switch (pll_id) {
case DSS_PLL_VIDEO1:
val = 1; break;
case DSS_PLL_VIDEO2:
switch (clk_src) {
case DSS_CLK_SRC_PLL2_1:
val = 0; break;
case DSS_PLL_HDMI:
case DSS_CLK_SRC_PLL1_3:
val = 1; break;
case DSS_CLK_SRC_HDMI_PLL:
val = 2; break;
default:
DSSERR("error in PLL mux config for LCD3\n");
return;
return -EINVAL;
}
break;
default:
DSSERR("error in PLL mux config\n");
return;
return -EINVAL;
}
regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
0x3 << shift, val << shift);
return 0;
}
void dss_sdi_init(int datapairs)
@@ -354,14 +361,14 @@ void dss_sdi_disable(void)
REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
}
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
const char *dss_get_clk_source_name(enum dss_clk_source clk_src)
{
return dss_generic_clk_source_names[clk_src];
}
void dss_dump_clocks(struct seq_file *s)
{
const char *fclk_name, *fclk_real_name;
const char *fclk_name;
unsigned long fclk_rate;
if (dss_runtime_get())
@@ -369,12 +376,11 @@ void dss_dump_clocks(struct seq_file *s)
seq_printf(s, "- DSS -\n");
fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
fclk_name = dss_get_clk_source_name(DSS_CLK_SRC_FCK);
fclk_rate = clk_get_rate(dss.dss_clk);
seq_printf(s, "%s (%s) = %lu\n",
fclk_name, fclk_real_name,
seq_printf(s, "%s = %lu\n",
fclk_name,
fclk_rate);
dss_runtime_put();
@@ -403,19 +409,42 @@ static void dss_dump_regs(struct seq_file *s)
#undef DUMPREG
}
static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
static int dss_get_channel_index(enum omap_channel channel)
{
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
return 0;
case OMAP_DSS_CHANNEL_LCD2:
return 1;
case OMAP_DSS_CHANNEL_LCD3:
return 2;
default:
WARN_ON(1);
return 0;
}
}
static void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
{
int b;
u8 start, end;
/*
* We always use PRCM clock as the DISPC func clock, except on DSS3,
* where we don't have separate DISPC and LCD clock sources.
*/
if (WARN_ON(dss_has_feature(FEAT_LCD_CLK_SRC) &&
clk_src != DSS_CLK_SRC_FCK))
return;
switch (clk_src) {
case OMAP_DSS_CLK_SRC_FCK:
case DSS_CLK_SRC_FCK:
b = 0;
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
case DSS_CLK_SRC_PLL1_1:
b = 1;
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
case DSS_CLK_SRC_PLL2_1:
b = 2;
break;
default:
@@ -431,19 +460,19 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
}
void dss_select_dsi_clk_source(int dsi_module,
enum omap_dss_clk_source clk_src)
enum dss_clk_source clk_src)
{
int b, pos;
switch (clk_src) {
case OMAP_DSS_CLK_SRC_FCK:
case DSS_CLK_SRC_FCK:
b = 0;
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
case DSS_CLK_SRC_PLL1_2:
BUG_ON(dsi_module != 0);
b = 1;
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
case DSS_CLK_SRC_PLL2_2:
BUG_ON(dsi_module != 1);
b = 1;
break;
@@ -458,59 +487,125 @@ void dss_select_dsi_clk_source(int dsi_module,
dss.dsi_clk_source[dsi_module] = clk_src;
}
void dss_select_lcd_clk_source(enum omap_channel channel,
enum omap_dss_clk_source clk_src)
static int dss_lcd_clk_mux_dra7(enum omap_channel channel,
enum dss_clk_source clk_src)
{
int b, ix, pos;
const u8 ctrl_bits[] = {
[OMAP_DSS_CHANNEL_LCD] = 0,
[OMAP_DSS_CHANNEL_LCD2] = 12,
[OMAP_DSS_CHANNEL_LCD3] = 19,
};
u8 ctrl_bit = ctrl_bits[channel];
int r;
if (clk_src == DSS_CLK_SRC_FCK) {
/* LCDx_CLK_SWITCH */
REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit);
return -EINVAL;
}
r = dss_ctrl_pll_set_control_mux(clk_src, channel);
if (r)
return r;
REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit);
return 0;
}
static int dss_lcd_clk_mux_omap5(enum omap_channel channel,
enum dss_clk_source clk_src)
{
const u8 ctrl_bits[] = {
[OMAP_DSS_CHANNEL_LCD] = 0,
[OMAP_DSS_CHANNEL_LCD2] = 12,
[OMAP_DSS_CHANNEL_LCD3] = 19,
};
const enum dss_clk_source allowed_plls[] = {
[OMAP_DSS_CHANNEL_LCD] = DSS_CLK_SRC_PLL1_1,
[OMAP_DSS_CHANNEL_LCD2] = DSS_CLK_SRC_FCK,
[OMAP_DSS_CHANNEL_LCD3] = DSS_CLK_SRC_PLL2_1,
};
u8 ctrl_bit = ctrl_bits[channel];
if (clk_src == DSS_CLK_SRC_FCK) {
/* LCDx_CLK_SWITCH */
REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit);
return -EINVAL;
}
if (WARN_ON(allowed_plls[channel] != clk_src))
return -EINVAL;
REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit);
return 0;
}
static int dss_lcd_clk_mux_omap4(enum omap_channel channel,
enum dss_clk_source clk_src)
{
const u8 ctrl_bits[] = {
[OMAP_DSS_CHANNEL_LCD] = 0,
[OMAP_DSS_CHANNEL_LCD2] = 12,
};
const enum dss_clk_source allowed_plls[] = {
[OMAP_DSS_CHANNEL_LCD] = DSS_CLK_SRC_PLL1_1,
[OMAP_DSS_CHANNEL_LCD2] = DSS_CLK_SRC_PLL2_1,
};
u8 ctrl_bit = ctrl_bits[channel];
if (clk_src == DSS_CLK_SRC_FCK) {
/* LCDx_CLK_SWITCH */
REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit);
return 0;
}
if (WARN_ON(allowed_plls[channel] != clk_src))
return -EINVAL;
REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit);
return 0;
}
void dss_select_lcd_clk_source(enum omap_channel channel,
enum dss_clk_source clk_src)
{
int idx = dss_get_channel_index(channel);
int r;
if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
dss_select_dispc_clk_source(clk_src);
dss.lcd_clk_source[idx] = clk_src;
return;
}
switch (clk_src) {
case OMAP_DSS_CLK_SRC_FCK:
b = 0;
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
b = 1;
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
channel != OMAP_DSS_CHANNEL_LCD3);
b = 1;
break;
default:
BUG();
r = dss.feat->select_lcd_source(channel, clk_src);
if (r)
return;
}
pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
(channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19);
REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */
ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
(channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
dss.lcd_clk_source[ix] = clk_src;
dss.lcd_clk_source[idx] = clk_src;
}
enum omap_dss_clk_source dss_get_dispc_clk_source(void)
enum dss_clk_source dss_get_dispc_clk_source(void)
{
return dss.dispc_clk_source;
}
enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
enum dss_clk_source dss_get_dsi_clk_source(int dsi_module)
{
return dss.dsi_clk_source[dsi_module];
}
enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
{
if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
(channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
return dss.lcd_clk_source[ix];
int idx = dss_get_channel_index(channel);
return dss.lcd_clk_source[idx];
} else {
/* LCD_CLK source is the same as DISPC_FCLK source for
* OMAP2 and OMAP3 */
@@ -859,6 +954,7 @@ static const struct dss_features omap44xx_dss_feats = {
.dpi_select_source = &dss_dpi_select_source_omap4,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
.select_lcd_source = &dss_lcd_clk_mux_omap4,
};
static const struct dss_features omap54xx_dss_feats = {
@@ -868,6 +964,7 @@ static const struct dss_features omap54xx_dss_feats = {
.dpi_select_source = &dss_dpi_select_source_omap5,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
.select_lcd_source = &dss_lcd_clk_mux_omap5,
};
static const struct dss_features am43xx_dss_feats = {
@@ -886,6 +983,7 @@ static const struct dss_features dra7xx_dss_feats = {
.dpi_select_source = &dss_dpi_select_source_dra7xx,
.ports = dra7xx_ports,
.num_ports = ARRAY_SIZE(dra7xx_ports),
.select_lcd_source = &dss_lcd_clk_mux_dra7,
};
static int dss_init_features(struct platform_device *pdev)
@@ -1143,18 +1241,18 @@ static int dss_bind(struct device *dev)
/* Select DPLL */
REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
#ifdef CONFIG_OMAP2_DSS_VENC
REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
#endif
dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK;
dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK;
dss.dispc_clk_source = DSS_CLK_SRC_FCK;
dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK;
dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK;
rev = dss_read_reg(DSS_REVISION);
printk(KERN_INFO "OMAP DSS rev %d.%d\n",