video/drm: dsi: fix pll clock setting for synopsys phy

Change-Id: Ib2cfdf413e3c4da039a16971fcc00baaab3b101c
Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
(sync from rk/kernel:develop-4.4:331690a183f536fe8a791ceed4231f7e484f8fb7)
This commit is contained in:
Wyon Bi 2019-01-19 10:11:05 +08:00 committed by Jianhong Chen
parent cef5be6b54
commit 1c3c799444
1 changed files with 104 additions and 79 deletions

View File

@ -229,6 +229,7 @@ struct mipi_dphy {
};
struct dw_mipi_dsi {
struct udevice *dev;
void *base;
void *grf;
const void *blob;
@ -468,6 +469,9 @@ static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi)
mipi_dphy_rstz_deassert(dsi);
mdelay(2);
if (dsi->dphy.phy)
rockchip_phy_power_on(dsi->dphy.phy);
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
val, val & PHY_LOCK,
1000, PHY_STATUS_TIMEOUT_US);
@ -537,76 +541,106 @@ static void dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
testif_write(dsi, 0x18, FEEDBACK_DIV_HI(m >> 5));
}
static unsigned long dw_mipi_dsi_calc_bandwidth(struct dw_mipi_dsi *dsi)
static unsigned long dw_mipi_dsi_get_lane_rate(struct dw_mipi_dsi *dsi)
{
int bpp;
unsigned long mpclk, tmp;
unsigned long target_mbps = 1000;
unsigned int max_mbps;
int lanes;
int rate;
const struct drm_display_mode *mode = dsi->mode;
unsigned long max_lane_rate = dsi->pdata->max_bit_rate_per_lane;
unsigned long lane_rate;
unsigned int value;
int bpp, lanes;
u64 tmp;
/* optional override of the desired bandwidth */
rate = ofnode_read_u32_default(dsi->node, "rockchip,lane-rate", -1);
if (rate > 0) {
return rate;
}
max_mbps = dsi->pdata->max_bit_rate_per_lane / USEC_PER_SEC;
value = dev_read_u32_default(dsi->dev, "rockchip,lane-rate", 0);
if (value > 0)
return value * USEC_PER_SEC;
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
if (bpp < 0) {
printf("failed to get bpp for pixel format %d\n",
dsi->format);
if (bpp < 0)
bpp = 24;
}
lanes = dsi->slave ? dsi->lanes * 2 : dsi->lanes;
tmp = (u64)mode->clock * 1000 * bpp;
do_div(tmp, lanes);
mpclk = DIV_ROUND_UP(dsi->mode->clock, MSEC_PER_SEC);
if (mpclk) {
/* take 1 / 0.9, since mbps must big than bandwidth of RGB */
tmp = mpclk * (bpp / lanes) * 10 / 9;
if (tmp < max_mbps)
target_mbps = tmp;
else
printf("DPHY clock frequency is out of range\n");
}
/* take 1 / 0.9, since mbps must big than bandwidth of RGB */
tmp *= 10;
do_div(tmp, 9);
return target_mbps;
if (tmp > max_lane_rate)
lane_rate = max_lane_rate;
else
lane_rate = tmp;
return lane_rate;
}
static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi)
static void dw_mipi_dsi_set_pll(struct dw_mipi_dsi *dsi, unsigned long rate)
{
unsigned int i, pre;
unsigned long pllref, tmp;
unsigned int m = 1, n = 1;
unsigned long target_mbps;
unsigned long fin, fout;
unsigned long fvco_min, fvco_max, best_freq = 984000000;
u8 min_prediv, max_prediv;
u8 _prediv, best_prediv = 2;
u16 _fbdiv, best_fbdiv = 82;
u32 min_delta = ~0U;
if (dsi->master)
return 0;
fin = 24000000;
fout = rate;
target_mbps = dw_mipi_dsi_calc_bandwidth(dsi);
/* 5Mhz < Fref / N < 40MHz, 80MHz < Fvco < 1500Mhz */
min_prediv = DIV_ROUND_UP(fin, 40000000);
max_prediv = fin / 5000000;
fvco_min = 80000000;
fvco_max = 1500000000;
/* ref clk : 24MHz*/
pllref = 24;
tmp = pllref;
for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
u64 tmp, _fout;
u32 delta;
for (i = 1; i < 6; i++) {
pre = pllref / i;
if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
tmp = target_mbps % pre;
n = i;
m = target_mbps / pre;
}
if (tmp == 0)
/* Fvco = Fref * M / N */
tmp = (u64)fout * _prediv;
do_div(tmp, fin);
_fbdiv = tmp;
/*
* Due to the use of a "by 2 pre-scaler," the range of the
* feedback multiplication value M is limited to even division
* numbers, and m must be greater than 12, less than 1000.
*/
if (_fbdiv <= 12 || _fbdiv >= 1000)
continue;
if (_fbdiv % 2)
++_fbdiv;
_fout = (u64)_fbdiv * fin;
do_div(_fout, _prediv);
if (_fout < fvco_min || _fout > fvco_max)
continue;
delta = abs(fout - _fout);
if (!delta) {
best_prediv = _prediv;
best_fbdiv = _fbdiv;
best_freq = _fout;
break;
} else if (delta < min_delta) {
best_prediv = _prediv;
best_fbdiv = _fbdiv;
best_freq = _fout;
min_delta = delta;
}
}
dsi->lane_mbps = pllref / n * m;
dsi->dphy.input_div = n;
dsi->dphy.feedback_div = m;
return 0;
dsi->lane_mbps = best_freq / USEC_PER_SEC;
dsi->dphy.input_div = best_prediv;
dsi->dphy.feedback_div = best_fbdiv;
if (dsi->slave) {
dsi->slave->lane_mbps = dsi->lane_mbps;
dsi->slave->dphy.input_div = dsi->dphy.input_div;
dsi->slave->dphy.feedback_div = dsi->dphy.feedback_div;
}
}
static int dw_mipi_dsi_read_from_fifo(struct dw_mipi_dsi *dsi,
@ -1108,16 +1142,11 @@ static int dw_mipi_dsi_connector_init(struct display_state *state)
const struct rockchip_connector *connector = conn_state->connector;
const struct dw_mipi_dsi_plat_data *pdata = connector->data;
ofnode mipi_node = conn_state->node;
struct dw_mipi_dsi *dsi;
struct dw_mipi_dsi *dsi = dev_get_priv(conn_state->dev);
ofnode panel;
int id;
int ret;
dsi = malloc(sizeof(*dsi));
if (!dsi)
return -ENOMEM;
memset(dsi, 0, sizeof(*dsi));
dsi->base = dev_read_addr_ptr(conn_state->dev);
dsi->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
if (dsi->grf <= 0) {
@ -1169,29 +1198,10 @@ static int dw_mipi_dsi_connector_init(struct display_state *state)
return 0;
}
static void dw_mipi_dsi_pre_init(struct dw_mipi_dsi *dsi)
static void dw_mipi_dsi_set_hs_clk(struct dw_mipi_dsi *dsi, unsigned long rate)
{
unsigned long bw, rate;
if (dsi->dphy.phy) {
bw = dw_mipi_dsi_calc_bandwidth(dsi);
rate = rockchip_phy_set_pll(dsi->dphy.phy, bw * USEC_PER_SEC);
dsi->lane_mbps = rate / USEC_PER_SEC;
rockchip_phy_set_mode(dsi->dphy.phy, PHY_MODE_VIDEO_MIPI);
rockchip_phy_power_on(dsi->dphy.phy);
} else {
dw_mipi_dsi_get_lane_bps(dsi);
}
if (dsi->slave) {
dsi->slave->mode = dsi->mode;
dsi->slave->lane_mbps = dsi->lane_mbps;
dsi->slave->dphy.input_div = dsi->dphy.input_div;
dsi->slave->dphy.feedback_div = dsi->dphy.feedback_div;
}
printf("final DSI-Link bandwidth: %u Mbps x %d\n",
dsi->lane_mbps, dsi->lanes);
rate = rockchip_phy_set_pll(dsi->dphy.phy, rate);
dsi->lane_mbps = rate / USEC_PER_SEC;
}
static void dw_mipi_dsi_host_init(struct dw_mipi_dsi *dsi)
@ -1270,11 +1280,22 @@ static int dw_mipi_dsi_connector_prepare(struct display_state *state)
struct connector_state *conn_state = &state->conn_state;
struct crtc_state *crtc_state = &state->crtc_state;
struct dw_mipi_dsi *dsi = conn_state->private;
unsigned long lane_rate;
dsi->mode = &conn_state->mode;
if (dsi->slave)
dsi->slave->mode = dsi->mode;
lane_rate = dw_mipi_dsi_get_lane_rate(dsi);
if (dsi->dphy.phy)
dw_mipi_dsi_set_hs_clk(dsi, lane_rate);
else
dw_mipi_dsi_set_pll(dsi, lane_rate);
printf("final DSI-Link bandwidth: %u Mbps x %d\n",
dsi->lane_mbps, dsi->slave ? dsi->lanes * 2 : dsi->lanes);
dw_mipi_dsi_vop_routing(dsi, crtc_state->crtc_id);
dw_mipi_dsi_pre_init(dsi);
dw_mipi_dsi_pre_enable(dsi);
return 0;
@ -1519,6 +1540,10 @@ static const struct udevice_id dw_mipi_dsi_ids[] = {
static int dw_mipi_dsi_probe(struct udevice *dev)
{
struct dw_mipi_dsi *dsi = dev_get_priv(dev);
dsi->dev = dev;
return 0;
}