drm: bridge: samsung-dsim: Dynamically configure DPHY timing

The DPHY timings are currently hard coded. Since the input
clock can be variable, the phy timings need to be variable
too.  To facilitate this, we need to cache the hs_clock
based on what is generated from the PLL.

The phy_mipi_dphy_get_default_config_for_hsclk function
configures the DPHY timings in pico-seconds, and a small macro
converts those timings into clock cycles based on the hs_clk.

Signed-off-by: Adam Ford <aford173@gmail.com>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Tested-by: Chen-Yu Tsai <wenst@chromium.org>
Tested-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Tested-by: Michael Walle <michael@walle.cc>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
Tested-by: Jagan Teki <jagan@amarulasolutions.com> # imx8mm-icore
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230526030559.326566-6-aford173@gmail.com
This commit is contained in:
Adam Ford
2023-05-25 22:05:57 -05:00
committed by Neil Armstrong
parent 171b3b1e0f
commit 89691775f5
2 changed files with 52 additions and 7 deletions

View File

@@ -220,6 +220,8 @@
#define OLD_SCLK_MIPI_CLK_NAME "pll_clk" #define OLD_SCLK_MIPI_CLK_NAME "pll_clk"
#define PS_TO_CYCLE(ps, hz) DIV64_U64_ROUND_CLOSEST(((ps) * (hz)), 1000000000000ULL)
static const char *const clk_names[5] = { static const char *const clk_names[5] = {
"bus_clk", "bus_clk",
"sclk_mipi", "sclk_mipi",
@@ -658,6 +660,8 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi,
reg = samsung_dsim_read(dsi, DSIM_STATUS_REG); reg = samsung_dsim_read(dsi, DSIM_STATUS_REG);
} while ((reg & DSIM_PLL_STABLE) == 0); } while ((reg & DSIM_PLL_STABLE) == 0);
dsi->hs_clock = fout;
return fout; return fout;
} }
@@ -705,13 +709,47 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi)
const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; const struct samsung_dsim_driver_data *driver_data = dsi->driver_data;
const unsigned int *reg_values = driver_data->reg_values; const unsigned int *reg_values = driver_data->reg_values;
u32 reg; u32 reg;
struct phy_configure_opts_mipi_dphy cfg;
int clk_prepare, lpx, clk_zero, clk_post, clk_trail;
int hs_exit, hs_prepare, hs_zero, hs_trail;
unsigned long long byte_clock = dsi->hs_clock / 8;
if (driver_data->has_freqband) if (driver_data->has_freqband)
return; return;
phy_mipi_dphy_get_default_config_for_hsclk(dsi->hs_clock,
dsi->lanes, &cfg);
/*
* TODO:
* The tech Applications Processor manuals for i.MX8M Mini, Nano,
* and Plus don't state what the definition of the PHYTIMING
* bits are beyond their address and bit position.
* After reviewing NXP's downstream code, it appears
* that the various PHYTIMING registers take the number
* of cycles and use various dividers on them. This
* calculation does not result in an exact match to the
* downstream code, but it is very close to the values
* generated by their lookup table, and it appears
* to sync at a variety of resolutions. If someone
* can get a more accurate mathematical equation needed
* for these registers, this should be updated.
*/
lpx = PS_TO_CYCLE(cfg.lpx, byte_clock);
hs_exit = PS_TO_CYCLE(cfg.hs_exit, byte_clock);
clk_prepare = PS_TO_CYCLE(cfg.clk_prepare, byte_clock);
clk_zero = PS_TO_CYCLE(cfg.clk_zero, byte_clock);
clk_post = PS_TO_CYCLE(cfg.clk_post, byte_clock);
clk_trail = PS_TO_CYCLE(cfg.clk_trail, byte_clock);
hs_prepare = PS_TO_CYCLE(cfg.hs_prepare, byte_clock);
hs_zero = PS_TO_CYCLE(cfg.hs_zero, byte_clock);
hs_trail = PS_TO_CYCLE(cfg.hs_trail, byte_clock);
/* B D-PHY: D-PHY Master & Slave Analog Block control */ /* B D-PHY: D-PHY Master & Slave Analog Block control */
reg = reg_values[PHYCTRL_ULPS_EXIT] | reg_values[PHYCTRL_VREG_LP] | reg = reg_values[PHYCTRL_ULPS_EXIT] | reg_values[PHYCTRL_VREG_LP] |
reg_values[PHYCTRL_SLEW_UP]; reg_values[PHYCTRL_SLEW_UP];
samsung_dsim_write(dsi, DSIM_PHYCTRL_REG, reg); samsung_dsim_write(dsi, DSIM_PHYCTRL_REG, reg);
/* /*
@@ -719,7 +757,9 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi)
* T HS-EXIT: Time that the transmitter drives LP-11 following a HS * T HS-EXIT: Time that the transmitter drives LP-11 following a HS
* burst * burst
*/ */
reg = reg_values[PHYTIMING_LPX] | reg_values[PHYTIMING_HS_EXIT];
reg = DSIM_PHYTIMING_LPX(lpx) | DSIM_PHYTIMING_HS_EXIT(hs_exit);
samsung_dsim_write(dsi, DSIM_PHYTIMING_REG, reg); samsung_dsim_write(dsi, DSIM_PHYTIMING_REG, reg);
/* /*
@@ -735,10 +775,11 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi)
* T CLK-TRAIL: Time that the transmitter drives the HS-0 state after * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after
* the last payload clock bit of a HS transmission burst * the last payload clock bit of a HS transmission burst
*/ */
reg = reg_values[PHYTIMING_CLK_PREPARE] |
reg_values[PHYTIMING_CLK_ZERO] | reg = DSIM_PHYTIMING1_CLK_PREPARE(clk_prepare) |
reg_values[PHYTIMING_CLK_POST] | DSIM_PHYTIMING1_CLK_ZERO(clk_zero) |
reg_values[PHYTIMING_CLK_TRAIL]; DSIM_PHYTIMING1_CLK_POST(clk_post) |
DSIM_PHYTIMING1_CLK_TRAIL(clk_trail);
samsung_dsim_write(dsi, DSIM_PHYTIMING1_REG, reg); samsung_dsim_write(dsi, DSIM_PHYTIMING1_REG, reg);
@@ -751,8 +792,11 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi)
* T HS-TRAIL: Time that the transmitter drives the flipped differential * T HS-TRAIL: Time that the transmitter drives the flipped differential
* state after last payload data bit of a HS transmission burst * state after last payload data bit of a HS transmission burst
*/ */
reg = reg_values[PHYTIMING_HS_PREPARE] | reg_values[PHYTIMING_HS_ZERO] |
reg_values[PHYTIMING_HS_TRAIL]; reg = DSIM_PHYTIMING2_HS_PREPARE(hs_prepare) |
DSIM_PHYTIMING2_HS_ZERO(hs_zero) |
DSIM_PHYTIMING2_HS_TRAIL(hs_trail);
samsung_dsim_write(dsi, DSIM_PHYTIMING2_REG, reg); samsung_dsim_write(dsi, DSIM_PHYTIMING2_REG, reg);
} }

View File

@@ -93,6 +93,7 @@ struct samsung_dsim {
u32 pll_clk_rate; u32 pll_clk_rate;
u32 burst_clk_rate; u32 burst_clk_rate;
u32 hs_clock;
u32 esc_clk_rate; u32 esc_clk_rate;
u32 lanes; u32 lanes;
u32 mode_flags; u32 mode_flags;