diff options
author | Sylwester Nawrocki <s.nawrocki@samsung.com> | 2013-04-23 07:34:37 -0400 |
---|---|---|
committer | Inki Dae <inki.dae@samsung.com> | 2013-04-29 01:35:32 -0400 |
commit | e5f8683923af2fd2bb0c5a7c0a66597cc6b50ef3 (patch) | |
tree | b2e43ec9b9c2df5042f73280fe4ae2f0cb8137b7 /drivers/gpu/drm/exynos | |
parent | 4c30cbc0b9c89d90c5a0d08bfb62d7a6b6c88d33 (diff) |
drm/exynos: rework fimc clocks handling
The clocks handling is refactored and a "mux" clock handling is
added to account for changes in the clocks driver. After switching
to the common clock framework the sclk_fimc clock is now split
into two clocks: a gate and a mux clock. In order to retain the
exisiting functionality two additional consumer clocks are passed
to the driver from device tree: "mux" and "parent". Then the driver
sets "parent" clock as a parent clock of the "mux" clock. These two
additional clocks are optional, and should go away when there is a
standard way of setting up parent clocks on DT platforms.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu/drm/exynos')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimc.c | 169 |
1 files changed, 99 insertions, 70 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index d812c5743eaf..2cce97d42ece 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c | |||
@@ -76,6 +76,27 @@ enum fimc_wb { | |||
76 | FIMC_WB_B, | 76 | FIMC_WB_B, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | enum { | ||
80 | FIMC_CLK_LCLK, | ||
81 | FIMC_CLK_GATE, | ||
82 | FIMC_CLK_WB_A, | ||
83 | FIMC_CLK_WB_B, | ||
84 | FIMC_CLK_MUX, | ||
85 | FIMC_CLK_PARENT, | ||
86 | FIMC_CLKS_MAX | ||
87 | }; | ||
88 | |||
89 | static const char * const fimc_clock_names[] = { | ||
90 | [FIMC_CLK_LCLK] = "sclk_fimc", | ||
91 | [FIMC_CLK_GATE] = "fimc", | ||
92 | [FIMC_CLK_WB_A] = "pxl_async0", | ||
93 | [FIMC_CLK_WB_B] = "pxl_async1", | ||
94 | [FIMC_CLK_MUX] = "mux", | ||
95 | [FIMC_CLK_PARENT] = "parent", | ||
96 | }; | ||
97 | |||
98 | #define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL | ||
99 | |||
79 | /* | 100 | /* |
80 | * A structure of scaler. | 101 | * A structure of scaler. |
81 | * | 102 | * |
@@ -134,13 +155,9 @@ struct fimc_driverdata { | |||
134 | * @regs_res: register resources. | 155 | * @regs_res: register resources. |
135 | * @regs: memory mapped io registers. | 156 | * @regs: memory mapped io registers. |
136 | * @lock: locking of operations. | 157 | * @lock: locking of operations. |
137 | * @sclk_fimc_clk: fimc source clock. | 158 | * @clocks: fimc clocks. |
138 | * @fimc_clk: fimc clock. | 159 | * @clk_frequency: LCLK clock frequency. |
139 | * @wb_clk: writeback a clock. | ||
140 | * @wb_b_clk: writeback b clock. | ||
141 | * @sc: scaler infomations. | 160 | * @sc: scaler infomations. |
142 | * @odr: ordering of YUV. | ||
143 | * @ver: fimc version. | ||
144 | * @pol: porarity of writeback. | 161 | * @pol: porarity of writeback. |
145 | * @id: fimc id. | 162 | * @id: fimc id. |
146 | * @irq: irq number. | 163 | * @irq: irq number. |
@@ -151,10 +168,8 @@ struct fimc_context { | |||
151 | struct resource *regs_res; | 168 | struct resource *regs_res; |
152 | void __iomem *regs; | 169 | void __iomem *regs; |
153 | struct mutex lock; | 170 | struct mutex lock; |
154 | struct clk *sclk_fimc_clk; | 171 | struct clk *clocks[FIMC_CLKS_MAX]; |
155 | struct clk *fimc_clk; | 172 | u32 clk_frequency; |
156 | struct clk *wb_clk; | ||
157 | struct clk *wb_b_clk; | ||
158 | struct fimc_scaler sc; | 173 | struct fimc_scaler sc; |
159 | struct fimc_driverdata *ddata; | 174 | struct fimc_driverdata *ddata; |
160 | struct exynos_drm_ipp_pol pol; | 175 | struct exynos_drm_ipp_pol pol; |
@@ -1301,14 +1316,12 @@ static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable) | |||
1301 | DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable); | 1316 | DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable); |
1302 | 1317 | ||
1303 | if (enable) { | 1318 | if (enable) { |
1304 | clk_enable(ctx->sclk_fimc_clk); | 1319 | clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]); |
1305 | clk_enable(ctx->fimc_clk); | 1320 | clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]); |
1306 | clk_enable(ctx->wb_clk); | ||
1307 | ctx->suspended = false; | 1321 | ctx->suspended = false; |
1308 | } else { | 1322 | } else { |
1309 | clk_disable(ctx->sclk_fimc_clk); | 1323 | clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]); |
1310 | clk_disable(ctx->fimc_clk); | 1324 | clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]); |
1311 | clk_disable(ctx->wb_clk); | ||
1312 | ctx->suspended = true; | 1325 | ctx->suspended = true; |
1313 | } | 1326 | } |
1314 | 1327 | ||
@@ -1713,11 +1726,70 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd) | |||
1713 | fimc_write(cfg, EXYNOS_CIGCTRL); | 1726 | fimc_write(cfg, EXYNOS_CIGCTRL); |
1714 | } | 1727 | } |
1715 | 1728 | ||
1729 | static void fimc_put_clocks(struct fimc_context *ctx) | ||
1730 | { | ||
1731 | int i; | ||
1732 | |||
1733 | for (i = 0; i < FIMC_CLKS_MAX; i++) { | ||
1734 | if (IS_ERR(ctx->clocks[i])) | ||
1735 | continue; | ||
1736 | clk_put(ctx->clocks[i]); | ||
1737 | ctx->clocks[i] = ERR_PTR(-EINVAL); | ||
1738 | } | ||
1739 | } | ||
1740 | |||
1741 | static int fimc_setup_clocks(struct fimc_context *ctx) | ||
1742 | { | ||
1743 | struct device *fimc_dev = ctx->ippdrv.dev; | ||
1744 | struct device *dev; | ||
1745 | int ret, i; | ||
1746 | |||
1747 | for (i = 0; i < FIMC_CLKS_MAX; i++) | ||
1748 | ctx->clocks[i] = ERR_PTR(-EINVAL); | ||
1749 | |||
1750 | for (i = 0; i < FIMC_CLKS_MAX; i++) { | ||
1751 | if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B) | ||
1752 | dev = fimc_dev->parent; | ||
1753 | else | ||
1754 | dev = fimc_dev; | ||
1755 | |||
1756 | ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]); | ||
1757 | if (IS_ERR(ctx->clocks[i])) { | ||
1758 | if (i >= FIMC_CLK_MUX) | ||
1759 | break; | ||
1760 | ret = PTR_ERR(ctx->clocks[i]); | ||
1761 | dev_err(fimc_dev, "failed to get clock: %s\n", | ||
1762 | fimc_clock_names[i]); | ||
1763 | goto e_clk_free; | ||
1764 | } | ||
1765 | } | ||
1766 | |||
1767 | /* Optional FIMC LCLK parent clock setting */ | ||
1768 | if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) { | ||
1769 | ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX], | ||
1770 | ctx->clocks[FIMC_CLK_PARENT]); | ||
1771 | if (ret < 0) { | ||
1772 | dev_err(fimc_dev, "failed to set parent.\n"); | ||
1773 | goto e_clk_free; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency); | ||
1778 | if (ret < 0) | ||
1779 | goto e_clk_free; | ||
1780 | |||
1781 | ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]); | ||
1782 | if (!ret) | ||
1783 | return ret; | ||
1784 | e_clk_free: | ||
1785 | fimc_put_clocks(ctx); | ||
1786 | return ret; | ||
1787 | } | ||
1788 | |||
1716 | static int fimc_probe(struct platform_device *pdev) | 1789 | static int fimc_probe(struct platform_device *pdev) |
1717 | { | 1790 | { |
1718 | struct device *dev = &pdev->dev; | 1791 | struct device *dev = &pdev->dev; |
1719 | struct fimc_context *ctx; | 1792 | struct fimc_context *ctx; |
1720 | struct clk *parent_clk; | ||
1721 | struct resource *res; | 1793 | struct resource *res; |
1722 | struct exynos_drm_ippdrv *ippdrv; | 1794 | struct exynos_drm_ippdrv *ippdrv; |
1723 | struct exynos_drm_fimc_pdata *pdata; | 1795 | struct exynos_drm_fimc_pdata *pdata; |
@@ -1734,55 +1806,6 @@ static int fimc_probe(struct platform_device *pdev) | |||
1734 | if (!ctx) | 1806 | if (!ctx) |
1735 | return -ENOMEM; | 1807 | return -ENOMEM; |
1736 | 1808 | ||
1737 | ddata = (struct fimc_driverdata *) | ||
1738 | platform_get_device_id(pdev)->driver_data; | ||
1739 | |||
1740 | /* clock control */ | ||
1741 | ctx->sclk_fimc_clk = devm_clk_get(dev, "sclk_fimc"); | ||
1742 | if (IS_ERR(ctx->sclk_fimc_clk)) { | ||
1743 | dev_err(dev, "failed to get src fimc clock.\n"); | ||
1744 | return PTR_ERR(ctx->sclk_fimc_clk); | ||
1745 | } | ||
1746 | clk_enable(ctx->sclk_fimc_clk); | ||
1747 | |||
1748 | ctx->fimc_clk = devm_clk_get(dev, "fimc"); | ||
1749 | if (IS_ERR(ctx->fimc_clk)) { | ||
1750 | dev_err(dev, "failed to get fimc clock.\n"); | ||
1751 | clk_disable(ctx->sclk_fimc_clk); | ||
1752 | return PTR_ERR(ctx->fimc_clk); | ||
1753 | } | ||
1754 | |||
1755 | ctx->wb_clk = devm_clk_get(dev, "pxl_async0"); | ||
1756 | if (IS_ERR(ctx->wb_clk)) { | ||
1757 | dev_err(dev, "failed to get writeback a clock.\n"); | ||
1758 | clk_disable(ctx->sclk_fimc_clk); | ||
1759 | return PTR_ERR(ctx->wb_clk); | ||
1760 | } | ||
1761 | |||
1762 | ctx->wb_b_clk = devm_clk_get(dev, "pxl_async1"); | ||
1763 | if (IS_ERR(ctx->wb_b_clk)) { | ||
1764 | dev_err(dev, "failed to get writeback b clock.\n"); | ||
1765 | clk_disable(ctx->sclk_fimc_clk); | ||
1766 | return PTR_ERR(ctx->wb_b_clk); | ||
1767 | } | ||
1768 | |||
1769 | parent_clk = devm_clk_get(dev, ddata->parent_clk); | ||
1770 | |||
1771 | if (IS_ERR(parent_clk)) { | ||
1772 | dev_err(dev, "failed to get parent clock.\n"); | ||
1773 | clk_disable(ctx->sclk_fimc_clk); | ||
1774 | return PTR_ERR(parent_clk); | ||
1775 | } | ||
1776 | |||
1777 | if (clk_set_parent(ctx->sclk_fimc_clk, parent_clk)) { | ||
1778 | dev_err(dev, "failed to set parent.\n"); | ||
1779 | clk_disable(ctx->sclk_fimc_clk); | ||
1780 | return -EINVAL; | ||
1781 | } | ||
1782 | |||
1783 | devm_clk_put(dev, parent_clk); | ||
1784 | clk_set_rate(ctx->sclk_fimc_clk, pdata->clk_rate); | ||
1785 | |||
1786 | /* resource memory */ | 1809 | /* resource memory */ |
1787 | ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1810 | ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1788 | ctx->regs = devm_ioremap_resource(dev, ctx->regs_res); | 1811 | ctx->regs = devm_ioremap_resource(dev, ctx->regs_res); |
@@ -1804,6 +1827,9 @@ static int fimc_probe(struct platform_device *pdev) | |||
1804 | return ret; | 1827 | return ret; |
1805 | } | 1828 | } |
1806 | 1829 | ||
1830 | ret = fimc_setup_clocks(ctx); | ||
1831 | if (ret < 0) | ||
1832 | goto err_free_irq; | ||
1807 | /* context initailization */ | 1833 | /* context initailization */ |
1808 | ctx->id = pdev->id; | 1834 | ctx->id = pdev->id; |
1809 | ctx->pol = pdata->pol; | 1835 | ctx->pol = pdata->pol; |
@@ -1820,7 +1846,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1820 | ret = fimc_init_prop_list(ippdrv); | 1846 | ret = fimc_init_prop_list(ippdrv); |
1821 | if (ret < 0) { | 1847 | if (ret < 0) { |
1822 | dev_err(dev, "failed to init property list.\n"); | 1848 | dev_err(dev, "failed to init property list.\n"); |
1823 | goto err_get_irq; | 1849 | goto err_put_clk; |
1824 | } | 1850 | } |
1825 | 1851 | ||
1826 | DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id, | 1852 | DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id, |
@@ -1835,16 +1861,18 @@ static int fimc_probe(struct platform_device *pdev) | |||
1835 | ret = exynos_drm_ippdrv_register(ippdrv); | 1861 | ret = exynos_drm_ippdrv_register(ippdrv); |
1836 | if (ret < 0) { | 1862 | if (ret < 0) { |
1837 | dev_err(dev, "failed to register drm fimc device.\n"); | 1863 | dev_err(dev, "failed to register drm fimc device.\n"); |
1838 | goto err_ippdrv_register; | 1864 | goto err_pm_dis; |
1839 | } | 1865 | } |
1840 | 1866 | ||
1841 | dev_info(&pdev->dev, "drm fimc registered successfully.\n"); | 1867 | dev_info(&pdev->dev, "drm fimc registered successfully.\n"); |
1842 | 1868 | ||
1843 | return 0; | 1869 | return 0; |
1844 | 1870 | ||
1845 | err_ippdrv_register: | 1871 | err_pm_dis: |
1846 | pm_runtime_disable(dev); | 1872 | pm_runtime_disable(dev); |
1847 | err_get_irq: | 1873 | err_put_clk: |
1874 | fimc_put_clocks(ctx); | ||
1875 | err_free_irq: | ||
1848 | free_irq(ctx->irq, ctx); | 1876 | free_irq(ctx->irq, ctx); |
1849 | 1877 | ||
1850 | return ret; | 1878 | return ret; |
@@ -1859,6 +1887,7 @@ static int fimc_remove(struct platform_device *pdev) | |||
1859 | exynos_drm_ippdrv_unregister(ippdrv); | 1887 | exynos_drm_ippdrv_unregister(ippdrv); |
1860 | mutex_destroy(&ctx->lock); | 1888 | mutex_destroy(&ctx->lock); |
1861 | 1889 | ||
1890 | fimc_put_clocks(ctx); | ||
1862 | pm_runtime_set_suspended(dev); | 1891 | pm_runtime_set_suspended(dev); |
1863 | pm_runtime_disable(dev); | 1892 | pm_runtime_disable(dev); |
1864 | 1893 | ||