Commit 2d701449 authored by Stefan Agner's avatar Stefan Agner

drm/fsl-dcu: use common clock framework for pixel clock divider

Use the common clock framework to calculate the pixel clock
dividier. The previous implementation rounded down the calculated
factor. Thanks to the CLK_DIVIDER_ROUND_CLOSEST flag using the
common clock framework divider implementation improves the pixel
clock accuracy in some cases. Ontop of that it also allows to see
the actual pixel clock in the sysfs clock summary.
Signed-off-by: default avatarStefan Agner <stefan@agner.ch>
parent f93500f4
...@@ -67,12 +67,10 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) ...@@ -67,12 +67,10 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
struct drm_display_mode *mode = &crtc->state->mode; struct drm_display_mode *mode = &crtc->state->mode;
unsigned int hbp, hfp, hsw, vbp, vfp, vsw, div, index, pol = 0; unsigned int hbp, hfp, hsw, vbp, vfp, vsw, index, pol = 0;
unsigned long dcuclk;
index = drm_crtc_index(crtc); index = drm_crtc_index(crtc);
dcuclk = clk_get_rate(fsl_dev->pix_clk); clk_set_rate(fsl_dev->pix_clk, mode->clock * 1000);
div = dcuclk / mode->clock / 1000;
/* Configure timings: */ /* Configure timings: */
hbp = mode->htotal - mode->hsync_end; hbp = mode->htotal - mode->hsync_end;
...@@ -99,7 +97,6 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) ...@@ -99,7 +97,6 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
regmap_write(fsl_dev->regmap, DCU_DISP_SIZE, regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) | DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
DCU_DISP_SIZE_DELTA_X(mode->hdisplay)); DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div);
regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol); regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol);
regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) | regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
DCU_BGND_G(0) | DCU_BGND_B(0)); DCU_BGND_G(0) | DCU_BGND_B(0));
......
...@@ -283,6 +283,9 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) ...@@ -283,6 +283,9 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
void __iomem *base; void __iomem *base;
struct drm_driver *driver = &fsl_dcu_drm_driver; struct drm_driver *driver = &fsl_dcu_drm_driver;
struct clk *pix_clk_in;
char pix_clk_name[32];
const char *pix_clk_in_name;
const struct of_device_id *id; const struct of_device_id *id;
int ret; int ret;
...@@ -331,15 +334,27 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) ...@@ -331,15 +334,27 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
return ret; return ret;
} }
fsl_dev->pix_clk = devm_clk_get(dev, "pix"); pix_clk_in = devm_clk_get(dev, "pix");
if (IS_ERR(pix_clk_in)) {
/* legancy binding, use dcu clock as pixel clock input */
pix_clk_in = fsl_dev->clk;
}
pix_clk_in_name = __clk_get_name(pix_clk_in);
snprintf(pix_clk_name, sizeof(pix_clk_name), "%s_pix", pix_clk_in_name);
fsl_dev->pix_clk = clk_register_divider(dev, pix_clk_name,
pix_clk_in_name, 0, base + DCU_DIV_RATIO,
0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL);
if (IS_ERR(fsl_dev->pix_clk)) { if (IS_ERR(fsl_dev->pix_clk)) {
/* legancy binding, use dcu clock as pixel clock */ dev_err(dev, "failed to register pix clk\n");
fsl_dev->pix_clk = fsl_dev->clk; ret = PTR_ERR(fsl_dev->pix_clk);
goto disable_clk;
} }
ret = clk_prepare_enable(fsl_dev->pix_clk); ret = clk_prepare_enable(fsl_dev->pix_clk);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "failed to enable pix clk\n"); dev_err(dev, "failed to enable pix clk\n");
goto disable_clk; goto unregister_pix_clk;
} }
drm = drm_dev_alloc(driver, dev); drm = drm_dev_alloc(driver, dev);
...@@ -368,6 +383,8 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) ...@@ -368,6 +383,8 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
drm_dev_unref(drm); drm_dev_unref(drm);
disable_pix_clk: disable_pix_clk:
clk_disable_unprepare(fsl_dev->pix_clk); clk_disable_unprepare(fsl_dev->pix_clk);
unregister_pix_clk:
clk_unregister(fsl_dev->pix_clk);
disable_clk: disable_clk:
clk_disable_unprepare(fsl_dev->clk); clk_disable_unprepare(fsl_dev->clk);
return ret; return ret;
...@@ -379,6 +396,7 @@ static int fsl_dcu_drm_remove(struct platform_device *pdev) ...@@ -379,6 +396,7 @@ static int fsl_dcu_drm_remove(struct platform_device *pdev)
clk_disable_unprepare(fsl_dev->clk); clk_disable_unprepare(fsl_dev->clk);
clk_disable_unprepare(fsl_dev->pix_clk); clk_disable_unprepare(fsl_dev->pix_clk);
clk_unregister(fsl_dev->pix_clk);
drm_put_dev(fsl_dev->drm); drm_put_dev(fsl_dev->drm);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment