Skip to content

Commit bb3b6fc

Browse files
committed
sun6i: dsi: Convert to generic phy handling
Now that we have everything in place in the PHY framework to deal in a generic way with MIPI D-PHY phys, let's convert our PHY driver and its associated DSI driver to that new API. Reviewed-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/dc6450e2978b6dafcc464595ad06204d22d2658f.1548085432.git-series.maxime.ripard@bootlin.com
1 parent 1eb6ea4 commit bb3b6fc

File tree

5 files changed

+126
-103
lines changed

5 files changed

+126
-103
lines changed

drivers/gpu/drm/sun4i/Kconfig

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,19 @@ config DRM_SUN6I_DSI
4545
default MACH_SUN8I
4646
select CRC_CCITT
4747
select DRM_MIPI_DSI
48+
select DRM_SUN6I_DPHY
4849
help
4950
Choose this option if you want have an Allwinner SoC with
5051
MIPI-DSI support. If M is selected the module will be called
51-
sun6i-dsi
52+
sun6i_mipi_dsi.
53+
54+
config DRM_SUN6I_DPHY
55+
tristate "Allwinner A31 MIPI D-PHY Support"
56+
select GENERIC_PHY_MIPI_DPHY
57+
help
58+
Choose this option if you have an Allwinner SoC with
59+
MIPI-DSI support. If M is selected, the module will be
60+
called sun6i_mipi_dphy.
5261

5362
config DRM_SUN8I_DW_HDMI
5463
tristate "Support for Allwinner version of DesignWare HDMI"

drivers/gpu/drm/sun4i/Makefile

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ sun4i-tcon-y += sun4i_lvds.o
2424
sun4i-tcon-y += sun4i_tcon.o
2525
sun4i-tcon-y += sun4i_rgb.o
2626

27-
sun6i-dsi-y += sun6i_mipi_dphy.o
28-
sun6i-dsi-y += sun6i_mipi_dsi.o
29-
3027
obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o
3128
obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o
3229
obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
@@ -37,7 +34,8 @@ ifdef CONFIG_DRM_SUN4I_BACKEND
3734
obj-$(CONFIG_DRM_SUN4I) += sun4i-frontend.o
3835
endif
3936
obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
40-
obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i-dsi.o
37+
obj-$(CONFIG_DRM_SUN6I_DPHY) += sun6i_mipi_dphy.o
38+
obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i_mipi_dsi.o
4139
obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o
4240
obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
4341
obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o

drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c

Lines changed: 95 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88

99
#include <linux/bitops.h>
1010
#include <linux/clk.h>
11+
#include <linux/module.h>
1112
#include <linux/of_address.h>
13+
#include <linux/platform_device.h>
1214
#include <linux/regmap.h>
1315
#include <linux/reset.h>
1416

15-
#include "sun6i_mipi_dsi.h"
17+
#include <linux/phy/phy.h>
18+
#include <linux/phy/phy-mipi-dphy.h>
1619

1720
#define SUN6I_DPHY_GCTL_REG 0x00
1821
#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
@@ -81,12 +84,46 @@
8184

8285
#define SUN6I_DPHY_DBG5_REG 0xf4
8386

84-
int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes)
87+
struct sun6i_dphy {
88+
struct clk *bus_clk;
89+
struct clk *mod_clk;
90+
struct regmap *regs;
91+
struct reset_control *reset;
92+
93+
struct phy *phy;
94+
struct phy_configure_opts_mipi_dphy config;
95+
};
96+
97+
static int sun6i_dphy_init(struct phy *phy)
8598
{
99+
struct sun6i_dphy *dphy = phy_get_drvdata(phy);
100+
86101
reset_control_deassert(dphy->reset);
87102
clk_prepare_enable(dphy->mod_clk);
88103
clk_set_rate_exclusive(dphy->mod_clk, 150000000);
89104

105+
return 0;
106+
}
107+
108+
static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
109+
{
110+
struct sun6i_dphy *dphy = phy_get_drvdata(phy);
111+
int ret;
112+
113+
ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
114+
if (ret)
115+
return ret;
116+
117+
memcpy(&dphy->config, opts, sizeof(dphy->config));
118+
119+
return 0;
120+
}
121+
122+
static int sun6i_dphy_power_on(struct phy *phy)
123+
{
124+
struct sun6i_dphy *dphy = phy_get_drvdata(phy);
125+
u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
126+
90127
regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
91128
SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
92129

@@ -111,16 +148,9 @@ int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes)
111148
SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
112149

113150
regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
114-
SUN6I_DPHY_GCTL_LANE_NUM(lanes) |
151+
SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
115152
SUN6I_DPHY_GCTL_EN);
116153

117-
return 0;
118-
}
119-
120-
int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes)
121-
{
122-
u8 lanes_mask = GENMASK(lanes - 1, 0);
123-
124154
regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
125155
SUN6I_DPHY_ANA0_REG_PWS |
126156
SUN6I_DPHY_ANA0_REG_DMPC |
@@ -181,23 +211,36 @@ int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes)
181211
return 0;
182212
}
183213

184-
int sun6i_dphy_power_off(struct sun6i_dphy *dphy)
214+
static int sun6i_dphy_power_off(struct phy *phy)
185215
{
216+
struct sun6i_dphy *dphy = phy_get_drvdata(phy);
217+
186218
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
187219
SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
188220

189221
return 0;
190222
}
191223

192-
int sun6i_dphy_exit(struct sun6i_dphy *dphy)
224+
static int sun6i_dphy_exit(struct phy *phy)
193225
{
226+
struct sun6i_dphy *dphy = phy_get_drvdata(phy);
227+
194228
clk_rate_exclusive_put(dphy->mod_clk);
195229
clk_disable_unprepare(dphy->mod_clk);
196230
reset_control_assert(dphy->reset);
197231

198232
return 0;
199233
}
200234

235+
236+
static struct phy_ops sun6i_dphy_ops = {
237+
.configure = sun6i_dphy_configure,
238+
.power_on = sun6i_dphy_power_on,
239+
.power_off = sun6i_dphy_power_off,
240+
.init = sun6i_dphy_init,
241+
.exit = sun6i_dphy_exit,
242+
};
243+
201244
static struct regmap_config sun6i_dphy_regmap_config = {
202245
.reg_bits = 32,
203246
.val_bits = 32,
@@ -206,87 +249,70 @@ static struct regmap_config sun6i_dphy_regmap_config = {
206249
.name = "mipi-dphy",
207250
};
208251

209-
static const struct of_device_id sun6i_dphy_of_table[] = {
210-
{ .compatible = "allwinner,sun6i-a31-mipi-dphy" },
211-
{ }
212-
};
213-
214-
int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node)
252+
static int sun6i_dphy_probe(struct platform_device *pdev)
215253
{
254+
struct phy_provider *phy_provider;
216255
struct sun6i_dphy *dphy;
217-
struct resource res;
256+
struct resource *res;
218257
void __iomem *regs;
219-
int ret;
220-
221-
if (!of_match_node(sun6i_dphy_of_table, node)) {
222-
dev_err(dsi->dev, "Incompatible D-PHY\n");
223-
return -EINVAL;
224-
}
225258

226-
dphy = devm_kzalloc(dsi->dev, sizeof(*dphy), GFP_KERNEL);
259+
dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
227260
if (!dphy)
228261
return -ENOMEM;
229262

230-
ret = of_address_to_resource(node, 0, &res);
231-
if (ret) {
232-
dev_err(dsi->dev, "phy: Couldn't get our resources\n");
233-
return ret;
234-
}
235-
236-
regs = devm_ioremap_resource(dsi->dev, &res);
263+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
264+
regs = devm_ioremap_resource(&pdev->dev, res);
237265
if (IS_ERR(regs)) {
238-
dev_err(dsi->dev, "Couldn't map the DPHY encoder registers\n");
266+
dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n");
239267
return PTR_ERR(regs);
240268
}
241269

242-
dphy->regs = devm_regmap_init_mmio(dsi->dev, regs,
243-
&sun6i_dphy_regmap_config);
270+
dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus",
271+
regs, &sun6i_dphy_regmap_config);
244272
if (IS_ERR(dphy->regs)) {
245-
dev_err(dsi->dev, "Couldn't create the DPHY encoder regmap\n");
273+
dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n");
246274
return PTR_ERR(dphy->regs);
247275
}
248276

