fbdev changes for 3.19

* support for mx6sl and mx6sx
 * OMAP HDMI audio rewrite to make it finally work
 * OMAP video PLL work to prepare for new DRA7xx SoCs
 * simplefb DT related improvements
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJUiZ3aAAoJEPo9qoy8lh71I4gP/0P0H7DtqwSRGWVDenVYC4o1
 IoRJgRBSu16gg9h1yEbluGIB0S/F+0vvgJLv83fXPIFYCApjeIyola60wzTxsCQO
 5+DY8IbioAiYCAC4brPbE17PQZhkqomVZy7Eo/WW8Bp7NRwhIVGgstjfKIKarRmR
 l7Zu7ciRt7A1677P8Te09w3hzWfvRNOCYi/lbSbHHeItpAfOqBQLI6WYh0WYFgbW
 oOqplfJKQDW67mj+DmnR8ep+CwN6/+AvmialkwiPKKBjE578zmTJuRXr/ZZMgqmY
 WiqC3O3yoTaDn9ReUw1CBmeYbWfhjdDotydTc0eUD+Z3cGIKlBh3coprpOEILuuU
 FCsbBWQGP2FtYPfvl0R80+VHLRhDxFXV0hcxocyvNzK78AfKrTKBMYTdPh/i+0M/
 +pA70thjlKpqZgBK6ukyMnB6KxiB9tOFdFx7PRXby4VgRGHqeYNRlvYPcYOPsgb2
 xRMIxCWhJHqZzNlv+bC6R4T8UTOIT4HoWthF0yN7SYrVujX0+1ky8Zz37jcTFnnS
 aNQ8MQL+6Uy1pa0v2c4oGH0qNVCWpsAXMtFBB1VkNzQg1vyuJHd3lgWYND33+3Uo
 C08lqzC3FZeA70g5iOhoP5IaW1JdQOe4EfDPU+ZjBQFB0Mgy025Z9dsAUcb08/2C
 s/ZXcRvzXMzpBSflsUzf
 =VAZB
 -----END PGP SIGNATURE-----

Merge tag 'fbdev-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux

Pull fbdev updates from Tomi Valkeinen:
 - support for mx6sl and mx6sx
 - OMAP HDMI audio rewrite to make it finally work
 - OMAP video PLL work to prepare for new DRA7xx SoCs
 - simplefb DT related improvements

* tag 'fbdev-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (81 commits)
  video: uvesafb: Deletion of an unnecessary check before the function call "platform_device_put"
  video: fbdev-VIA: Deletion of an unnecessary check before the function call "framebuffer_release"
  video: fbdev-MMP: Deletion of an unnecessary check before the function call "mmp_unregister_path"
  video: mx3fb: Deletion of an unnecessary check before the function call "backlight_device_unregister"
  video: fbdev-OMAP2: Deletion of unnecessary checks before the function call "i2c_put_adapter"
  video: fbdev-SIS: Deletion of unnecessary checks before the function call "pci_dev_put"
  video: smscufx: Deletion of unnecessary checks before the function call "vfree"
  video: udlfb: Deletion of unnecessary checks before the function call "vfree"
  video: uvesafb: Deletion of an unnecessary check before the function call "uvesafb_free"
  video: fbdev-LCDC: Deletion of an unnecessary check before the function call "vfree"
  video: fbdev: arkfb: suppress build warning
  video: fbdev: s3fb: suppress build warning
  video: fbdev: vt8623fb: suppress build warning
  OMAPDSS: hdmi5: Fix bit field for IEC958_AES2_CON_SOURCE
  OMAPDSS: hdmi: Remove __exit qualifier from hdmi_uninit_output()
  OMAPDSS: hdmi5: Change hdmi_wp idlemode to to no_idle for audio playback
  OMAPDSS: Remove all references to obsolete HDMI audio callbacks
  ASoC: omap: Remove obsolete HDMI audio code and Kconfig options
  OMAPDSS: hdmi5: Register ASoC platform device for omap hdmi audio
  OMAPDSS: hdmi5: Remove callbacks for the old ASoC DAI driver
  ...
This commit is contained in:
Linus Torvalds 2014-12-11 12:46:32 -08:00
commit 413fd0e3fb
58 changed files with 2398 additions and 2156 deletions

View file

@ -3624,7 +3624,7 @@ static int __init fb_console_init(void)
return 0;
}
module_init(fb_console_init);
fs_initcall(fb_console_init);
#ifdef MODULE

View file

@ -2408,7 +2408,7 @@ config FB_JZ4740
config FB_MXS
tristate "MXS LCD framebuffer support"
depends on FB && ARCH_MXS
depends on FB && (ARCH_MXS || ARCH_MXC)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT

View file

@ -27,7 +27,6 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/hardirq.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>

View file

@ -1016,7 +1016,7 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
par->state.vgabase = (void __iomem *) vga_res.start;
par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
/* FIXME get memsize */
regval = vga_rseq(par->state.vgabase, 0x10);

View file

@ -223,10 +223,10 @@ struct mmp_path *mmp_register_path(struct mmp_path_info *info)
EXPORT_SYMBOL_GPL(mmp_register_path);
/*
* mmp_unregister_path - unregister and destory path
* @p: path to be destoried.
* mmp_unregister_path - unregister and destroy path
* @p: path to be destroyed.
*
* this function registers path and destorys it.
* this function registers path and destroys it.
*/
void mmp_unregister_path(struct mmp_path *path)
{

View file

@ -441,8 +441,7 @@ static void path_deinit(struct mmphw_path_plat *path_plat)
if (!path_plat)
return;
if (path_plat->path)
mmp_unregister_path(path_plat->path);
mmp_unregister_path(path_plat->path);
}
static int mmphw_probe(struct platform_device *pdev)

View file

@ -334,8 +334,7 @@ static void mx3fb_init_backlight(struct mx3fb_data *fbd)
static void mx3fb_exit_backlight(struct mx3fb_data *fbd)
{
if (fbd->bl)
backlight_device_unregister(fbd->bl);
backlight_device_unregister(fbd->bl);
}
static void mx3fb_dma_done(void *);

View file

@ -172,6 +172,8 @@ struct mxsfb_info {
struct fb_info fb_info;
struct platform_device *pdev;
struct clk *clk;
struct clk *clk_axi;
struct clk *clk_disp_axi;
void __iomem *base; /* registers */
unsigned allocated_size;
int enabled;
@ -331,6 +333,11 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
}
}
if (host->clk_axi)
clk_prepare_enable(host->clk_axi);
if (host->clk_disp_axi)
clk_prepare_enable(host->clk_disp_axi);
clk_prepare_enable(host->clk);
clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
@ -374,6 +381,10 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
clk_disable_unprepare(host->clk);
if (host->clk_disp_axi)
clk_disable_unprepare(host->clk_disp_axi);
if (host->clk_axi)
clk_disable_unprepare(host->clk_axi);
host->enabled = 0;
@ -867,6 +878,14 @@ static int mxsfb_probe(struct platform_device *pdev)
goto fb_release;
}
host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");
if (IS_ERR(host->clk_axi))
host->clk_axi = NULL;
host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");
if (IS_ERR(host->clk_disp_axi))
host->clk_disp_axi = NULL;
host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");
if (IS_ERR(host->reg_lcd))
host->reg_lcd = NULL;

View file

@ -262,8 +262,7 @@ static int dvic_probe_pdata(struct platform_device *pdev)
in = omap_dss_find_output(pdata->source);
if (in == NULL) {
if (ddata->i2c_adapter)
i2c_put_adapter(ddata->i2c_adapter);
i2c_put_adapter(ddata->i2c_adapter);
dev_err(&pdev->dev, "Failed to find video source\n");
return -EPROBE_DEFER;
@ -352,8 +351,7 @@ static int dvic_probe(struct platform_device *pdev)
err_reg:
omap_dss_put_device(ddata->in);
if (ddata->i2c_adapter)
i2c_put_adapter(ddata->i2c_adapter);
i2c_put_adapter(ddata->i2c_adapter);
return r;
}
@ -371,8 +369,7 @@ static int __exit dvic_remove(struct platform_device *pdev)
omap_dss_put_device(in);
if (ddata->i2c_adapter)
i2c_put_adapter(ddata->i2c_adapter);
i2c_put_adapter(ddata->i2c_adapter);
return 0;
}

View file

@ -170,98 +170,6 @@ static bool hdmic_detect(struct omap_dss_device *dssdev)
return in->ops.hdmi->detect(in);
}
static int hdmic_audio_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
/* enable audio only if the display is active */
if (!omapdss_device_is_enabled(dssdev))
return -EPERM;
r = in->ops.hdmi->audio_enable(in);
if (r)
return r;
dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
return 0;
}
static void hdmic_audio_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
in->ops.hdmi->audio_disable(in);
dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
}
static int hdmic_audio_start(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
/*
* No need to check the panel state. It was checked when trasitioning
* to AUDIO_ENABLED.
*/
if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED)
return -EPERM;
r = in->ops.hdmi->audio_start(in);
if (r)
return r;
dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
return 0;
}
static void hdmic_audio_stop(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
in->ops.hdmi->audio_stop(in);
dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
}
static bool hdmic_audio_supported(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_enabled(dssdev))
return false;
return in->ops.hdmi->audio_supported(in);
}
static int hdmic_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
/* config audio only if the display is active */
if (!omapdss_device_is_enabled(dssdev))
return -EPERM;
r = in->ops.hdmi->audio_config(in, audio);
if (r)
return r;
dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
return 0;
}
static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
@ -296,13 +204,6 @@ static struct omap_dss_driver hdmic_driver = {
.detect = hdmic_detect,
.set_hdmi_mode = hdmic_set_hdmi_mode,
.set_hdmi_infoframe = hdmic_set_infoframe,
.audio_enable = hdmic_audio_enable,
.audio_disable = hdmic_audio_disable,
.audio_start = hdmic_audio_start,
.audio_stop = hdmic_audio_stop,
.audio_supported = hdmic_audio_supported,
.audio_config = hdmic_audio_config,
};
static int hdmic_probe_pdata(struct platform_device *pdev)

View file

@ -249,6 +249,7 @@ static int tfp410_probe(struct platform_device *pdev)
dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
dssdev->owner = THIS_MODULE;
dssdev->phy.dpi.data_lines = ddata->data_lines;
dssdev->port_num = 1;
r = omapdss_register_output(dssdev);
if (r) {

View file

@ -193,55 +193,6 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
return gpio_get_value_cansleep(ddata->hpd_gpio);
}
static int tpd_audio_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->audio_enable(in);
}
static void tpd_audio_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
in->ops.hdmi->audio_disable(in);
}
static int tpd_audio_start(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->audio_start(in);
}
static void tpd_audio_stop(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
in->ops.hdmi->audio_stop(in);
}
static bool tpd_audio_supported(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->audio_supported(in);
}
static int tpd_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->audio_config(in, audio);
}
static int tpd_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi)
{
@ -275,13 +226,6 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
.detect = tpd_detect,
.set_infoframe = tpd_set_infoframe,
.set_hdmi_mode = tpd_set_hdmi_mode,
.audio_enable = tpd_audio_enable,
.audio_disable = tpd_audio_disable,
.audio_start = tpd_audio_start,
.audio_stop = tpd_audio_stop,
.audio_supported = tpd_audio_supported,
.audio_config = tpd_audio_config,
};
static int tpd_probe_pdata(struct platform_device *pdev)
@ -409,6 +353,7 @@ static int tpd_probe(struct platform_device *pdev)
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->owner = THIS_MODULE;
dssdev->port_num = 1;
in = ddata->in;

View file

@ -74,9 +74,6 @@ config OMAP4_DSS_HDMI
help
HDMI support for OMAP4 based SoCs.
config OMAP4_DSS_HDMI_AUDIO
bool
config OMAP5_DSS_HDMI
bool "HDMI support for OMAP5"
default n
@ -86,10 +83,6 @@ config OMAP5_DSS_HDMI
Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
specification.
config OMAP5_DSS_HDMI_AUDIO
depends on OMAP5_DSS_HDMI
bool
config OMAP2_DSS_SDI
bool "SDI support"
default n

View file

@ -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
output.o dss-of.o 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

View file

