mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
drm/rockchip: dsi: resolved dependency between mipi_tx0 and mipi_tx1
It has a shared pll for mipi_tx0/mipi_tx1 on RK3288/RK3399, so we need to initialize mipi_tx0 as necessary before enabling mipi_tx1. Change-Id: I2cd9ffe576c7a3d1e6c3081c2b174e3e971a0c4a Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
This commit is contained in:
@@ -31,7 +31,6 @@ Optional properties
|
||||
- phys: phandle to Non-SNPS PHY node
|
||||
- phy-names: the string "mipi_dphy" when is found in a node, along with "phys"
|
||||
attribute, provides phandle to MIPI PHY node
|
||||
- rockchip,dual-channel: for dual-channel panel, if not, don't configure
|
||||
- rockchip,lane-rate: manually configure lane-rate, not necessary.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
@@ -52,7 +51,6 @@ For Rockchip RK3288:
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rockchip,dual-channel = <&dsi1>;
|
||||
rockchip,lane-rate = <900>;
|
||||
|
||||
status = "okay";
|
||||
|
||||
@@ -282,12 +282,11 @@ struct dw_mipi_dsi {
|
||||
struct clk *pclk;
|
||||
struct clk *h2p_clk;
|
||||
int irq;
|
||||
|
||||
/* dual-channel */
|
||||
struct dw_mipi_dsi *master;
|
||||
struct dw_mipi_dsi *slave;
|
||||
struct device_node *panel_node;
|
||||
int id;
|
||||
struct mutex mutex;
|
||||
bool prepared;
|
||||
unsigned int id;
|
||||
|
||||
unsigned long mode_flags;
|
||||
unsigned int lane_mbps; /* per lane */
|
||||
@@ -802,6 +801,11 @@ static void dw_mipi_dsi_set_pll(struct dw_mipi_dsi *dsi, unsigned long rate)
|
||||
dsi->slave->dphy.input_div = dsi->dphy.input_div;
|
||||
dsi->slave->dphy.feedback_div = dsi->dphy.feedback_div;
|
||||
}
|
||||
if (dsi->master) {
|
||||
dsi->master->lane_mbps = dsi->lane_mbps;
|
||||
dsi->master->dphy.input_div = dsi->dphy.input_div;
|
||||
dsi->master->dphy.feedback_div = dsi->dphy.feedback_div;
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_mipi_dsi_set_hs_clk(struct dw_mipi_dsi *dsi, unsigned long rate)
|
||||
@@ -816,9 +820,6 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
|
||||
{
|
||||
struct dw_mipi_dsi *dsi = host_to_dsi(host);
|
||||
|
||||
if (dsi->master)
|
||||
return 0;
|
||||
|
||||
if (device->lanes < 1 || device->lanes > 8)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1095,7 +1096,7 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
|
||||
|
||||
static void mipi_dphy_init(struct dw_mipi_dsi *dsi)
|
||||
{
|
||||
u32 map[] = {0x1, 0x3, 0x7, 0xf};
|
||||
u32 map[] = {0x0, 0x1, 0x3, 0x7, 0xf};
|
||||
|
||||
mipi_dphy_enableclk_deassert(dsi);
|
||||
mipi_dphy_shutdownz_assert(dsi);
|
||||
@@ -1121,7 +1122,7 @@ static void mipi_dphy_init(struct dw_mipi_dsi *dsi)
|
||||
dw_mipi_dsi_phy_init(dsi);
|
||||
|
||||
/* Enable Data Lane Module */
|
||||
grf_field_write(dsi, ENABLE_N, map[dsi->lanes - 1]);
|
||||
grf_field_write(dsi, ENABLE_N, map[dsi->lanes]);
|
||||
|
||||
/* Enable Clock Lane Module */
|
||||
grf_field_write(dsi, ENABLECLK, 1);
|
||||
@@ -1186,14 +1187,8 @@ static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
|
||||
static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
int pkt_size;
|
||||
|
||||
if (dsi->slave || dsi->master)
|
||||
pkt_size = VID_PKT_SIZE(mode->hdisplay / 2);
|
||||
else
|
||||
pkt_size = VID_PKT_SIZE(mode->hdisplay);
|
||||
|
||||
regmap_write(dsi->regmap, DSI_VID_PKT_SIZE, pkt_size);
|
||||
regmap_write(dsi->regmap, DSI_VID_PKT_SIZE,
|
||||
VID_PKT_SIZE(mode->hdisplay));
|
||||
}
|
||||
|
||||
static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
|
||||
@@ -1211,10 +1206,8 @@ static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi,
|
||||
|
||||
lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8;
|
||||
|
||||
if (dsi->mode.clock == 0) {
|
||||
dev_err(dsi->dev, "dsi mode clock is 0!\n");
|
||||
if (dsi->mode.clock == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL(lbcc, dsi->mode.clock);
|
||||
}
|
||||
@@ -1288,8 +1281,10 @@ static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
|
||||
|
||||
drm_mode_copy(&dsi->mode, adjusted_mode);
|
||||
|
||||
if (dsi->slave)
|
||||
drm_mode_copy(&dsi->slave->mode, adjusted_mode);
|
||||
if (dsi->slave) {
|
||||
dsi->mode.hdisplay /= 2;
|
||||
drm_mode_copy(&dsi->slave->mode, &dsi->mode);
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
|
||||
@@ -1308,14 +1303,28 @@ static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
|
||||
|
||||
static void dw_mipi_dsi_post_disable(struct dw_mipi_dsi *dsi)
|
||||
{
|
||||
if (dsi->slave)
|
||||
dw_mipi_dsi_post_disable(dsi->slave);
|
||||
|
||||
mutex_lock(&dsi->mutex);
|
||||
|
||||
if (!dsi->prepared) {
|
||||
mutex_unlock(&dsi->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
dw_mipi_dsi_interrupt_disable(dsi);
|
||||
dw_mipi_dsi_host_power_off(dsi);
|
||||
mipi_dphy_power_off(dsi);
|
||||
|
||||
pm_runtime_put(dsi->dev);
|
||||
|
||||
if (dsi->slave)
|
||||
dw_mipi_dsi_post_disable(dsi->slave);
|
||||
dsi->prepared = false;
|
||||
|
||||
mutex_unlock(&dsi->mutex);
|
||||
|
||||
if (dsi->master)
|
||||
dw_mipi_dsi_post_disable(dsi->master);
|
||||
}
|
||||
|
||||
static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
|
||||
@@ -1352,6 +1361,16 @@ static void dw_mipi_dsi_host_init(struct dw_mipi_dsi *dsi)
|
||||
|
||||
static void dw_mipi_dsi_pre_enable(struct dw_mipi_dsi *dsi)
|
||||
{
|
||||
if (dsi->master)
|
||||
dw_mipi_dsi_pre_enable(dsi->master);
|
||||
|
||||
mutex_lock(&dsi->mutex);
|
||||
|
||||
if (dsi->prepared) {
|
||||
mutex_unlock(&dsi->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(dsi->dev);
|
||||
|
||||
/* MIPI DSI APB software reset request. */
|
||||
@@ -1365,6 +1384,10 @@ static void dw_mipi_dsi_pre_enable(struct dw_mipi_dsi *dsi)
|
||||
mipi_dphy_power_on(dsi);
|
||||
dw_mipi_dsi_host_power_on(dsi);
|
||||
|
||||
dsi->prepared = true;
|
||||
|
||||
mutex_unlock(&dsi->mutex);
|
||||
|
||||
if (dsi->slave)
|
||||
dw_mipi_dsi_pre_enable(dsi->slave);
|
||||
}
|
||||
@@ -1489,6 +1512,9 @@ static int dw_mipi_dsi_loader_protect(struct dw_mipi_dsi *dsi, bool on)
|
||||
{
|
||||
u32 int_st1;
|
||||
|
||||
if (dsi->master)
|
||||
dw_mipi_dsi_loader_protect(dsi->master, on);
|
||||
|
||||
if (on) {
|
||||
pm_runtime_get_sync(dsi->dev);
|
||||
regmap_read(dsi->regmap, DSI_INT_ST1, &int_st1);
|
||||
@@ -1573,32 +1599,6 @@ static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int dw_mipi_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct platform_device *secondary;
|
||||
|
||||
np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
|
||||
if (np) {
|
||||
secondary = of_find_device_by_node(np);
|
||||
dsi->slave = platform_get_drvdata(secondary);
|
||||
of_node_put(np);
|
||||
|
||||
if (!dsi->slave)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dsi->slave->master = dsi;
|
||||
dsi->lanes /= 2;
|
||||
|
||||
dsi->slave->lanes = dsi->lanes;
|
||||
dsi->slave->channel = dsi->channel;
|
||||
dsi->slave->format = dsi->format;
|
||||
dsi->slave->mode_flags = dsi->mode_flags;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_mipi_dsi_register(struct drm_device *drm,
|
||||
struct dw_mipi_dsi *dsi)
|
||||
{
|
||||
@@ -1669,6 +1669,50 @@ encoder_cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw_mipi_dsi_match_by_id(struct device *dev, void *data)
|
||||
{
|
||||
struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
|
||||
unsigned int *id = data;
|
||||
|
||||
return dsi->id == *id;
|
||||
}
|
||||
|
||||
static struct dw_mipi_dsi *dw_mipi_dsi_find_by_id(struct device_driver *drv,
|
||||
unsigned int id)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = driver_find_device(drv, NULL, &id, dw_mipi_dsi_match_by_id);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
return dev_get_drvdata(dev);
|
||||
}
|
||||
|
||||
static void dw_mipi_dsi_rpm_enable(struct dw_mipi_dsi *dsi)
|
||||
{
|
||||
if (!pm_runtime_enabled(dsi->dev))
|
||||
pm_runtime_enable(dsi->dev);
|
||||
|
||||
if (dsi->slave && !pm_runtime_enabled(dsi->slave->dev))
|
||||
pm_runtime_enable(dsi->slave->dev);
|
||||
|
||||
if (dsi->master && !pm_runtime_enabled(dsi->master->dev))
|
||||
pm_runtime_enable(dsi->master->dev);
|
||||
}
|
||||
|
||||
static void dw_mipi_dsi_rpm_disable(struct dw_mipi_dsi *dsi)
|
||||
{
|
||||
if (pm_runtime_enabled(dsi->dev))
|
||||
pm_runtime_disable(dsi->dev);
|
||||
|
||||
if (dsi->slave && pm_runtime_enabled(dsi->slave->dev))
|
||||
pm_runtime_disable(dsi->slave->dev);
|
||||
|
||||
if (dsi->master && pm_runtime_enabled(dsi->master->dev))
|
||||
pm_runtime_enable(dsi->master->dev);
|
||||
}
|
||||
|
||||
static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
@@ -1676,13 +1720,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
|
||||
struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = dw_mipi_dsi_dual_channel_probe(dsi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dsi->master)
|
||||
return 0;
|
||||
|
||||
dsi->panel = of_drm_find_panel(dsi->client);
|
||||
if (!dsi->panel) {
|
||||
dsi->bridge = of_drm_find_bridge(dsi->client);
|
||||
@@ -1690,6 +1727,24 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
if (dsi->id) {
|
||||
dsi->master = dw_mipi_dsi_find_by_id(dev->driver, 0);
|
||||
if (!dsi->master)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
if (dsi->lanes > 4) {
|
||||
dsi->slave = dw_mipi_dsi_find_by_id(dev->driver, 1);
|
||||
if (!dsi->slave)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dsi->lanes /= 2;
|
||||
dsi->slave->lanes = dsi->lanes;
|
||||
dsi->slave->channel = dsi->channel;
|
||||
dsi->slave->format = dsi->format;
|
||||
dsi->slave->mode_flags = dsi->mode_flags;
|
||||
}
|
||||
|
||||
ret = dw_mipi_dsi_register(drm, dsi);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
|
||||
@@ -1698,9 +1753,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
|
||||
|
||||
dev_set_drvdata(dev, dsi);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
if (dsi->slave)
|
||||
pm_runtime_enable(dsi->slave->dev);
|
||||
dw_mipi_dsi_rpm_enable(dsi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1710,12 +1763,10 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
|
||||
{
|
||||
struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
|
||||
|
||||
dw_mipi_dsi_rpm_disable(dsi);
|
||||
|
||||
if (dsi->panel)
|
||||
drm_panel_detach(dsi->panel);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
if (dsi->slave)
|
||||
pm_runtime_disable(dsi->slave->dev);
|
||||
}
|
||||
|
||||
static const struct component_ops dw_mipi_dsi_ops = {
|
||||
@@ -1898,6 +1949,8 @@ static int dw_mipi_dsi_probe(struct platform_device *pdev)
|
||||
if (!dsi)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&dsi->mutex);
|
||||
|
||||
dsi_id = of_alias_get_id(np, "dsi");
|
||||
if (dsi_id < 0)
|
||||
dsi_id = 0;
|
||||
|
||||
Reference in New Issue
Block a user