249-
dphy->reset = of_reset_control_get_shared(node, NULL);
277+
dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL);
250278
if (IS_ERR(dphy->reset)) {
251-
dev_err(dsi->dev, "Couldn't get our reset line\n");
279+
dev_err(&pdev->dev, "Couldn't get our reset line\n");
252280
return PTR_ERR(dphy->reset);
253281
}
254282

255-
dphy->bus_clk = of_clk_get_by_name(node, "bus");
256-
if (IS_ERR(dphy->bus_clk)) {
257-
dev_err(dsi->dev, "Couldn't get the DPHY bus clock\n");
258-
ret = PTR_ERR(dphy->bus_clk);
259-
goto err_free_reset;
260-
}
261-
regmap_mmio_attach_clk(dphy->regs, dphy->bus_clk);
262-
263-
dphy->mod_clk = of_clk_get_by_name(node, "mod");
283+
dphy->mod_clk = devm_clk_get(&pdev->dev, "mod");
264284
if (IS_ERR(dphy->mod_clk)) {
265-
dev_err(dsi->dev, "Couldn't get the DPHY mod clock\n");
266-
ret = PTR_ERR(dphy->mod_clk);
267-
goto err_free_bus;
285+
dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n");
286+
return PTR_ERR(dphy->mod_clk);
268287
}
269288

270-
dsi->dphy = dphy;
289+
dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops);
290+
if (IS_ERR(dphy->phy)) {
291+
dev_err(&pdev->dev, "failed to create PHY\n");
292+
return PTR_ERR(dphy->phy);
293+
}
271294

272-
return 0;
295+
phy_set_drvdata(dphy->phy, dphy);
296+
phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
273297

274-
err_free_bus:
275-
regmap_mmio_detach_clk(dphy->regs);
276-
clk_put(dphy->bus_clk);
277-
err_free_reset:
278-
reset_control_put(dphy->reset);
279-
return ret;
298+
return PTR_ERR_OR_ZERO(phy_provider);
280299
}
281300

282-
int sun6i_dphy_remove(struct sun6i_dsi *dsi)
283-
{
284-
struct sun6i_dphy *dphy = dsi->dphy;
285-
286-
regmap_mmio_detach_clk(dphy->regs);
287-
clk_put(dphy->mod_clk);
288-
clk_put(dphy->bus_clk);
289-
reset_control_put(dphy->reset);
301+
static const struct of_device_id sun6i_dphy_of_table[] = {
302+
{ .compatible = "allwinner,sun6i-a31-mipi-dphy" },
303+
{ }
304+
};
305+
MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);
306+
307+
static struct platform_driver sun6i_dphy_platform_driver = {
308+
.probe = sun6i_dphy_probe,
309+
.driver = {
310+
.name = "sun6i-mipi-dphy",
311+
.of_match_table = sun6i_dphy_of_table,
312+
},
313+
};
314+
module_platform_driver(sun6i_dphy_platform_driver);
290315

291-
return 0;
292-
}
316+
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin>");
317+
MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver");
318+
MODULE_LICENSE("GPL");

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/slab.h>
1717

1818
#include <linux/phy/phy.h>
19+
#include <linux/phy/phy-mipi-dphy.h>
1920