@ -3028,7 +3028,7 @@ static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
unsigned long dispc_fclk_rate(void)
{
struct platform_device *dsidev;
struct dss_pll *pll;
unsigned long r = 0;
switch (dss_get_dispc_clk_source()) {
@ -3036,12 +3036,12 @@ unsigned long dispc_fclk_rate(void)
r = dss_get_dispc_clk_rate();
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(0);
r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
pll = dss_pll_find("dsi0");
r = pll->cinfo.clkout[0];
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(1);
r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
pll = dss_pll_find("dsi1");
r = pll->cinfo.clkout[0];
break;
default:
BUG();
@ -3053,7 +3053,7 @@ unsigned long dispc_fclk_rate(void)
unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
{
struct platform_device *dsidev;
struct dss_pll *pll;
int lcd;
unsigned long r;
u32 l;
@ -3068,12 +3068,12 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
r = dss_get_dispc_clk_rate();
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(0);
r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
pll = dss_pll_find("dsi0");
r = pll->cinfo.clkout[0];
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(1);
r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
pll = dss_pll_find("dsi1");
r = pll->cinfo.clkout[0];
break;
default:
BUG();

View file

@ -31,17 +31,20 @@
#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <video/omapdss.h>
#include "dss.h"
#include "dss_features.h"
static struct {
#define HSDIV_DISPC 0
struct dpi_data {
struct platform_device *pdev;
struct regulator *vdds_dsi_reg;
struct platform_device *dsidev;
struct dss_pll *pll;
struct mutex lock;
@ -52,9 +55,20 @@ static struct {
struct omap_dss_device output;
bool port_initialized;
} dpi;
};
static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
{
return container_of(dssdev, struct dpi_data, output);
}
/* only used in non-DT mode */
static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
{
return dev_get_drvdata(&pdev->dev);
}
static struct dss_pll *dpi_get_pll(enum omap_channel channel)
{
/*
* XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
@ -75,9 +89,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case OMAPDSS_VER_OMAP4:
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
return dsi_get_dsidev_from_id(0);
return dss_pll_find("dsi0");
case OMAP_DSS_CHANNEL_LCD2:
return dsi_get_dsidev_from_id(1);
return dss_pll_find("dsi1");
default:
return NULL;
}
@ -85,9 +99,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case OMAPDSS_VER_OMAP5:
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
return dsi_get_dsidev_from_id(0);
return dss_pll_find("dsi0");
case OMAP_DSS_CHANNEL_LCD3:
return dsi_get_dsidev_from_id(1);
return dss_pll_find("dsi1");
default:
return NULL;
}
@ -114,7 +128,7 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
}
struct dpi_clk_calc_ctx {
struct platform_device *dsidev;
struct dss_pll *pll;
/* inputs */
@ -122,7 +136,7 @@ struct dpi_clk_calc_ctx {
/* outputs */
struct dsi_clock_info dsi_cinfo;
struct dss_pll_clock_info dsi_cinfo;
unsigned long fck;
struct dispc_clock_info dispc_cinfo;
};
@ -154,7 +168,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
}
static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
void *data)
{
struct dpi_clk_calc_ctx *ctx = data;
@ -164,30 +178,31 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
* shifted. So skip all odd dividers when the pixel clock is on the
* higher side.
*/
if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000)
if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
return false;
ctx->dsi_cinfo.regm_dispc = regm_dispc;
ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
dpi_calc_dispc_cb, ctx);
}
static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
unsigned long pll,
static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
unsigned long clkdco,
void *data)
{
struct dpi_clk_calc_ctx *ctx = data;
ctx->dsi_cinfo.regn = regn;
ctx->dsi_cinfo.regm = regm;
ctx->dsi_cinfo.n = n;
ctx->dsi_cinfo.m = m;
ctx->dsi_cinfo.fint = fint;
ctx->dsi_cinfo.clkin4ddr = pll;
ctx->dsi_cinfo.clkdco = clkdco;
return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
dpi_calc_hsdiv_cb, ctx);
return dss_pll_hsdiv_calc(ctx->pll, clkdco,
ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
dpi_calc_hsdiv_cb, ctx);
}
static bool dpi_calc_dss_cb(unsigned long fck, void *data)
@ -200,23 +215,23 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data)
dpi_calc_dispc_cb, ctx);
}
static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
struct dpi_clk_calc_ctx *ctx)
{
unsigned long clkin;
unsigned long pll_min, pll_max;
clkin = dsi_get_pll_clkin(dpi.dsidev);
memset(ctx, 0, sizeof(*ctx));
ctx->dsidev = dpi.dsidev;
ctx->pll = dpi->pll;
ctx->pck_min = pck - 1000;
ctx->pck_max = pck + 1000;
ctx->dsi_cinfo.clkin = clkin;
pll_min = 0;
pll_max = 0;
return dsi_pll_calc(dpi.dsidev, clkin,
clkin = clk_get_rate(ctx->pll->clkin);
return dss_pll_calc(ctx->pll, clkin,
pll_min, pll_max,
dpi_calc_pll_cb, ctx);
}
@ -252,7 +267,7 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
static int dpi_set_dsi_clk(enum omap_channel channel,
static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div)
{
@ -260,28 +275,28 @@ static int dpi_set_dsi_clk(enum omap_channel channel,
int r;
bool ok;
ok = dpi_dsi_clk_calc(pck_req, &ctx);
ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
if (!ok)
return -EINVAL;
r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
if (r)
return r;
dss_select_lcd_clk_source(channel,
dpi_get_alt_clk_src(channel));
dpi.mgr_config.clock_info = ctx.dispc_cinfo;
dpi->mgr_config.clock_info = ctx.dispc_cinfo;
*fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
*fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
*lck_div = ctx.dispc_cinfo.lck_div;
*pck_div = ctx.dispc_cinfo.pck_div;
return 0;
}
static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
int *lck_div, int *pck_div)
static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
unsigned long *fck, int *lck_div, int *pck_div)
{
struct dpi_clk_calc_ctx ctx;
int r;
@ -295,7 +310,7 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
if (r)
return r;
dpi.mgr_config.clock_info = ctx.dispc_cinfo;
dpi->mgr_config.clock_info = ctx.dispc_cinfo;
*fck = ctx.fck;
*lck_div = ctx.dispc_cinfo.lck_div;
@ -304,19 +319,21 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
return 0;
}
static int dpi_set_mode(struct omap_overlay_manager *mgr)
static int dpi_set_mode(struct dpi_data *dpi)
{
struct omap_video_timings *t = &dpi.timings;
struct omap_dss_device *out = &dpi->output;
struct omap_overlay_manager *mgr = out->manager;
struct omap_video_timings *t = &dpi->timings;
int lck_div = 0, pck_div = 0;
unsigned long fck = 0;
unsigned long pck;
int r = 0;
if (dpi.dsidev)
r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck,
if (dpi->pll)
r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
&lck_div, &pck_div);
else
r = dpi_set_dispc_clk(t->pixelclock, &fck,
r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
&lck_div, &pck_div);
if (r)
return r;
@ -335,28 +352,32 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr)
return 0;
}
static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
static void dpi_config_lcd_manager(struct dpi_data *dpi)
{
dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
struct omap_dss_device *out = &dpi->output;
struct omap_overlay_manager *mgr = out->manager;
dpi.mgr_config.stallmode = false;
dpi.mgr_config.fifohandcheck = false;
dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
dpi.mgr_config.video_port_width = dpi.data_lines;
dpi->mgr_config.stallmode = false;
dpi->mgr_config.fifohandcheck = false;
dpi.mgr_config.lcden_sig_polarity = 0;
dpi->mgr_config.video_port_width = dpi->data_lines;
dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
dpi->mgr_config.lcden_sig_polarity = 0;
dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
}
static int dpi_display_enable(struct omap_dss_device *dssdev)
{
struct omap_dss_device *out = &dpi.output;
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_dss_device *out = &dpi->output;
int r;
mutex_lock(&dpi.lock);
mutex_lock(&dpi->lock);
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
DSSERR("no VDSS_DSI regulator\n");
r = -ENODEV;
goto err_no_reg;
@ -369,7 +390,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
}
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
r = regulator_enable(dpi.vdds_dsi_reg);
r = regulator_enable(dpi->vdds_dsi_reg);
if (r)
goto err_reg_enable;
}
@ -378,25 +399,21 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
r = dss_dpi_select_source(out->manager->id);
r = dss_dpi_select_source(out->port_num, out->manager->id);
if (r)
goto err_src_sel;
if (dpi.dsidev) {
r = dsi_runtime_get(dpi.dsidev);
if (r)
goto err_get_dsi;
r = dsi_pll_init(dpi.dsidev, 0, 1);
if (dpi->pll) {
r = dss_pll_enable(dpi->pll);
if (r)
goto err_dsi_pll_init;
}
r = dpi_set_mode(out->manager);
r = dpi_set_mode(dpi);
if (r)
goto err_set_mode;
dpi_config_lcd_manager(out->manager);
dpi_config_lcd_manager(dpi);
mdelay(2);
@ -404,78 +421,80 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_mgr_enable;
mutex_unlock(&dpi.lock);
mutex_unlock(&dpi->lock);
return 0;
err_mgr_enable:
err_set_mode:
if (dpi.dsidev)
dsi_pll_uninit(dpi.dsidev, true);
if (dpi->pll)
dss_pll_disable(dpi->pll);
err_dsi_pll_init:
if (dpi.dsidev)
dsi_runtime_put(dpi.dsidev);
err_get_dsi:
err_src_sel:
dispc_runtime_put();
err_get_dispc:
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
regulator_disable(dpi->vdds_dsi_reg);
err_reg_enable:
err_no_out_mgr:
err_no_reg:
mutex_unlock(&dpi.lock);
mutex_unlock(&dpi->lock);
return r;
}
static void dpi_display_disable(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dpi.output.manager;
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_overlay_manager *mgr = dpi->output.manager;
mutex_lock(&dpi.lock);
mutex_lock(&dpi->lock);
dss_mgr_disable(mgr);
if (dpi.dsidev) {
if (dpi->pll) {
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
dsi_pll_uninit(dpi.dsidev, true);
dsi_runtime_put(dpi.dsidev);
dss_pll_disable(dpi->pll);
}
dispc_runtime_put();
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
regulator_disable(dpi->vdds_dsi_reg);
mutex_unlock(&dpi.lock);
mutex_unlock(&dpi->lock);
}
static void dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
DSSDBG("dpi_set_timings\n");
mutex_lock(&dpi.lock);
mutex_lock(&dpi->lock);
dpi.timings = *timings;
dpi->timings = *timings;
mutex_unlock(&dpi.lock);
mutex_unlock(&dpi->lock);
}
static void dpi_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
mutex_lock(&dpi.lock);
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
*timings = dpi.timings;
mutex_lock(&dpi->lock);
mutex_unlock(&dpi.lock);
*timings = dpi->timings;
mutex_unlock(&dpi->lock);
}
static int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct omap_overlay_manager *mgr = dpi.output.manager;
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_overlay_manager *mgr = dpi->output.manager;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
@ -488,12 +507,12 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
if (timings->pixelclock == 0)
return -EINVAL;
if (dpi.dsidev) {
ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx);
if (dpi->pll) {
ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
if (!ok)
return -EINVAL;
fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
} else {
ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
if (!ok)
@ -514,74 +533,69 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
{
mutex_lock(&dpi.lock);
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
dpi.data_lines = data_lines;
mutex_lock(&dpi->lock);
mutex_unlock(&dpi.lock);
dpi->data_lines = data_lines;
mutex_unlock(&dpi->lock);
}
static int dpi_verify_dsi_pll(struct platform_device *dsidev)
static int dpi_verify_dsi_pll(struct dss_pll *pll)
{
int r;
/* do initial setup with the PLL to see if it is operational */
r = dsi_runtime_get(dsidev);
r = dss_pll_enable(pll);
if (r)
return r;
r = dsi_pll_init(dsidev, 0, 1);
if (r) {
dsi_runtime_put(dsidev);
return r;
}
dsi_pll_uninit(dsidev, true);
dsi_runtime_put(dsidev);
dss_pll_disable(pll);
return 0;
}
static int dpi_init_regulator(void)
static int dpi_init_regulator(struct dpi_data *dpi)
{
struct regulator *vdds_dsi;
if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
return 0;
if (dpi.vdds_dsi_reg)
if (dpi->vdds_dsi_reg)
return 0;
vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi");
vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
if (IS_ERR(vdds_dsi)) {
if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
DSSERR("can't get VDDS_DSI regulator\n");
return PTR_ERR(vdds_dsi);
}
dpi.vdds_dsi_reg = vdds_dsi;
dpi->vdds_dsi_reg = vdds_dsi;
return 0;
}
static void dpi_init_pll(void)
static void dpi_init_pll(struct dpi_data *dpi)
{
struct platform_device *dsidev;
struct dss_pll *pll;
if (dpi.dsidev)
if (dpi->pll)
return;
dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
if (!dsidev)
pll = dpi_get_pll(dpi->output.dispc_channel);
if (!pll)
return;
if (dpi_verify_dsi_pll(dsidev)) {
if (dpi_verify_dsi_pll(pll)) {
DSSWARN("DSI PLL not operational\n");
return;
}
dpi.dsidev = dsidev;
dpi->pll = pll;
}
/*
@ -590,7 +604,7 @@ static void dpi_init_pll(void)
* the channel in some more dynamic manner, or get the channel as a user
* parameter.
*/
static enum omap_channel dpi_get_channel(void)
static enum omap_channel dpi_get_channel(int port_num)
{
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP24xx:
@ -618,14 +632,15 @@ static enum omap_channel dpi_get_channel(void)
static int dpi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_overlay_manager *mgr;
int r;
r = dpi_init_regulator();
r = dpi_init_regulator(dpi);
if (r)
return r;
dpi_init_pll();
dpi_init_pll(dpi);
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
if (!mgr)
@ -676,13 +691,14 @@ static const struct omapdss_dpi_ops dpi_ops = {
static void dpi_init_output(struct platform_device *pdev)
{
struct omap_dss_device *out = &dpi.output;
struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
struct omap_dss_device *out = &dpi->output;
out->dev = &pdev->dev;
out->id = OMAP_DSS_OUTPUT_DPI;
out->output_type = OMAP_DISPLAY_TYPE_DPI;
out->name = "dpi.0";
out->dispc_channel = dpi_get_channel();
out->dispc_channel = dpi_get_channel(0);
out->ops.dpi = &dpi_ops;
out->owner = THIS_MODULE;
@ -691,16 +707,69 @@ static void dpi_init_output(struct platform_device *pdev)
static void __exit dpi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_device *out = &dpi.output;
struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
struct omap_dss_device *out = &dpi->output;
omapdss_unregister_output(out);
}
static void dpi_init_output_port(struct platform_device *pdev,
struct device_node *port)
{
struct dpi_data *dpi = port->data;
struct omap_dss_device *out = &dpi->output;
int r;
u32 port_num;
r = of_property_read_u32(port, "reg", &port_num);
if (r)
port_num = 0;
switch (port_num) {
case 2:
out->name = "dpi.2";
break;
case 1:
out->name = "dpi.1";
break;
case 0:
default:
out->name = "dpi.0";
break;
}
out->dev = &pdev->dev;
out->id = OMAP_DSS_OUTPUT_DPI;
out->output_type = OMAP_DISPLAY_TYPE_DPI;
out->dispc_channel = dpi_get_channel(port_num);
out->port_num = port_num;
out->ops.dpi = &dpi_ops;
out->owner = THIS_MODULE;
omapdss_register_output(out);
}
static void __exit dpi_uninit_output_port(struct device_node *port)
{
struct dpi_data *dpi = port->data;
struct omap_dss_device *out = &dpi->output;
omapdss_unregister_output(out);
}
static int omap_dpi_probe(struct platform_device *pdev)
{
dpi.pdev = pdev;
struct dpi_data *dpi;
mutex_init(&dpi.lock);
dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
if (!dpi)
return -ENOMEM;
dpi->pdev = pdev;
dev_set_drvdata(&pdev->dev, dpi);
mutex_init(&dpi->lock);
dpi_init_output(pdev);
@ -736,10 +805,15 @@ void __exit dpi_uninit_platform_driver(void)
int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
{
struct dpi_data *dpi;
struct device_node *ep;
u32 datalines;
int r;
dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
if (!dpi)
return -ENOMEM;
ep = omapdss_of_get_next_endpoint(port, NULL);
if (!ep)
return 0;
@ -750,17 +824,18 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
goto err_datalines;
}
dpi.data_lines = datalines;
dpi->data_lines = datalines;
of_node_put(ep);
dpi.pdev = pdev;
dpi->pdev = pdev;
port->data = dpi;
mutex_init(&dpi.lock);
mutex_init(&dpi->lock);
dpi_init_output(pdev);
dpi_init_output_port(pdev, port);
dpi.port_initialized = true;
dpi->port_initialized = true;
return 0;
@ -770,10 +845,12 @@ err_datalines:
return r;
}
void __exit dpi_uninit_port(void)
void __exit dpi_uninit_port(struct device_node *port)
{
if (!dpi.port_initialized)
struct dpi_data *dpi = port->data;
if (!dpi->port_initialized)
return;
dpi_uninit_output(dpi.pdev);
dpi_uninit_output_port(port);
}

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,8 @@
#include <video/omapdss.h>
#include "dss.h"
struct device_node *
omapdss_of_get_next_port(const struct device_node *parent,
struct device_node *prev)
@ -84,20 +86,17 @@ omapdss_of_get_next_endpoint(const struct device_node *parent,
}
EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
static struct device_node *
omapdss_of_get_remote_device_node(const struct device_node *node)
struct device_node *dss_of_port_get_parent_device(struct device_node *port)
{
struct device_node *np;
int i;
np = of_parse_phandle(node, "remote-endpoint", 0);
if (!np)
if (!port)
return NULL;
np = of_get_next_parent(np);
np = of_get_next_parent(port);
for (i = 0; i < 3 && np; ++i) {
for (i = 0; i < 2 && np; ++i) {
struct property *prop;
prop = of_find_property(np, "compatible", NULL);
@ -111,6 +110,31 @@ omapdss_of_get_remote_device_node(const struct device_node *node)
return NULL;
}
u32 dss_of_port_get_port_number(struct device_node *port)
{
int r;
u32 reg;
r = of_property_read_u32(port, "reg", &reg);
if (r)
reg = 0;
return reg;
}
static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
{
struct device_node *np;
np = of_parse_phandle(node, "remote-endpoint", 0);
if (!np)
return NULL;
np = of_get_next_parent(np);
return np;
}
struct device_node *
omapdss_of_get_first_endpoint(const struct device_node *parent)
{
@ -133,27 +157,25 @@ struct omap_dss_device *
omapdss_of_find_source_for_first_ep(struct device_node *node)
{
struct device_node *ep;
struct device_node *src_node;
struct device_node *src_port;
struct omap_dss_device *src;
ep = omapdss_of_get_first_endpoint(node);
if (!ep)
return ERR_PTR(-EINVAL);
src_node = omapdss_of_get_remote_device_node(ep);
src_port = omapdss_of_get_remote_port(ep);
if (!src_port) {
of_node_put(ep);
return ERR_PTR(-EINVAL);
}
of_node_put(ep);
if (!src_node)
return ERR_PTR(-EINVAL);
src = omap_dss_find_output_by_port_node(src_port);
src = omap_dss_find_output_by_node(src_node);
of_node_put(src_port);
of_node_put(src_node);
if (!src)
return ERR_PTR(-EPROBE_DEFER);
return src;
return src ? src : ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);

View file

@ -70,7 +70,9 @@ struct dss_features {
u8 fck_div_max;
u8 dss_fck_multiplier;
const char *parent_clk_name;
int (*dpi_select_source)(enum omap_channel channel);
enum omap_display_type *ports;
int num_ports;
int (*dpi_select_source)(int port, enum omap_channel channel);
};
static struct {
@ -294,7 +296,6 @@ static void dss_dump_regs(struct seq_file *s)
static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
{
struct platform_device *dsidev;
int b;
u8 start, end;
@ -304,13 +305,9 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
b = 1;
dsidev = dsi_get_dsidev_from_id(0);
dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
b = 2;
dsidev = dsi_get_dsidev_from_id(1);
dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
default:
BUG();
@ -327,7 +324,6 @@ 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)
{
struct platform_device *dsidev;
int b, pos;
switch (clk_src) {
@ -337,14 +333,10 @@ void dss_select_dsi_clk_source(int dsi_module,
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
BUG_ON(dsi_module != 0);
b = 1;
dsidev = dsi_get_dsidev_from_id(0);
dsi_wait_pll_hsdiv_dsi_active(dsidev);
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
BUG_ON(dsi_module != 1);
b = 1;
dsidev = dsi_get_dsidev_from_id(1);
dsi_wait_pll_hsdiv_dsi_active(dsidev);
break;
default:
BUG();
@ -360,7 +352,6 @@ void dss_select_dsi_clk_source(int dsi_module,
void dss_select_lcd_clk_source(enum omap_channel channel,
enum omap_dss_clk_source clk_src)
{
struct platform_device *dsidev;
int b, ix, pos;
if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
@ -375,15 +366,11 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
b = 1;
dsidev = dsi_get_dsidev_from_id(0);
dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
channel != OMAP_DSS_CHANNEL_LCD3);
b = 1;
dsidev = dsi_get_dsidev_from_id(1);
dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
default:
BUG();
@ -564,7 +551,7 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
return REG_GET(DSS_CONTROL, 15, 15);
}
static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel)
{
if (channel != OMAP_DSS_CHANNEL_LCD)
return -EINVAL;
@ -572,7 +559,7 @@ static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
return 0;
}
static int dss_dpi_select_source_omap4(enum omap_channel channel)
static int dss_dpi_select_source_omap4(int port, enum omap_channel channel)
{
int val;
@ -592,7 +579,7 @@ static int dss_dpi_select_source_omap4(enum omap_channel channel)
return 0;
}
static int dss_dpi_select_source_omap5(enum omap_channel channel)
static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
{
int val;
@ -618,9 +605,9 @@ static int dss_dpi_select_source_omap5(enum omap_channel channel)
return 0;
}
int dss_dpi_select_source(enum omap_channel channel)
int dss_dpi_select_source(int port, enum omap_channel channel)
{
return dss.feat->dpi_select_source(channel);
return dss.feat->dpi_select_source(port, channel);
}
static int dss_get_clocks(void)
@ -689,6 +676,16 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif
static enum omap_display_type omap2plus_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
};
static enum omap_display_type omap34xx_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
OMAP_DISPLAY_TYPE_SDI,
};
static const struct dss_features omap24xx_dss_feats __initconst = {
/*
* fck div max is really 16, but the divider range has gaps. The range
@ -698,6 +695,8 @@ static const struct dss_features omap24xx_dss_feats __initconst = {
.dss_fck_multiplier = 2,
.parent_clk_name = "core_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features omap34xx_dss_feats __initconst = {
@ -705,6 +704,8 @@ static const struct dss_features omap34xx_dss_feats __initconst = {
.dss_fck_multiplier = 2,
.parent_clk_name = "dpll4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap34xx_ports,
.num_ports = ARRAY_SIZE(omap34xx_ports),
};
static const struct dss_features omap3630_dss_feats __initconst = {
@ -712,6 +713,8 @@ static const struct dss_features omap3630_dss_feats __initconst = {
.dss_fck_multiplier = 1,
.parent_clk_name = "dpll4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features omap44xx_dss_feats __initconst = {
@ -719,6 +722,8 @@ static const struct dss_features omap44xx_dss_feats __initconst = {
.dss_fck_multiplier = 1,
.parent_clk_name = "dpll_per_x2_ck",
.dpi_select_source = &dss_dpi_select_source_omap4,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features omap54xx_dss_feats __initconst = {
@ -726,6 +731,8 @@ static const struct dss_features omap54xx_dss_feats __initconst = {
.dss_fck_multiplier = 1,
.parent_clk_name = "dpll_per_x2_ck",
.dpi_select_source = &dss_dpi_select_source_omap5,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features am43xx_dss_feats __initconst = {
@ -733,6 +740,8 @@ static const struct dss_features am43xx_dss_feats __initconst = {
.dss_fck_multiplier = 0,
.parent_clk_name = NULL,
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
};
static int __init dss_init_features(struct platform_device *pdev)
@ -798,37 +807,77 @@ static int __init dss_init_ports(struct platform_device *pdev)
if (!port)
return 0;
if (dss.feat->num_ports == 0)
return 0;
do {
enum omap_display_type port_type;
u32 reg;
r = of_property_read_u32(port, "reg", &reg);
if (r)
reg = 0;
#ifdef CONFIG_OMAP2_DSS_DPI
if (reg == 0)
if (reg >= dss.feat->num_ports)
continue;
port_type = dss.feat->ports[reg];
switch (port_type) {
case OMAP_DISPLAY_TYPE_DPI:
dpi_init_port(pdev, port);
#endif
#ifdef CONFIG_OMAP2_DSS_SDI
if (reg == 1)
break;
case OMAP_DISPLAY_TYPE_SDI:
sdi_init_port(pdev, port);
#endif
break;
default:
break;
}
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
return 0;
}
static void __exit dss_uninit_ports(void)
static void __exit dss_uninit_ports(struct platform_device *pdev)
{
#ifdef CONFIG_OMAP2_DSS_DPI
dpi_uninit_port();
#endif
struct device_node *parent = pdev->dev.of_node;
struct device_node *port;
#ifdef CONFIG_OMAP2_DSS_SDI
sdi_uninit_port();
#endif
if (parent == NULL)
return;
port = omapdss_of_get_next_port(parent, NULL);
if (!port)
return;
if (dss.feat->num_ports == 0)
return;
do {
enum omap_display_type port_type;
u32 reg;
int r;
r = of_property_read_u32(port, "reg", &reg);
if (r)
reg = 0;
if (reg >= dss.feat->num_ports)
continue;
port_type = dss.feat->ports[reg];
switch (port_type) {
case OMAP_DISPLAY_TYPE_DPI:
dpi_uninit_port(port);
break;
case OMAP_DISPLAY_TYPE_SDI:
sdi_uninit_port(port);
break;
default:
break;
}
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
}
/* DSS HW IP initialisation */
@ -910,7 +959,7 @@ err_setup_clocks:
static int __exit omap_dsshw_remove(struct platform_device *pdev)
{
dss_uninit_ports();
dss_uninit_ports(pdev);
pm_runtime_disable(&pdev->dev);

View file

@ -100,6 +100,69 @@ enum dss_writeback_channel {
DSS_WB_LCD3_MGR = 7,
};
struct dss_pll;
#define DSS_PLL_MAX_HSDIVS 4
/*
* Type-A PLLs: clkout[]/mX[] refer to hsdiv outputs m4, m5, m6, m7.
* Type-B PLLs: clkout[0] refers to m2.
*/
struct dss_pll_clock_info {
/* rates that we get with dividers below */
unsigned long fint;
unsigned long clkdco;
unsigned long clkout[DSS_PLL_MAX_HSDIVS];
/* dividers */
u16 n;
u16 m;
u32 mf;
u16 mX[DSS_PLL_MAX_HSDIVS];
u16 sd;
};
struct dss_pll_ops {
int (*enable)(struct dss_pll *pll);
void (*disable)(struct dss_pll *pll);
int (*set_config)(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
};
struct dss_pll_hw {
unsigned n_max;
unsigned m_min;
unsigned m_max;
unsigned mX_max;
unsigned long fint_min, fint_max;
unsigned long clkdco_min, clkdco_low, clkdco_max;
u8 n_msb, n_lsb;
u8 m_msb, m_lsb;
u8 mX_msb[DSS_PLL_MAX_HSDIVS], mX_lsb[DSS_PLL_MAX_HSDIVS];
bool has_stopmode;
bool has_freqsel;
bool has_selfreqdco;
bool has_refsel;
};
struct dss_pll {
const char *name;
struct clk *clkin;
struct regulator *regulator;
void __iomem *base;
const struct dss_pll_hw *hw;
const struct dss_pll_ops *ops;
struct dss_pll_clock_info cinfo;
};
struct dispc_clock_info {
/* rates that we get with dividers below */
unsigned long lck;
@ -110,27 +173,6 @@ struct dispc_clock_info {
u16 pck_div;
};
struct dsi_clock_info {
/* rates that we get with dividers below */
unsigned long fint;
unsigned long clkin4ddr;
unsigned long clkin;
unsigned long dsi_pll_hsdiv_dispc_clk; /* OMAP3: DSI1_PLL_CLK
* OMAP4: PLLx_CLK1 */
unsigned long dsi_pll_hsdiv_dsi_clk; /* OMAP3: DSI2_PLL_CLK
* OMAP4: PLLx_CLK2 */
unsigned long lp_clk;
/* dividers */
u16 regn;
u16 regm;
u16 regm_dispc; /* OMAP3: REGM3
* OMAP4: REGM4 */
u16 regm_dsi; /* OMAP3: REGM4
* OMAP4: REGM5 */
u16 lp_clk_div;
};
struct dss_lcd_mgr_config {
enum dss_io_pad_mode io_pad_mode;
@ -209,12 +251,16 @@ int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
unsigned long dss_get_dispc_clk_rate(void);
int dss_dpi_select_source(enum omap_channel channel);
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);
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-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);
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
void dss_debug_dump_clocks(struct seq_file *s);
#endif
@ -244,16 +290,22 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min,
int sdi_init_platform_driver(void) __init;
void sdi_uninit_platform_driver(void) __exit;
#ifdef CONFIG_OMAP2_DSS_SDI
int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init;
void sdi_uninit_port(void) __exit;
void sdi_uninit_port(struct device_node *port) __exit;
#else
static inline int __init sdi_init_port(struct platform_device *pdev,
struct device_node *port)
{
return 0;
}
static inline void __exit sdi_uninit_port(struct device_node *port)
{
}
#endif
/* DSI */
typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
unsigned long pll, void *data);
typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
void *data);
#ifdef CONFIG_OMAP2_DSS_DSI
struct dentry;
@ -262,104 +314,36 @@ struct file_operations;
int dsi_init_platform_driver(void) __init;
void dsi_uninit_platform_driver(void) __exit;
int dsi_runtime_get(struct platform_device *dsidev);
void dsi_runtime_put(struct platform_device *dsidev);
void dsi_dump_clocks(struct seq_file *s);
void dsi_irq_handler(void);
u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
unsigned long pll_min, unsigned long pll_max,
dsi_pll_calc_func func, void *data);
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo);
int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
bool enable_hsdiv);
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
struct platform_device *dsi_get_dsidev_from_id(int module);
#else
static inline int dsi_runtime_get(struct platform_device *dsidev)
{
return 0;
}
static inline void dsi_runtime_put(struct platform_device *dsidev)
{
}
static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
{
WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
return 0;
}
static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
{
WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
return 0;
}
static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo)
{
WARN("%s: DSI not compiled in\n", __func__);
return -ENODEV;
}
static inline int dsi_pll_init(struct platform_device *dsidev,
bool enable_hsclk, bool enable_hsdiv)
{
WARN("%s: DSI not compiled in\n", __func__);
return -ENODEV;
}
static inline void dsi_pll_uninit(struct platform_device *dsidev,
bool disconnect_lanes)
{
}
static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
{
}
static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
{
}
static inline struct platform_device *dsi_get_dsidev_from_id(int module)
{
return NULL;
}
static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
{
return 0;
}
static inline bool dsi_hsdiv_calc(struct platform_device *dsidev,
unsigned long pll, unsigned long out_min,
dsi_hsdiv_calc_func func, void *data)
{
return false;
}
static inline bool dsi_pll_calc(struct platform_device *dsidev,
unsigned long clkin,
unsigned long pll_min, unsigned long pll_max,
dsi_pll_calc_func func, void *data)
{
return false;
}
#endif
/* DPI */
int dpi_init_platform_driver(void) __init;
void dpi_uninit_platform_driver(void) __exit;
#ifdef CONFIG_OMAP2_DSS_DPI
int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init;
void dpi_uninit_port(void) __exit;
void dpi_uninit_port(struct device_node *port) __exit;
#else
static inline int __init dpi_init_port(struct platform_device *pdev,
struct device_node *port)
{
return 0;
}
static inline void __exit dpi_uninit_port(struct device_node *port)
{
}
#endif
/* DISPC */
int dispc_init_platform_driver(void) __init;
@ -438,4 +422,29 @@ static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
}
#endif
/* PLL */
typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint,
unsigned long clkdco, void *data);
typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc,
void *data);
int dss_pll_register(struct dss_pll *pll);
void dss_pll_unregister(struct dss_pll *pll);
struct dss_pll *dss_pll_find(const char *name);
int dss_pll_enable(struct dss_pll *pll);
void dss_pll_disable(struct dss_pll *pll);
int dss_pll_set_config(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
unsigned long out_min, unsigned long out_max,
dss_hsdiv_calc_func func, void *data);
bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
unsigned long pll_min, unsigned long pll_max,
dss_pll_calc_func func, void *data);
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);
#endif

View file

@ -72,10 +72,6 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 9, 0 },
[FEAT_REG_VERTICALACCU] = { 25, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
[FEAT_REG_DSIPLL_REGN] = { 0, 0 },
[FEAT_REG_DSIPLL_REGM] = { 0, 0 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 },
};
static const struct dss_reg_field omap3_dss_reg_fields[] = {
@ -87,10 +83,6 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 9, 0 },
[FEAT_REG_VERTICALACCU] = { 25, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
[FEAT_REG_DSIPLL_REGN] = { 7, 1 },
[FEAT_REG_DSIPLL_REGM] = { 18, 8 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 },
};
static const struct dss_reg_field am43xx_dss_reg_fields[] = {
@ -113,10 +105,6 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
[FEAT_REG_VERTICALACCU] = { 26, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 },
[FEAT_REG_DSIPLL_REGN] = { 8, 1 },
[FEAT_REG_DSIPLL_REGM] = { 20, 9 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
static const struct dss_reg_field omap5_dss_reg_fields[] = {
@ -128,10 +116,6 @@ static const struct dss_reg_field omap5_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
[FEAT_REG_VERTICALACCU] = { 26, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
[FEAT_REG_DSIPLL_REGN] = { 8, 1 },
[FEAT_REG_DSIPLL_REGM] = { 20, 9 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
static const enum omap_display_type omap2_dss_supported_displays[] = {
@ -437,12 +421,6 @@ static const char * const omap5_dss_clk_source_names[] = {
static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, 0 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, 0 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 },
[FEAT_PARAM_DSIPLL_FINT] = { 0, 0 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 },
[FEAT_PARAM_DOWNSCALE] = { 1, 2 },
/*
* Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
@ -454,11 +432,6 @@ static const struct dss_param_range omap2_dss_param_range[] = {
static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
[FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
@ -475,11 +448,6 @@ static const struct dss_param_range am43xx_dss_param_range[] = {
static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
@ -489,11 +457,6 @@ static const struct dss_param_range omap4_dss_param_range[] = {
static const struct dss_param_range omap5_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
@ -517,7 +480,6 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
FEAT_LINEBUFFERSPLIT,
FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF,
FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_VENC_REQUIRES_TV_DAC_CLK,
FEAT_CPR,
@ -537,7 +499,6 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = {
FEAT_LINEBUFFERSPLIT,
FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF,
FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_VENC_REQUIRES_TV_DAC_CLK,
FEAT_CPR,
@ -572,7 +533,6 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = {
FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF,
FEAT_DSI_PLL_PWR_BUG,
FEAT_DSI_PLL_FREQSEL,
FEAT_CPR,
FEAT_PRELOAD,
FEAT_FIR_COEF_V,
@ -654,8 +614,6 @@ static const enum dss_feat_id omap5_dss_feat_list[] = {
FEAT_ALPHA_FREE_ZORDER,
FEAT_FIFO_MERGE,
FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
FEAT_DSI_PLL_REFSEL,
FEAT_DSI_PHY_DCC,
FEAT_MFLAG,
};

View file

@ -41,7 +41,6 @@ enum dss_feat_id {
FEAT_LCD_CLK_SRC,
/* DSI-PLL power command 0x3 is not working */
FEAT_DSI_PLL_PWR_BUG,
FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_DCS_CMD_CONFIG_VC,
FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_REVERSE_TXCLKESC,
@ -61,8 +60,6 @@ enum dss_feat_id {
/* An unknown HW bug causing the normal FIFO thresholds not to work */
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
FEAT_DSI_PLL_REFSEL,
FEAT_DSI_PHY_DCC,
FEAT_MFLAG,
};
@ -77,20 +74,11 @@ enum dss_feat_reg_field {
FEAT_REG_HORIZONTALACCU,
FEAT_REG_VERTICALACCU,
FEAT_REG_DISPC_CLK_SWITCH,
FEAT_REG_DSIPLL_REGN,
FEAT_REG_DSIPLL_REGM,
FEAT_REG_DSIPLL_REGM_DISPC,
FEAT_REG_DSIPLL_REGM_DSI,
};
enum dss_range_param {
FEAT_PARAM_DSS_FCK,
FEAT_PARAM_DSS_PCD,
FEAT_PARAM_DSIPLL_REGN,
FEAT_PARAM_DSIPLL_REGM,
FEAT_PARAM_DSIPLL_REGM_DISPC,
FEAT_PARAM_DSIPLL_REGM_DSI,
FEAT_PARAM_DSIPLL_FINT,
FEAT_PARAM_DSIPLL_LPDIV,
FEAT_PARAM_DSI_FCK,
FEAT_PARAM_DOWNSCALE,

View file

@ -101,13 +101,6 @@ enum hdmi_core_hdmi_dvi {
HDMI_HDMI = 1
};
enum hdmi_clk_refsel {
HDMI_REFSEL_PCLK = 0,
HDMI_REFSEL_REF1 = 1,
HDMI_REFSEL_REF2 = 2,
HDMI_REFSEL_SYSCLK = 3
};
enum hdmi_packing_mode {
HDMI_PACK_10b_RGB_YUV444 = 0,
HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
@ -160,7 +153,8 @@ enum hdmi_audio_blk_strt_end_sig {
enum hdmi_core_audio_layout {
HDMI_AUDIO_LAYOUT_2CH = 0,
HDMI_AUDIO_LAYOUT_8CH = 1
HDMI_AUDIO_LAYOUT_8CH = 1,
HDMI_AUDIO_LAYOUT_6CH = 2
};
enum hdmi_core_cts_mode {
@ -191,17 +185,6 @@ struct hdmi_config {
enum hdmi_core_hdmi_dvi hdmi_dvi_mode;
};
/* HDMI PLL structure */
struct hdmi_pll_info {
u16 regn;
u16 regm;
u32 regmf;
u16 regm2;
u16 regsd;
u16 dcofreq;
enum hdmi_clk_refsel refsel;
};
struct hdmi_audio_format {
enum hdmi_stereo_channels stereo_channels;
u8 active_chnnls_msk;
@ -249,12 +232,15 @@ struct hdmi_core_audio_config {
struct hdmi_wp_data {
void __iomem *base;
phys_addr_t phys_base;
};
struct hdmi_pll_data {
struct dss_pll pll;
void __iomem *base;
struct hdmi_pll_info info;
struct hdmi_wp_data *wp;
};
struct hdmi_phy_data {
@ -316,16 +302,19 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
struct omap_video_timings *timings, struct hdmi_config *param);
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);
/* HDMI PLL funcs */
int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy);
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
void hdmi_pll_compute(struct hdmi_pll_data *pll,
unsigned long target_tmds, struct dss_pll_clock_info *pi);
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
struct hdmi_wp_data *wp);
void hdmi_pll_uninit(struct hdmi_pll_data *hpll);
/* HDMI PHY funcs */
int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg);
int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
unsigned long lfbitclk);
void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
@ -334,7 +323,7 @@ int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
struct hdmi_phy_data *phy);
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
/* Audio funcs */
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
@ -342,9 +331,33 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
struct hdmi_audio_format *aud_fmt);
void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
struct hdmi_audio_dma *aud_dma);
static inline bool hdmi_mode_has_audio(int mode)
static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg)
{
return mode == HDMI_HDMI ? true : false;
return cfg->hdmi_dvi_mode == HDMI_HDMI ? true : false;
}
#endif
/* HDMI DRV data */
struct omap_hdmi {
struct mutex lock;
struct platform_device *pdev;
struct hdmi_wp_data wp;
struct hdmi_pll_data pll;
struct hdmi_phy_data phy;
struct hdmi_core_data core;
struct hdmi_config cfg;
struct regulator *vdda_reg;
bool core_enabled;
bool display_enabled;
struct omap_dss_device output;
struct platform_device *audio_pdev;
void (*audio_abort_cb)(struct device *dev);
int wp_idlemode;
};
#endif

View file

@ -33,29 +33,14 @@
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
#include <sound/omap-hdmi-audio.h>
#include "hdmi4_core.h"
#include "dss.h"
#include "dss_features.h"
#include "hdmi.h"
static struct {
struct mutex lock;
struct platform_device *pdev;
struct hdmi_wp_data wp;
struct hdmi_pll_data pll;
struct hdmi_phy_data phy;
struct hdmi_core_data core;
struct hdmi_config cfg;
struct clk *sys_clk;
struct regulator *vdda_hdmi_dac_reg;
bool core_enabled;
struct omap_dss_device output;
} hdmi;
static struct omap_hdmi hdmi;
static int hdmi_runtime_get(void)
{
@ -117,7 +102,7 @@ static int hdmi_init_regulator(void)
int r;
struct regulator *reg;
if (hdmi.vdda_hdmi_dac_reg != NULL)
if (hdmi.vdda_reg != NULL)
return 0;
reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
@ -137,7 +122,7 @@ static int hdmi_init_regulator(void)
}
}
hdmi.vdda_hdmi_dac_reg = reg;
hdmi.vdda_reg = reg;
return 0;
}
@ -146,7 +131,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
{
int r;
r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
r = regulator_enable(hdmi.vdda_reg);
if (r)
return r;
@ -162,7 +147,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
return 0;
err_runtime_get:
regulator_disable(hdmi.vdda_hdmi_dac_reg);
regulator_disable(hdmi.vdda_reg);
return r;
}
@ -172,7 +157,7 @@ static void hdmi_power_off_core(struct omap_dss_device *dssdev)
hdmi.core_enabled = false;
hdmi_runtime_put();
regulator_disable(hdmi.vdda_hdmi_dac_reg);
regulator_disable(hdmi.vdda_reg);
}
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
@ -180,8 +165,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
int r;
struct omap_video_timings *p;
struct omap_overlay_manager *mgr = hdmi.output.manager;
unsigned long phy;
struct hdmi_wp_data *wp = &hdmi.wp;
struct dss_pll_clock_info hdmi_cinfo = { 0 };
r = hdmi_power_on_core(dssdev);
if (r)
@ -195,19 +180,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
/* the functions below use kHz pixel clock. TODO: change to Hz */
phy = p->pixelclock / 1000;
hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
/* config the PLL and PHY hdmi_set_pll_pwrfirst */
r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
r = dss_pll_enable(&hdmi.pll.pll);
if (r) {
DSSDBG("Failed to lock PLL\n");
DSSERR("Failed to enable PLL\n");
goto err_pll_enable;
}
r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg);
r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
if (r) {
DSSERR("Failed to configure PLL\n");
goto err_pll_cfg;
}
r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
hdmi_cinfo.clkout[0]);
if (r) {
DSSDBG("Failed to configure PHY\n");
goto err_phy_cfg;
@ -244,7 +232,8 @@ err_vid_enable:
err_phy_cfg:
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr:
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
err_pll_cfg:
dss_pll_disable(&hdmi.pll.pll);
err_pll_enable:
hdmi_power_off_core(dssdev);
return -EIO;
@ -262,7 +251,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
dss_pll_disable(&hdmi.pll.pll);
hdmi_power_off_core(dssdev);
}
@ -352,6 +341,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
hdmi.display_enabled = true;
mutex_unlock(&hdmi.lock);
return 0;
@ -366,8 +357,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock);
if (hdmi.audio_pdev && hdmi.audio_abort_cb)
hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
hdmi_power_off_full(dssdev);
hdmi.display_enabled = false;
mutex_unlock(&hdmi.lock);
}
@ -404,21 +400,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock);
}
static int hdmi_get_clocks(struct platform_device *pdev)
{
struct clk *clk;
clk = devm_clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n");
return PTR_ERR(clk);
}
hdmi.sys_clk = clk;
return 0;
}
static int hdmi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
@ -484,112 +465,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
return r;
}
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
{
int r;
mutex_lock(&hdmi.lock);
if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
r = -EPERM;
goto err;
}
r = hdmi_wp_audio_enable(&hdmi.wp, true);
if (r)
goto err;
mutex_unlock(&hdmi.lock);
return 0;
err:
mutex_unlock(&hdmi.lock);
return r;
}
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
{
hdmi_wp_audio_enable(&hdmi.wp, false);
}
static int hdmi_audio_start(struct omap_dss_device *dssdev)
{
return hdmi4_audio_start(&hdmi.core, &hdmi.wp);
}
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
{
hdmi4_audio_stop(&hdmi.core, &hdmi.wp);
}
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
{
bool r;
mutex_lock(&hdmi.lock);
r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
mutex_unlock(&hdmi.lock);
return r;
}
static int hdmi_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
int r;
u32 pclk = hdmi.cfg.timings.pixelclock;
mutex_lock(&hdmi.lock);
if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
r = -EPERM;
goto err;
}
r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
if (r)
goto err;
mutex_unlock(&hdmi.lock);
return 0;
err:
mutex_unlock(&hdmi.lock);
return r;
}
#else
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
{
return -EPERM;
}
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
{
}
static int hdmi_audio_start(struct omap_dss_device *dssdev)
{
return -EPERM;
}
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
{
}
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
{
return false;
}
static int hdmi_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
return -EPERM;
}
#endif
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi)
{
@ -618,13 +493,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
.read_edid = hdmi_read_edid,
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
.audio_enable = hdmi_audio_enable,
.audio_disable = hdmi_audio_disable,
.audio_start = hdmi_audio_start,
.audio_stop = hdmi_audio_stop,
.audio_supported = hdmi_audio_supported,
.audio_config = hdmi_audio_config,
};
static void hdmi_init_output(struct platform_device *pdev)
@ -642,7 +510,7 @@ static void hdmi_init_output(struct platform_device *pdev)
omapdss_register_output(out);
}
static void __exit hdmi_uninit_output(struct platform_device *pdev)
static void hdmi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_device *out = &hdmi.output;
@ -671,6 +539,112 @@ err:
return r;
}
/* Audio callbacks */
static int hdmi_audio_startup(struct device *dev,
void (*abort_cb)(struct device *dev))
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&hd->lock);
if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
ret = -EPERM;
goto out;
}
hd->audio_abort_cb = abort_cb;
out:
mutex_unlock(&hd->lock);
return ret;
}
static int hdmi_audio_shutdown(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
mutex_lock(&hd->lock);
hd->audio_abort_cb = NULL;
mutex_unlock(&hd->lock);
return 0;
}
static int hdmi_audio_start(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
WARN_ON(!hd->display_enabled);
hdmi_wp_audio_enable(&hd->wp, true);
hdmi4_audio_start(&hd->core, &hd->wp);
return 0;
}
static void hdmi_audio_stop(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
WARN_ON(!hd->display_enabled);
hdmi4_audio_stop(&hd->core, &hd->wp);
hdmi_wp_audio_enable(&hd->wp, false);
}
static int hdmi_audio_config(struct device *dev,
struct omap_dss_audio *dss_audio)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
int ret;
mutex_lock(&hd->lock);
if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
ret = -EPERM;
goto out;
}
ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
hd->cfg.timings.pixelclock);
out:
mutex_unlock(&hd->lock);
return ret;
}
static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
.audio_startup = hdmi_audio_startup,
.audio_shutdown = hdmi_audio_shutdown,
.audio_start = hdmi_audio_start,
.audio_stop = hdmi_audio_stop,
.audio_config = hdmi_audio_config,
};
static int hdmi_audio_register(struct device *dev)
{
struct omap_hdmi_audio_pdata pdata = {
.dev = dev,
.dss_version = omapdss_get_version(),
.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
.ops = &hdmi_audio_ops,
};
hdmi.audio_pdev = platform_device_register_data(
dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
&pdata, sizeof(pdata));
if (IS_ERR(hdmi.audio_pdev))
return PTR_ERR(hdmi.audio_pdev);
return 0;
}
/* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev)
{
@ -678,6 +652,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
int irq;
hdmi.pdev = pdev;
dev_set_drvdata(&pdev->dev, &hdmi);
mutex_init(&hdmi.lock);
@ -691,28 +666,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
if (r)
return r;
r = hdmi_pll_init(pdev, &hdmi.pll);
r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
if (r)
return r;
r = hdmi_phy_init(pdev, &hdmi.phy);
if (r)
return r;
goto err;
r = hdmi4_core_init(pdev, &hdmi.core);
if (r)
return r;
r = hdmi_get_clocks(pdev);
if (r) {
DSSERR("can't get clocks\n");
return r;
}
goto err;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
DSSERR("platform_get_irq failed\n");
return -ENODEV;
r = -ENODEV;
goto err;
}
r = devm_request_threaded_irq(&pdev->dev, irq,
@ -720,22 +690,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
if (r) {
DSSERR("HDMI IRQ request failed\n");
return r;
goto err;
}
pm_runtime_enable(&pdev->dev);
hdmi_init_output(pdev);
r = hdmi_audio_register(&pdev->dev);
if (r) {
DSSERR("Registering HDMI audio failed\n");
hdmi_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
return r;
}
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
return 0;
err:
hdmi_pll_uninit(&hdmi.pll);
return r;
}
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{
if (hdmi.audio_pdev)
platform_device_unregister(hdmi.audio_pdev);
hdmi_uninit_output(pdev);
hdmi_pll_uninit(&hdmi.pll);
pm_runtime_disable(&pdev->dev);
return 0;
@ -743,8 +729,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
static int hdmi_runtime_suspend(struct device *dev)
{
clk_disable_unprepare(hdmi.sys_clk);
dispc_runtime_put();
return 0;
@ -758,8 +742,6 @@ static int hdmi_runtime_resume(struct device *dev)
if (r < 0)
return r;
clk_prepare_enable(hdmi.sys_clk);
return 0;
}

View file

@ -31,10 +31,8 @@
#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
#include <sound/asound.h>
#include <sound/asoundef.h>
#endif
#include "hdmi4_core.h"
#include "dss_features.h"
@ -530,7 +528,6 @@ void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s)
DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID);
}
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
static void hdmi_core_audio_config(struct hdmi_core_data *core,
struct hdmi_core_audio_config *cfg)
{
@ -877,17 +874,6 @@ void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
hdmi_wp_audio_core_req_enable(wp, false);
}
int hdmi4_audio_get_dma_port(u32 *offset, u32 *size)
{
if (!offset || !size)
return -EINVAL;
*offset = HDMI_WP_AUDIO_DATA;
*size = 4;
return 0;
}
#endif
int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
{
struct resource *res;

View file

@ -266,12 +266,8 @@ void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct omap_dss_audio *audio, u32 pclk);
int hdmi4_audio_get_dma_port(u32 *offset, u32 *size);
#endif
#endif

View file

@ -38,29 +38,13 @@
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
#include <sound/omap-hdmi-audio.h>
#include "hdmi5_core.h"
#include "dss.h"
#include "dss_features.h"
static struct {
struct mutex lock;
struct platform_device *pdev;
struct hdmi_wp_data wp;
struct hdmi_pll_data pll;
struct hdmi_phy_data phy;
struct hdmi_core_data core;
struct hdmi_config cfg;
struct clk *sys_clk;
struct regulator *vdda_reg;
bool core_enabled;
struct omap_dss_device output;
} hdmi;
static struct omap_hdmi hdmi;
static int hdmi_runtime_get(void)
{
@ -198,7 +182,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
int r;
struct omap_video_timings *p;
struct omap_overlay_manager *mgr = hdmi.output.manager;
unsigned long phy;
struct dss_pll_clock_info hdmi_cinfo = { 0 };
r = hdmi_power_on_core(dssdev);
if (r)
@ -208,24 +192,27 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
/* the functions below use kHz pixel clock. TODO: change to Hz */
phy = p->pixelclock / 1000;
hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
/* disable and clear irqs */
hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
hdmi_wp_set_irqstatus(&hdmi.wp,
hdmi_wp_get_irqstatus(&hdmi.wp));
/* config the PLL and PHY hdmi_set_pll_pwrfirst */
r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
r = dss_pll_enable(&hdmi.pll.pll);
if (r) {
DSSDBG("Failed to lock PLL\n");
DSSERR("Failed to enable PLL\n");
goto err_pll_enable;
}
r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg);
r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
if (r) {
DSSERR("Failed to configure PLL\n");
goto err_pll_cfg;
}
r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
hdmi_cinfo.clkout[0]);
if (r) {
DSSDBG("Failed to start PHY\n");
goto err_phy_cfg;
@ -262,7 +249,8 @@ err_vid_enable:
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr:
err_phy_cfg:
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
err_pll_cfg:
dss_pll_disable(&hdmi.pll.pll);
err_pll_enable:
hdmi_power_off_core(dssdev);
return -EIO;
@ -280,7 +268,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
dss_pll_disable(&hdmi.pll.pll);
hdmi_power_off_core(dssdev);
}
@ -290,6 +278,10 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
{
struct omap_dss_device *out = &hdmi.output;
/* TODO: proper interlace support */
if (timings->interlace)
return -EINVAL;
if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
return -EINVAL;
@ -377,6 +369,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
hdmi.display_enabled = true;
mutex_unlock(&hdmi.lock);
return 0;
@ -391,8 +385,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock);
if (hdmi.audio_pdev && hdmi.audio_abort_cb)
hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
hdmi_power_off_full(dssdev);
hdmi.display_enabled = false;
mutex_unlock(&hdmi.lock);
}
@ -429,21 +428,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock);
}
static int hdmi_get_clocks(struct platform_device *pdev)
{
struct clk *clk;
clk = devm_clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n");
return PTR_ERR(clk);
}
hdmi.sys_clk = clk;
return 0;
}
static int hdmi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
@ -509,112 +493,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
return r;
}
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
{
int r;
mutex_lock(&hdmi.lock);
if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
r = -EPERM;
goto err;
}
r = hdmi_wp_audio_enable(&hdmi.wp, true);
if (r)
goto err;
mutex_unlock(&hdmi.lock);
return 0;
err:
mutex_unlock(&hdmi.lock);
return r;
}
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
{
hdmi_wp_audio_enable(&hdmi.wp, false);
}
static int hdmi_audio_start(struct omap_dss_device *dssdev)
{
return hdmi_wp_audio_core_req_enable(&hdmi.wp, true);
}
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
{
hdmi_wp_audio_core_req_enable(&hdmi.wp, false);
}
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
{
bool r;
mutex_lock(&hdmi.lock);
r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
mutex_unlock(&hdmi.lock);
return r;
}
static int hdmi_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
int r;
u32 pclk = hdmi.cfg.timings.pixelclock;
mutex_lock(&hdmi.lock);
if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
r = -EPERM;
goto err;
}
r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
if (r)
goto err;
mutex_unlock(&hdmi.lock);
return 0;
err:
mutex_unlock(&hdmi.lock);
return r;
}
#else
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
{
return -EPERM;
}
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
{
}
static int hdmi_audio_start(struct omap_dss_device *dssdev)
{
return -EPERM;
}
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
{
}
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
{
return false;
}
static int hdmi_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
return -EPERM;
}
#endif
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi)
{
@ -643,13 +521,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
.read_edid = hdmi_read_edid,
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
.audio_enable = hdmi_audio_enable,
.audio_disable = hdmi_audio_disable,
.audio_start = hdmi_audio_start,
.audio_stop = hdmi_audio_stop,
.audio_supported = hdmi_audio_supported,
.audio_config = hdmi_audio_config,
};
static void hdmi_init_output(struct platform_device *pdev)
@ -667,7 +538,7 @@ static void hdmi_init_output(struct platform_device *pdev)
omapdss_register_output(out);
}
static void __exit hdmi_uninit_output(struct platform_device *pdev)
static void hdmi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_device *out = &hdmi.output;
@ -696,6 +567,119 @@ err:
return r;
}
/* Audio callbacks */
static int hdmi_audio_startup(struct device *dev,
void (*abort_cb)(struct device *dev))
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&hd->lock);
if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
ret = -EPERM;
goto out;
}
hd->audio_abort_cb = abort_cb;
out:
mutex_unlock(&hd->lock);
return ret;
}
static int hdmi_audio_shutdown(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
mutex_lock(&hd->lock);
hd->audio_abort_cb = NULL;
mutex_unlock(&hd->lock);
return 0;
}
static int hdmi_audio_start(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
WARN_ON(!hd->display_enabled);
/* No-idle while playing audio, store the old value */
hd->wp_idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
hdmi_wp_audio_enable(&hd->wp, true);
hdmi_wp_audio_core_req_enable(&hd->wp, true);
return 0;
}
static void hdmi_audio_stop(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
WARN_ON(!hd->display_enabled);
hdmi_wp_audio_core_req_enable(&hd->wp, false);
hdmi_wp_audio_enable(&hd->wp, false);
/* Playback stopped, restore original idlemode */
REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
}
static int hdmi_audio_config(struct device *dev,
struct omap_dss_audio *dss_audio)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
int ret;
mutex_lock(&hd->lock);
if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
ret = -EPERM;
goto out;
}
ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
hd->cfg.timings.pixelclock);
out:
mutex_unlock(&hd->lock);
return ret;
}
static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
.audio_startup = hdmi_audio_startup,
.audio_shutdown = hdmi_audio_shutdown,
.audio_start = hdmi_audio_start,
.audio_stop = hdmi_audio_stop,
.audio_config = hdmi_audio_config,
};
static int hdmi_audio_register(struct device *dev)
{
struct omap_hdmi_audio_pdata pdata = {
.dev = dev,
.dss_version = omapdss_get_version(),
.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
.ops = &hdmi_audio_ops,
};
hdmi.audio_pdev = platform_device_register_data(
dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
&pdata, sizeof(pdata));
if (IS_ERR(hdmi.audio_pdev))
return PTR_ERR(hdmi.audio_pdev);
return 0;
}
/* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev)
{
@ -703,6 +687,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
int irq;
hdmi.pdev = pdev;
dev_set_drvdata(&pdev->dev, &hdmi);
mutex_init(&hdmi.lock);
@ -716,28 +701,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
if (r)
return r;
r = hdmi_pll_init(pdev, &hdmi.pll);
r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
if (r)
return r;
r = hdmi_phy_init(pdev, &hdmi.phy);
if (r)
return r;
goto err;
r = hdmi5_core_init(pdev, &hdmi.core);
if (r)
return r;
r = hdmi_get_clocks(pdev);
if (r) {
DSSERR("can't get clocks\n");
return r;
}
goto err;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
DSSERR("platform_get_irq failed\n");
return -ENODEV;
r = -ENODEV;
goto err;
}
r = devm_request_threaded_irq(&pdev->dev, irq,
@ -745,22 +725,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
if (r) {
DSSERR("HDMI IRQ request failed\n");
return r;
goto err;
}
pm_runtime_enable(&pdev->dev);
hdmi_init_output(pdev);
r = hdmi_audio_register(&pdev->dev);
if (r) {
DSSERR("Registering HDMI audio failed %d\n", r);
hdmi_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
return r;
}
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
return 0;
err:
hdmi_pll_uninit(&hdmi.pll);
return r;
}
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{
if (hdmi.audio_pdev)
platform_device_unregister(hdmi.audio_pdev);
hdmi_uninit_output(pdev);
hdmi_pll_uninit(&hdmi.pll);
pm_runtime_disable(&pdev->dev);
return 0;
@ -768,8 +764,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
static int hdmi_runtime_suspend(struct device *dev)
{
clk_disable_unprepare(hdmi.sys_clk);
dispc_runtime_put();
return 0;
@ -783,8 +777,6 @@ static int hdmi_runtime_resume(struct device *dev)
if (r < 0)
return r;
clk_prepare_enable(hdmi.sys_clk);
return 0;
}

View file

@ -30,10 +30,8 @@
#include <linux/string.h>
#include <linux/seq_file.h>
#include <drm/drm_edid.h>
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
#include <sound/asound.h>
#include <sound/asoundef.h>
#endif
#include "hdmi5_core.h"
@ -644,9 +642,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
hdmi_core_enable_interrupts(core);
}
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
static void hdmi5_core_audio_config(struct hdmi_core_data *core,
struct hdmi_core_audio_config *cfg)
{
@ -721,7 +716,7 @@ static void hdmi5_core_audio_config(struct hdmi_core_data *core,
/* Source number */
val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE;
REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 4);
REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 0);
/* Channel number right 0 */
REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0);
@ -879,6 +874,9 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
/* only LPCM atm */
audio_format.type = HDMI_AUDIO_TYPE_LPCM;
/* only allowed option */
audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
/* disable start/stop signals of IEC 60958 blocks */
audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
@ -894,7 +892,6 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
return 0;
}
#endif
int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
{

View file

@ -299,8 +299,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct hdmi_config *cfg);
int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct omap_dss_audio *audio, u32 pclk);
#endif
#endif