2021
#include <drm/drmP.h>
2122
#include <drm/drm_atomic_helper.h>
@@ -616,6 +617,8 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
616617
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
617618
struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
618619
struct mipi_dsi_device *device = dsi->device;
620+
union phy_configure_opts opts = { 0 };
621+
struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
619622
u16 delay;
620623

621624
DRM_DEBUG_DRIVER("Enabling DSI output\n");
@@ -634,8 +637,15 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
634637
sun6i_dsi_setup_format(dsi, mode);
635638
sun6i_dsi_setup_timings(dsi, mode);
636639

637-
sun6i_dphy_init(dsi->dphy, device->lanes);
638-
sun6i_dphy_power_on(dsi->dphy, device->lanes);
640+
phy_init(dsi->dphy);
641+
642+
phy_mipi_dphy_get_default_config(mode->clock * 1000,
643+
mipi_dsi_pixel_format_to_bpp(device->format),
644+
device->lanes, cfg);
645+
646+
phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY);
647+
phy_configure(dsi->dphy, &opts);
648+
phy_power_on(dsi->dphy);
639649

640650
if (!IS_ERR(dsi->panel))
641651
drm_panel_prepare(dsi->panel);
@@ -673,8 +683,8 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
673683
drm_panel_unprepare(dsi->panel);
674684
}
675685

676-
sun6i_dphy_power_off(dsi->dphy);
677-
sun6i_dphy_exit(dsi->dphy);
686+
phy_power_off(dsi->dphy);
687+
phy_exit(dsi->dphy);
678688

679689
pm_runtime_put(dsi->dev);
680690
}
@@ -967,7 +977,6 @@ static const struct component_ops sun6i_dsi_ops = {
967977
static int sun6i_dsi_probe(struct platform_device *pdev)
968978
{
969979
struct device *dev = &pdev->dev;
970-
struct device_node *dphy_node;
971980
struct sun6i_dsi *dsi;
972981
struct resource *res;
973982
void __iomem *base;
@@ -1013,10 +1022,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
10131022
*/
10141023
clk_set_rate_exclusive(dsi->mod_clk, 297000000);
10151024

1016-
dphy_node = of_parse_phandle(dev->of_node, "phys", 0);
1017-
ret = sun6i_dphy_probe(dsi, dphy_node);
1018-
of_node_put(dphy_node);
1019-
if (ret) {
1025+
dsi->dphy = devm_phy_get(dev, "dphy");
1026+
if (IS_ERR(dsi->dphy)) {
10201027
dev_err(dev, "Couldn't get the MIPI D-PHY\n");
10211028
goto err_unprotect_clk;
10221029
}
@@ -1026,7 +1033,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
10261033
ret = mipi_dsi_host_register(&dsi->host);
10271034
if (ret) {
10281035
dev_err(dev, "Couldn't register MIPI-DSI host\n");
1029-
goto err_remove_phy;
1036+
goto err_pm_disable;
10301037
}
10311038

10321039
ret = component_add(&pdev->dev, &sun6i_dsi_ops);
@@ -1039,9 +1046,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
10391046

10401047
err_remove_dsi_host:
10411048
mipi_dsi_host_unregister(&dsi->host);
1042-
err_remove_phy:
1049+
err_pm_disable:
10431050
pm_runtime_disable(dev);
1044-
sun6i_dphy_remove(dsi);
10451051
err_unprotect_clk:
10461052
clk_rate_exclusive_put(dsi->mod_clk);
10471053
return ret;
@@ -1055,7 +1061,6 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
10551061
component_del(&pdev->dev, &sun6i_dsi_ops);
10561062
mipi_dsi_host_unregister(&dsi->host);
10571063
pm_runtime_disable(dev);
1058-
sun6i_dphy_remove(dsi);
10591064
clk_rate_exclusive_put(dsi->mod_clk);
10601065

10611066
return 0;

0 commit comments

Comments
 (0)