View file

@ -48,7 +48,6 @@ int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
return 0;
}
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
{
u32 deep_color;
@ -147,4 +146,3 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
return 0;
}
#endif

View file

@ -20,9 +20,7 @@
struct hdmi_phy_features {
bool bist_ctrl;
bool calc_freqout;
bool ldo_voltage;
unsigned long dcofreq_min;
unsigned long max_phy;
};
@ -132,7 +130,8 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
}
int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
unsigned long lfbitclk)
{
u8 freqout;
@ -149,20 +148,16 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
if (phy_feat->bist_ctrl)
REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
if (phy_feat->calc_freqout) {
/* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */
u32 dco_min = phy_feat->dcofreq_min / 10;
u32 pclk = cfg->timings.pixelclock;
if (pclk < dco_min)
freqout = 0;
else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy))
freqout = 1;
else
freqout = 2;
} else {
/*
* If the hfbitclk != lfbitclk, it means the lfbitclk was configured
* to be used for TMDS.
*/
if (hfbitclk != lfbitclk)
freqout = 0;
else if (hfbitclk / 10 < phy_feat->max_phy)
freqout = 1;
}
else
freqout = 2;
/*
* Write to phy address 0 to configure the clock
@ -184,17 +179,13 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
static const struct hdmi_phy_features omap44xx_phy_feats = {
.bist_ctrl = false,
.calc_freqout = false,
.ldo_voltage = true,
.dcofreq_min = 500000000,
.max_phy = 185675000,
};
static const struct hdmi_phy_features omap54xx_phy_feats = {
.bist_ctrl = true,
.calc_freqout = true,
.ldo_voltage = false,
.dcofreq_min = 750000000,
.max_phy = 186000000,
};

View file

@ -15,26 +15,13 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <video/omapdss.h>
#include "dss.h"
#include "hdmi.h"
#define HDMI_DEFAULT_REGN 16
#define HDMI_DEFAULT_REGM2 1
struct hdmi_pll_features {
bool sys_reset;
/* this is a hack, need to replace it with a better computation of M2 */
bool bound_dcofreq;
unsigned long fint_min, fint_max;
u16 regm_max;
unsigned long dcofreq_low_min, dcofreq_low_max;
unsigned long dcofreq_high_min, dcofreq_high_max;
};
static const struct hdmi_pll_features *pll_feat;
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
{
#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
@ -51,228 +38,189 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
DUMPPLL(PLLCTRL_CFG4);
}
void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
void hdmi_pll_compute(struct hdmi_pll_data *pll,
unsigned long target_tmds, struct dss_pll_clock_info *pi)
{
struct hdmi_pll_info *pi = &pll->info;
unsigned long refclk;
u32 mf;
unsigned long fint, clkdco, clkout;
unsigned long target_bitclk, target_clkdco;
unsigned long min_dco;
unsigned n, m, mf, m2, sd;
unsigned long clkin;
const struct dss_pll_hw *hw = pll->pll.hw;
/* use our funky units */
clkin /= 10000;
clkin = clk_get_rate(pll->pll.clkin);
/*
* Input clock is predivided by N + 1
* out put of which is reference clk
*/
DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
pi->regn = HDMI_DEFAULT_REGN;
target_bitclk = target_tmds * 10;
refclk = clkin / pi->regn;
/* Fint */
n = DIV_ROUND_UP(clkin, hw->fint_max);
fint = clkin / n;
/* temorary hack to make sure DCO freq isn't calculated too low */
if (pll_feat->bound_dcofreq && phy <= 65000)
pi->regm2 = 3;
/* adjust m2 so that the clkdco will be high enough */
min_dco = roundup(hw->clkdco_min, fint);
m2 = DIV_ROUND_UP(min_dco, target_bitclk);
if (m2 == 0)
m2 = 1;
target_clkdco = target_bitclk * m2;
m = target_clkdco / fint;
clkdco = fint * m;
/* adjust clkdco with fractional mf */
if (WARN_ON(target_clkdco - clkdco > fint))
mf = 0;
else
pi->regm2 = HDMI_DEFAULT_REGM2;
mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
/*
* multiplier is pixel_clk/ref_clk
* Multiplying by 100 to avoid fractional part removal
*/
pi->regm = phy * pi->regm2 / refclk;
if (mf > 0)
clkdco += (u32)div_u64((u64)mf * fint, 262144);
/*
* fractional multiplier is remainder of the difference between
* multiplier and actual phy(required pixel clock thus should be
* multiplied by 2^18(262144) divided by the reference clock
*/
mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
pi->regmf = pi->regm2 * mf / refclk;
clkout = clkdco / m2;
/*
* Dcofreq should be set to 1 if required pixel clock
* is greater than 1000MHz
*/
pi->dcofreq = phy > 1000 * 100;
pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
/* sigma-delta */
sd = DIV_ROUND_UP(fint * m, 250000000);
/* Set the reference clock to sysclk reference */
pi->refsel = HDMI_REFSEL_SYSCLK;
DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
n, m, mf, m2, sd);
DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
pi->n = n;
pi->m = m;
pi->mf = mf;
pi->mX[0] = m2;
pi->sd = sd;
pi->fint = fint;
pi->clkdco = clkdco;
pi->clkout[0] = clkout;
}
static int hdmi_pll_config(struct hdmi_pll_data *pll)
{
u32 r;
struct hdmi_pll_info *fmt = &pll->info;
/* PLL start always use manual mode */
REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */
hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);
r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);
r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
if (fmt->dcofreq)
r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
else
r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
r = hdmi_read_reg(pll->base, PLLCTRL_CFG4);
r = FLD_MOD(r, fmt->regm2, 24, 18);
r = FLD_MOD(r, fmt->regmf, 17, 0);
hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
/* go now */
REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
/* wait for bit change */
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
0, 0, 0) != 0) {
DSSERR("PLL GO bit not clearing\n");
return -ETIMEDOUT;
}
/* Wait till the lock bit is set in PLL status */
if (hdmi_wait_for_bit_change(pll->base,
PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
DSSERR("cannot lock PLL\n");
DSSERR("CFG1 0x%x\n",
hdmi_read_reg(pll->base, PLLCTRL_CFG1));
DSSERR("CFG2 0x%x\n",
hdmi_read_reg(pll->base, PLLCTRL_CFG2));
DSSERR("CFG4 0x%x\n",
hdmi_read_reg(pll->base, PLLCTRL_CFG4));
return -ETIMEDOUT;
}
DSSDBG("PLL locked!\n");
return 0;
}
static int hdmi_pll_reset(struct hdmi_pll_data *pll)
{
/* SYSRESET controlled by power FSM */
REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3);
/* READ 0x0 reset is in progress */
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
!= 1) {
DSSERR("Failed to sysreset PLL\n");
return -ETIMEDOUT;
}
return 0;
}
int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
static int hdmi_pll_enable(struct dss_pll *dsspll)
{
struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
struct hdmi_wp_data *wp = pll->wp;
u16 r = 0;
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
if (r)
return r;
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
if (r)
return r;
r = hdmi_pll_reset(pll);
if (r)
return r;
r = hdmi_pll_config(pll);
if (r)
return r;
return 0;
}
void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
static void hdmi_pll_disable(struct dss_pll *dsspll)
{
struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
struct hdmi_wp_data *wp = pll->wp;
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
}
static const struct hdmi_pll_features omap44xx_pll_feats = {
.sys_reset = false,
.bound_dcofreq = false,
.fint_min = 500000,
.fint_max = 2500000,
.regm_max = 4095,
.dcofreq_low_min = 500000000,
.dcofreq_low_max = 1000000000,
.dcofreq_high_min = 1000000000,
.dcofreq_high_max = 2000000000,
static const struct dss_pll_ops dsi_pll_ops = {
.enable = hdmi_pll_enable,
.disable = hdmi_pll_disable,
.set_config = dss_pll_write_config_type_b,
};
static const struct hdmi_pll_features omap54xx_pll_feats = {
.sys_reset = true,
.bound_dcofreq = true,
.fint_min = 620000,
.fint_max = 2500000,
.regm_max = 2046,
.dcofreq_low_min = 750000000,
.dcofreq_low_max = 1500000000,
.dcofreq_high_min = 1250000000,
.dcofreq_high_max = 2500000000UL,
static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
.n_max = 255,
.m_min = 20,
.m_max = 4095,
.mX_max = 127,
.fint_min = 500000,
.fint_max = 2500000,
.clkdco_max = 1800000000,
.clkdco_min = 500000000,
.clkdco_low = 1000000000,
.clkdco_max = 2000000000,
.n_msb = 8,
.n_lsb = 1,
.m_msb = 20,
.m_lsb = 9,
.mX_msb[0] = 24,
.mX_lsb[0] = 18,
.has_selfreqdco = true,
};
static int hdmi_pll_init_features(struct platform_device *pdev)
static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
.n_max = 255,
.m_min = 20,
.m_max = 2045,
.mX_max = 127,
.fint_min = 620000,
.fint_max = 2500000,
.clkdco_max = 1800000000,
.clkdco_min = 750000000,
.clkdco_low = 1500000000,
.clkdco_max = 2500000000UL,
.n_msb = 8,
.n_lsb = 1,
.m_msb = 20,
.m_lsb = 9,
.mX_msb[0] = 24,
.mX_lsb[0] = 18,
.has_selfreqdco = true,
.has_refsel = true,
};
static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll)
{
struct hdmi_pll_features *dst;
const struct hdmi_pll_features *src;
struct dss_pll *pll = &hpll->pll;
struct clk *clk;
int r;
dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
if (!dst) {
dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
return -ENOMEM;
clk = devm_clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n");
return PTR_ERR(clk);
}
pll->name = "hdmi";
pll->base = hpll->base;
pll->clkin = clk;
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
src = &omap44xx_pll_feats;
pll->hw = &dss_omap4_hdmi_pll_hw;
break;
case OMAPDSS_VER_OMAP5:
src = &omap54xx_pll_feats;
pll->hw = &dss_omap5_hdmi_pll_hw;
break;
default:
return -ENODEV;
}
memcpy(dst, src, sizeof(*dst));
pll_feat = dst;
pll->ops = &dsi_pll_ops;
r = dss_pll_register(pll);
if (r)
return r;
return 0;
}
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
struct hdmi_wp_data *wp)
{
int r;
struct resource *res;
r = hdmi_pll_init_features(pdev);
if (r)
return r;
pll->wp = wp;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
if (!res) {
@ -286,5 +234,18 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
return PTR_ERR(pll->base);
}
r = dsi_init_pll_data(pdev, pll);
if (r) {
DSSERR("failed to init HDMI PLL\n");
return r;
}
return 0;
}
void hdmi_pll_uninit(struct hdmi_pll_data *hpll)
{
struct dss_pll *pll = &hpll->pll;
dss_pll_unregister(pll);
}

View file

@ -185,7 +185,6 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
timings->interlace = param->timings.interlace;
}
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
struct hdmi_audio_format *aud_fmt)
{
@ -194,8 +193,12 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
DSSDBG("Enter hdmi_wp_audio_config_format\n");
r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
omapdss_get_version() == OMAPDSS_VER_OMAP4) {
r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
}
r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
r = FLD_MOD(r, aud_fmt->type, 4, 4);
r = FLD_MOD(r, aud_fmt->justification, 3, 3);
@ -236,7 +239,6 @@ int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
return 0;
}
#endif
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
{
@ -247,6 +249,7 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
DSSERR("can't get WP mem resource\n");
return -EINVAL;
}
wp->phys_base = res->start;
wp->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(wp->base)) {
@ -256,3 +259,8 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
return 0;
}
phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
{
return wp->phys_base + HDMI_WP_AUDIO_DATA;
}

View file

@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <video/omapdss.h>
@ -131,18 +132,30 @@ struct omap_dss_device *omap_dss_find_output(const char *name)
}
EXPORT_SYMBOL(omap_dss_find_output);
struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node)
struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port)
{
struct device_node *src_node;
struct omap_dss_device *out;
u32 reg;
src_node = dss_of_port_get_parent_device(port);
if (!src_node)
return NULL;
reg = dss_of_port_get_port_number(port);
list_for_each_entry(out, &output_list, list) {
if (out->dev->of_node == node)
if (out->dev->of_node == src_node && out->port_num == reg) {
of_node_put(src_node);
return omap_dss_get_device(out);
}
}
of_node_put(src_node);
return NULL;
}
EXPORT_SYMBOL(omap_dss_find_output_by_node);
EXPORT_SYMBOL(omap_dss_find_output_by_port_node);
struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
{

View file

@ -0,0 +1,378 @@
/*
* Copyright (C) 2014 Texas Instruments Incorporated
*
* 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "PLL"
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/regulator/consumer.h>
#include <linux/sched.h>
#include <video/omapdss.h>
#include "dss.h"
#define PLL_CONTROL 0x0000
#define PLL_STATUS 0x0004
#define PLL_GO 0x0008
#define PLL_CONFIGURATION1 0x000C
#define PLL_CONFIGURATION2 0x0010
#define PLL_CONFIGURATION3 0x0014
#define PLL_SSC_CONFIGURATION1 0x0018
#define PLL_SSC_CONFIGURATION2 0x001C
#define PLL_CONFIGURATION4 0x0020
static struct dss_pll *dss_plls[4];
int dss_pll_register(struct dss_pll *pll)
{
int i;
for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
if (!dss_plls[i]) {
dss_plls[i] = pll;
return 0;
}
}
return -EBUSY;
}
void dss_pll_unregister(struct dss_pll *pll)
{
int i;
for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
if (dss_plls[i] == pll) {
dss_plls[i] = NULL;
return;
}
}
}
struct dss_pll *dss_pll_find(const char *name)
{
int i;
for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0)
return dss_plls[i];
}
return NULL;
}
int dss_pll_enable(struct dss_pll *pll)
{
int r;
r = clk_prepare_enable(pll->clkin);
if (r)
return r;
if (pll->regulator) {
r = regulator_enable(pll->regulator);
if (r)
goto err_reg;
}
r = pll->ops->enable(pll);
if (r)
goto err_enable;
return 0;
err_enable:
regulator_disable(pll->regulator);
err_reg:
clk_disable_unprepare(pll->clkin);
return r;
}
void dss_pll_disable(struct dss_pll *pll)
{
pll->ops->disable(pll);
if (pll->regulator)
regulator_disable(pll->regulator);
clk_disable_unprepare(pll->clkin);
memset(&pll->cinfo, 0, sizeof(pll->cinfo));
}
int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo)
{
int r;
r = pll->ops->set_config(pll, cinfo);
if (r)
return r;
pll->cinfo = *cinfo;
return 0;
}
bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
unsigned long out_min, unsigned long out_max,
dss_hsdiv_calc_func func, void *data)
{
const struct dss_pll_hw *hw = pll->hw;
int m, m_start, m_stop;
unsigned long out;
out_min = out_min ? out_min : 1;
out_max = out_max ? out_max : ULONG_MAX;
m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul);
m_stop = min((unsigned)(clkdco / out_min), hw->mX_max);
for (m = m_start; m <= m_stop; ++m) {
out = clkdco / m;
if (func(m, out, data))
return true;
}
return false;
}
bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
unsigned long pll_min, unsigned long pll_max,
dss_pll_calc_func func, void *data)
{
const struct dss_pll_hw *hw = pll->hw;
int n, n_start, n_stop;
int m, m_start, m_stop;
unsigned long fint, clkdco;
unsigned long pll_hw_max;
unsigned long fint_hw_min, fint_hw_max;
pll_hw_max = hw->clkdco_max;
fint_hw_min = hw->fint_min;
fint_hw_max = hw->fint_max;
n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);
pll_max = pll_max ? pll_max : ULONG_MAX;
for (n = n_start; n <= n_stop; ++n) {
fint = clkin / n;
m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
1ul);
m_stop = min3((unsigned)(pll_max / fint / 2),
(unsigned)(pll_hw_max / fint / 2),
hw->m_max);
for (m = m_start; m <= m_stop; ++m) {
clkdco = 2 * m * fint;
if (func(n, m, fint, clkdco, data))
return true;
}
}
return false;
}
static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
{
unsigned long timeout;
ktime_t wait;
int t;
/* first busyloop to see if the bit changes right away */
t = 100;
while (t-- > 0) {
if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
return value;
}
/* then loop for 500ms, sleeping for 1ms in between */
timeout = jiffies + msecs_to_jiffies(500);
while (time_before(jiffies, timeout)) {
if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
return value;
wait = ns_to_ktime(1000 * 1000);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
}
return !value;
}
static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
{
int t = 100;
while (t-- > 0) {
u32 v = readl_relaxed(pll->base + PLL_STATUS);
v &= hsdiv_ack_mask;
if (v == hsdiv_ack_mask)
return 0;
}
return -ETIMEDOUT;
}
int dss_pll_write_config_type_a(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo)
{
const struct dss_pll_hw *hw = pll->hw;
void __iomem *base = pll->base;
int r = 0;
u32 l;
l = 0;
if (hw->has_stopmode)
l = FLD_MOD(l, 1, 0, 0); /* PLL_STOPMODE */
l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb); /* PLL_REGN */
l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb); /* PLL_REGM */
/* M4 */
l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0,
hw->mX_msb[0], hw->mX_lsb[0]);
/* M5 */
l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0,
hw->mX_msb[1], hw->mX_lsb[1]);
writel_relaxed(l, base + PLL_CONFIGURATION1);
l = 0;
/* M6 */
l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0,
hw->mX_msb[2], hw->mX_lsb[2]);
/* M7 */
l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0,
hw->mX_msb[3], hw->mX_lsb[3]);
writel_relaxed(l, base + PLL_CONFIGURATION3);
l = readl_relaxed(base + PLL_CONFIGURATION2);
if (hw->has_freqsel) {
u32 f = cinfo->fint < 1000000 ? 0x3 :
cinfo->fint < 1250000 ? 0x4 :
cinfo->fint < 1500000 ? 0x5 :
cinfo->fint < 1750000 ? 0x6 :
0x7;
l = FLD_MOD(l, f, 4, 1); /* PLL_FREQSEL */
} else if (hw->has_selfreqdco) {
u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4;
l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */
}
l = FLD_MOD(l, 1, 13, 13); /* PLL_REFEN */
l = FLD_MOD(l, 0, 14, 14); /* PHY_CLKINEN */
l = FLD_MOD(l, 0, 16, 16); /* M4_CLOCK_EN */
l = FLD_MOD(l, 0, 18, 18); /* M5_CLOCK_EN */
l = FLD_MOD(l, 1, 20, 20); /* HSDIVBYPASS */
if (hw->has_refsel)
l = FLD_MOD(l, 3, 22, 21); /* REFSEL = sysclk */
l = FLD_MOD(l, 0, 23, 23); /* M6_CLOCK_EN */
l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */
writel_relaxed(l, base + PLL_CONFIGURATION2);
writel_relaxed(1, base + PLL_GO); /* PLL_GO */
if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
DSSERR("DSS DPLL GO bit not going down.\n");
r = -EIO;
goto err;
}
if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
DSSERR("cannot lock DSS DPLL\n");
r = -EIO;
goto err;
}
l = readl_relaxed(base + PLL_CONFIGURATION2);
l = FLD_MOD(l, 1, 14, 14); /* PHY_CLKINEN */
l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16); /* M4_CLOCK_EN */
l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18); /* M5_CLOCK_EN */
l = FLD_MOD(l, 0, 20, 20); /* HSDIVBYPASS */
l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23); /* M6_CLOCK_EN */
l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25); /* M7_CLOCK_EN */
writel_relaxed(l, base + PLL_CONFIGURATION2);
r = dss_wait_hsdiv_ack(pll,
(cinfo->mX[0] ? BIT(7) : 0) |
(cinfo->mX[1] ? BIT(8) : 0) |
(cinfo->mX[2] ? BIT(10) : 0) |
(cinfo->mX[3] ? BIT(11) : 0));
if (r) {
DSSERR("failed to enable HSDIV clocks\n");
goto err;
}
err:
return r;
}
int dss_pll_write_config_type_b(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo)
{
const struct dss_pll_hw *hw = pll->hw;
void __iomem *base = pll->base;
u32 l;
l = 0;
l = FLD_MOD(l, cinfo->m, 20, 9); /* PLL_REGM */
l = FLD_MOD(l, cinfo->n - 1, 8, 1); /* PLL_REGN */
writel_relaxed(l, base + PLL_CONFIGURATION1);
l = readl_relaxed(base + PLL_CONFIGURATION2);
l = FLD_MOD(l, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
l = FLD_MOD(l, 0x1, 13, 13); /* PLL_REFEN */
l = FLD_MOD(l, 0x0, 14, 14); /* PHY_CLKINEN */
if (hw->has_refsel)
l = FLD_MOD(l, 0x3, 22, 21); /* REFSEL = SYSCLK */
/* PLL_SELFREQDCO */
if (cinfo->clkdco > hw->clkdco_low)
l = FLD_MOD(l, 0x4, 3, 1);
else
l = FLD_MOD(l, 0x2, 3, 1);
writel_relaxed(l, base + PLL_CONFIGURATION2);
l = readl_relaxed(base + PLL_CONFIGURATION3);
l = FLD_MOD(l, cinfo->sd, 17, 10); /* PLL_REGSD */
writel_relaxed(l, base + PLL_CONFIGURATION3);
l = readl_relaxed(base + PLL_CONFIGURATION4);
l = FLD_MOD(l, cinfo->mX[0], 24, 18); /* PLL_REGM2 */
l = FLD_MOD(l, cinfo->mf, 17, 0); /* PLL_REGM_F */
writel_relaxed(l, base + PLL_CONFIGURATION4);
writel_relaxed(1, base + PLL_GO); /* PLL_GO */
if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
DSSERR("DSS DPLL GO bit not going down.\n");
return -EIO;
}
if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
DSSERR("cannot lock DSS DPLL\n");
return -ETIMEDOUT;
}
return 0;
}

View file

@ -425,7 +425,7 @@ err_datapairs:
return r;
}
void __exit sdi_uninit_port(void)
void __exit sdi_uninit_port(struct device_node *port)
{
if (!sdi.port_initialized)
return;

View file

@ -1182,7 +1182,7 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
par->state.vgabase = (void __iomem *) vga_res.start;
par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
/* Unlock regs */
cr38 = vga_rcrt(par->state.vgabase, 0x38);

View file

@ -2181,8 +2181,7 @@ sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
if (!info || !info->device)
return;
if (ch->sglist)
vfree(ch->sglist);
vfree(ch->sglist);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);

View file

@ -26,6 +26,8 @@
#include <linux/module.h>
#include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/of_platform.h>
static struct fb_fix_screeninfo simplefb_fix = {
.id = "simple",
@ -41,6 +43,8 @@ static struct fb_var_screeninfo simplefb_var = {
.vmode = FB_VMODE_NONINTERLACED,
};
#define PSEUDO_PALETTE_SIZE 16
static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
@ -50,7 +54,7 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u32 cb = blue >> (16 - info->var.blue.length);
u32 value;
if (regno >= 16)
if (regno >= PSEUDO_PALETTE_SIZE)
return -EINVAL;
value = (cr << info->var.red.offset) |
@ -163,11 +167,113 @@ static int simplefb_parse_pd(struct platform_device *pdev,
return 0;
}
struct simplefb_par {
u32 palette[PSEUDO_PALETTE_SIZE];
#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
int clk_count;
struct clk **clks;
#endif
};
#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
/*
* Clock handling code.
*
* Here we handle the clocks property of our "simple-framebuffer" dt node.
* This is necessary so that we can make sure that any clocks needed by
* the display engine that the bootloader set up for us (and for which it
* provided a simplefb dt node), stay up, for the life of the simplefb
* driver.
*
* When the driver unloads, we cleanly disable, and then release the clocks.
*
* We only complain about errors here, no action is taken as the most likely
* error can only happen due to a mismatch between the bootloader which set
* up simplefb, and the clock definitions in the device tree. Chances are
* that there are no adverse effects, and if there are, a clean teardown of
* the fb probe will not help us much either. So just complain and carry on,
* and hope that the user actually gets a working fb at the end of things.
*/
static int simplefb_clocks_init(struct simplefb_par *par,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct clk *clock;
int i, ret;
if (dev_get_platdata(&pdev->dev) || !np)
return 0;
par->clk_count = of_clk_get_parent_count(np);
if (par->clk_count <= 0)
return 0;
par->clks = kcalloc(par->clk_count, sizeof(struct clk *), GFP_KERNEL);
if (!par->clks)
return -ENOMEM;
for (i = 0; i < par->clk_count; i++) {
clock = of_clk_get(np, i);
if (IS_ERR(clock)) {
if (PTR_ERR(clock) == -EPROBE_DEFER) {
while (--i >= 0) {
if (par->clks[i])
clk_put(par->clks[i]);
}
kfree(par->clks);
return -EPROBE_DEFER;
}
dev_err(&pdev->dev, "%s: clock %d not found: %ld\n",
__func__, i, PTR_ERR(clock));
continue;
}
par->clks[i] = clock;
}
for (i = 0; i < par->clk_count; i++) {
if (par->clks[i]) {
ret = clk_prepare_enable(par->clks[i]);
if (ret) {
dev_err(&pdev->dev,
"%s: failed to enable clock %d: %d\n",
__func__, i, ret);
clk_put(par->clks[i]);
par->clks[i] = NULL;
}
}
}
return 0;
}
static void simplefb_clocks_destroy(struct simplefb_par *par)
{
int i;
if (!par->clks)
return;
for (i = 0; i < par->clk_count; i++) {
if (par->clks[i]) {
clk_disable_unprepare(par->clks[i]);
clk_put(par->clks[i]);
}
}
kfree(par->clks);
}
#else
static int simplefb_clocks_init(struct simplefb_par *par,
struct platform_device *pdev) { return 0; }
static void simplefb_clocks_destroy(struct simplefb_par *par) { }
#endif
static int simplefb_probe(struct platform_device *pdev)
{
int ret;
struct simplefb_params params;
struct fb_info *info;
struct simplefb_par *par;
struct resource *mem;
if (fb_get_options("simplefb", NULL))
@ -188,11 +294,13 @@ static int simplefb_probe(struct platform_device *pdev)
return -EINVAL;
}
info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev);
if (!info)
return -ENOMEM;
platform_set_drvdata(pdev, info);
par = info->par;
info->fix = simplefb_fix;
info->fix.smem_start = mem->start;
info->fix.smem_len = resource_size(mem);
@ -211,8 +319,8 @@ static int simplefb_probe(struct platform_device *pdev)
info->apertures = alloc_apertures(1);
if (!info->apertures) {
framebuffer_release(info);
return -ENOMEM;
ret = -ENOMEM;
goto error_fb_release;
}
info->apertures->ranges[0].base = info->fix.smem_start;
info->apertures->ranges[0].size = info->fix.smem_len;
@ -222,10 +330,14 @@ static int simplefb_probe(struct platform_device *pdev)
info->screen_base = ioremap_wc(info->fix.smem_start,
info->fix.smem_len);
if (!info->screen_base) {
framebuffer_release(info);
return -ENODEV;
ret = -ENOMEM;
goto error_fb_release;
}
info->pseudo_palette = (void *)(info + 1);
info->pseudo_palette = par->palette;
ret = simplefb_clocks_init(par, pdev);
if (ret < 0)
goto error_unmap;
dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
info->fix.smem_start, info->fix.smem_len,
@ -238,21 +350,29 @@ static int simplefb_probe(struct platform_device *pdev)
ret = register_framebuffer(info);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
iounmap(info->screen_base);
framebuffer_release(info);
return ret;
goto error_clocks;
}
dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
return 0;
error_clocks:
simplefb_clocks_destroy(par);
error_unmap:
iounmap(info->screen_base);
error_fb_release:
framebuffer_release(info);
return ret;
}
static int simplefb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
struct simplefb_par *par = info->par;
unregister_framebuffer(info);
simplefb_clocks_destroy(par);
framebuffer_release(info);
return 0;
@ -273,7 +393,27 @@ static struct platform_driver simplefb_driver = {
.probe = simplefb_probe,
.remove = simplefb_remove,
};
module_platform_driver(simplefb_driver);
static int __init simplefb_init(void)
{
int ret;
struct device_node *np;
ret = platform_driver_register(&simplefb_driver);
if (ret)
return ret;
if (IS_ENABLED(CONFIG_OF) && of_chosen) {
for_each_child_of_node(of_chosen, np) {
if (of_device_is_compatible(np, "simple-framebuffer"))
of_platform_device_create(np, NULL, NULL);
}
}
return 0;
}
fs_initcall(simplefb_init);
MODULE_AUTHOR("Stephen Warren <[email protected]>");
MODULE_DESCRIPTION("Simple framebuffer driver");

View file

@ -5989,7 +5989,7 @@ static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if(!ivideo->sisvga_enabled) {
if(pci_enable_device(pdev)) {
if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
pci_dev_put(ivideo->nbridge);
framebuffer_release(sis_fb_info);
return -EIO;
}
@ -6202,10 +6202,8 @@ error_0: iounmap(ivideo->video_vbase);
error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
error_3: vfree(ivideo->bios_abase);
if(ivideo->lpcdev)
pci_dev_put(ivideo->lpcdev);
if(ivideo->nbridge)
pci_dev_put(ivideo->nbridge);
pci_dev_put(ivideo->lpcdev);
pci_dev_put(ivideo->nbridge);
if(!ivideo->sisvga_enabled)
pci_disable_device(pdev);
framebuffer_release(sis_fb_info);
@ -6505,11 +6503,9 @@ static void sisfb_remove(struct pci_dev *pdev)
vfree(ivideo->bios_abase);
if(ivideo->lpcdev)
pci_dev_put(ivideo->lpcdev);
pci_dev_put(ivideo->lpcdev);
if(ivideo->nbridge)
pci_dev_put(ivideo->nbridge);
pci_dev_put(ivideo->nbridge);
#ifdef CONFIG_MTRR
/* Release MTRR region */

View file

@ -1988,6 +1988,7 @@ static int sm501fb_probe(struct platform_device *pdev)
if (info->fb[HEAD_PANEL] == NULL &&
info->fb[HEAD_CRT] == NULL) {
dev_err(dev, "no framebuffers found\n");
ret = -ENODEV;
goto err_alloc;
}

View file

@ -1142,8 +1142,7 @@ static void ufx_free_framebuffer_work(struct work_struct *work)
fb_dealloc_cmap(&info->cmap);
if (info->monspecs.modedb)
fb_destroy_modedb(info->monspecs.modedb);
if (info->screen_base)
vfree(info->screen_base);
vfree(info->screen_base);
fb_destroy_modelist(&info->modelist);
@ -1743,8 +1742,7 @@ error:
fb_dealloc_cmap(&info->cmap);
if (info->monspecs.modedb)
fb_destroy_modedb(info->monspecs.modedb);
if (info->screen_base)
vfree(info->screen_base);
vfree(info->screen_base);
fb_destroy_modelist(&info->modelist);

View file

@ -922,8 +922,7 @@ static void dlfb_free(struct kref *kref)
{
struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
if (dev->backing_buffer)
vfree(dev->backing_buffer);
vfree(dev->backing_buffer);
kfree(dev->edid);
@ -953,8 +952,7 @@ static void dlfb_free_framebuffer(struct dlfb_data *dev)
fb_dealloc_cmap(&info->cmap);
if (info->monspecs.modedb)
fb_destroy_modedb(info->monspecs.modedb);
if (info->screen_base)
vfree(info->screen_base);
vfree(info->screen_base);
fb_destroy_modelist(&info->modelist);
@ -1203,8 +1201,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
if (!new_back)
pr_info("No shadow/backing buffer allocated\n");
else {
if (dev->backing_buffer)
vfree(dev->backing_buffer);
vfree(dev->backing_buffer);
dev->backing_buffer = new_back;
}
}

View file

@ -1219,8 +1219,7 @@ static int uvesafb_release(struct fb_info *info, int user)
uvesafb_vbe_state_restore(par, par->vbe_state_orig);
out:
atomic_dec(&par->ref_count);
if (task)
uvesafb_free(task);
uvesafb_free(task);
return 0;
}
@ -1923,8 +1922,7 @@ static int uvesafb_init(void)
err = -ENOMEM;
if (err) {
if (uvesafb_device)
platform_device_put(uvesafb_device);
platform_device_put(uvesafb_device);
platform_driver_unregister(&uvesafb_driver);
cn_del_callback(&uvesafb_cn_id);
return err;

View file

@ -1937,8 +1937,7 @@ out_fb1_unreg_lcd_cle266:
out_dealloc_cmap:
fb_dealloc_cmap(&viafbinfo->cmap);
out_fb1_release:
if (viafbinfo1)
framebuffer_release(viafbinfo1);
framebuffer_release(viafbinfo1);
out_fb_release:
i2c_bus_free(viaparinfo->shared);
framebuffer_release(viafbinfo);

View file

@ -731,7 +731,7 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
par->state.vgabase = (void __iomem *) vga_res.start;
par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
/* Find how many physical memory there is on card */
memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1;