Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/media into drm-next
LVDS startup fixes, enable VSP compositor on GEN3 * 'drm/next/du' of git://linuxtv.org/pinchartl/media: drm: rcar-du: lvds: Refactor LVDS startup drm: rcar-du: lvds: Fix LVDS startup on R-Car Gen3 drm: rcar-du: lvds: Fix LVDS startup on R-Car Gen2 drm: rcar-du: lvds: Fix LVDS clock frequency range drm: rcar-du: lvds: Fix LVDCR1 for R-Car gen3 drm: rcar-du: Enable VSP compositor by default on Gen3 drm: rcar-du: Calculate DPLLCR to be more small jitter drm: rcar-du: Use 1000 to avoid misunderstanding in rcar_du_dpll_divider() drm: rcar-du: Remove zpos field from rcar_du_vsp_plane_state structure
This commit is contained in:
commit
e53a2079f4
|
@ -26,7 +26,8 @@ config DRM_RCAR_LVDS
|
||||||
Enable support for the R-Car Display Unit embedded LVDS encoders.
|
Enable support for the R-Car Display Unit embedded LVDS encoders.
|
||||||
|
|
||||||
config DRM_RCAR_VSP
|
config DRM_RCAR_VSP
|
||||||
bool "R-Car DU VSP Compositor Support"
|
bool "R-Car DU VSP Compositor Support" if ARM
|
||||||
|
default y if ARM64
|
||||||
depends on DRM_RCAR_DU
|
depends on DRM_RCAR_DU
|
||||||
depends on VIDEO_RENESAS_VSP1=y || (VIDEO_RENESAS_VSP1 && DRM_RCAR_DU=m)
|
depends on VIDEO_RENESAS_VSP1=y || (VIDEO_RENESAS_VSP1 && DRM_RCAR_DU=m)
|
||||||
help
|
help
|
||||||
|
|
|
@ -125,14 +125,55 @@ static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc,
|
||||||
unsigned int m;
|
unsigned int m;
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
|
|
||||||
for (n = 39; n < 120; n++) {
|
/*
|
||||||
for (m = 0; m < 4; m++) {
|
* fin fvco fout fclkout
|
||||||
|
* in --> [1/M] --> |PD| -> [LPF] -> [VCO] -> [1/P] -+-> [1/FDPLL] -> out
|
||||||
|
* +-> | | |
|
||||||
|
* | |
|
||||||
|
* +---------------- [1/N] <------------+
|
||||||
|
*
|
||||||
|
* fclkout = fvco / P / FDPLL -- (1)
|
||||||
|
*
|
||||||
|
* fin/M = fvco/P/N
|
||||||
|
*
|
||||||
|
* fvco = fin * P * N / M -- (2)
|
||||||
|
*
|
||||||
|
* (1) + (2) indicates
|
||||||
|
*
|
||||||
|
* fclkout = fin * N / M / FDPLL
|
||||||
|
*
|
||||||
|
* NOTES
|
||||||
|
* N : (n + 1)
|
||||||
|
* M : (m + 1)
|
||||||
|
* FDPLL : (fdpll + 1)
|
||||||
|
* P : 2
|
||||||
|
* 2kHz < fvco < 4096MHz
|
||||||
|
*
|
||||||
|
* To minimize the jitter,
|
||||||
|
* N : as large as possible
|
||||||
|
* M : as small as possible
|
||||||
|
*/
|
||||||
|
for (m = 0; m < 4; m++) {
|
||||||
|
for (n = 119; n > 38; n--) {
|
||||||
|
/*
|
||||||
|
* This code only runs on 64-bit architectures, the
|
||||||
|
* unsigned long type can thus be used for 64-bit
|
||||||
|
* computation. It will still compile without any
|
||||||
|
* warning on 32-bit architectures.
|
||||||
|
*
|
||||||
|
* To optimize calculations, use fout instead of fvco
|
||||||
|
* to verify the VCO frequency constraint.
|
||||||
|
*/
|
||||||
|
unsigned long fout = input * (n + 1) / (m + 1);
|
||||||
|
|
||||||
|
if (fout < 1000 || fout > 2048 * 1000 * 1000U)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (fdpll = 1; fdpll < 32; fdpll++) {
|
for (fdpll = 1; fdpll < 32; fdpll++) {
|
||||||
unsigned long output;
|
unsigned long output;
|
||||||
|
|
||||||
output = input * (n + 1) / (m + 1)
|
output = fout / (fdpll + 1);
|
||||||
/ (fdpll + 1);
|
if (output >= 400 * 1000 * 1000)
|
||||||
if (output >= 400000000)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
diff = abs((long)output - (long)target);
|
diff = abs((long)output - (long)target);
|
||||||
|
|
|
@ -39,100 +39,37 @@ static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
|
||||||
iowrite32(data, lvds->mmio + reg);
|
iowrite32(data, lvds->mmio + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds,
|
static u32 rcar_lvds_lvdpllcr_gen2(unsigned int freq)
|
||||||
struct rcar_du_crtc *rcrtc)
|
|
||||||
{
|
{
|
||||||
const struct drm_display_mode *mode = &rcrtc->crtc.mode;
|
|
||||||
unsigned int freq = mode->clock;
|
|
||||||
u32 lvdcr0;
|
|
||||||
u32 pllcr;
|
|
||||||
|
|
||||||
/* PLL clock configuration */
|
|
||||||
if (freq < 39000)
|
if (freq < 39000)
|
||||||
pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
|
return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
|
||||||
else if (freq < 61000)
|
else if (freq < 61000)
|
||||||
pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
|
return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
|
||||||
else if (freq < 121000)
|
else if (freq < 121000)
|
||||||
pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
|
return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
|
||||||
else
|
else
|
||||||
pllcr = LVDPLLCR_PLLDLYCNT_150M;
|
return LVDPLLCR_PLLDLYCNT_150M;
|
||||||
|
|
||||||
rcar_lvds_write(lvds, LVDPLLCR, pllcr);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Select the input, hardcode mode 0, enable LVDS operation and turn
|
|
||||||
* bias circuitry on.
|
|
||||||
*/
|
|
||||||
lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_BEN | LVDCR0_LVEN;
|
|
||||||
if (rcrtc->index == 2)
|
|
||||||
lvdcr0 |= LVDCR0_DUSEL;
|
|
||||||
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
|
||||||
|
|
||||||
/* Turn all the channels on. */
|
|
||||||
rcar_lvds_write(lvds, LVDCR1,
|
|
||||||
LVDCR1_CHSTBY_GEN2(3) | LVDCR1_CHSTBY_GEN2(2) |
|
|
||||||
LVDCR1_CHSTBY_GEN2(1) | LVDCR1_CHSTBY_GEN2(0) |
|
|
||||||
LVDCR1_CLKSTBY_GEN2);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Turn the PLL on, wait for the startup delay, and turn the output
|
|
||||||
* on.
|
|
||||||
*/
|
|
||||||
lvdcr0 |= LVDCR0_PLLON;
|
|
||||||
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
|
||||||
|
|
||||||
usleep_range(100, 150);
|
|
||||||
|
|
||||||
lvdcr0 |= LVDCR0_LVRES;
|
|
||||||
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
|
static u32 rcar_lvds_lvdpllcr_gen3(unsigned int freq)
|
||||||
struct rcar_du_crtc *rcrtc)
|
|
||||||
{
|
{
|
||||||
const struct drm_display_mode *mode = &rcrtc->crtc.mode;
|
|
||||||
unsigned int freq = mode->clock;
|
|
||||||
u32 lvdcr0;
|
|
||||||
u32 pllcr;
|
|
||||||
|
|
||||||
/* PLL clock configuration */
|
|
||||||
if (freq < 42000)
|
if (freq < 42000)
|
||||||
pllcr = LVDPLLCR_PLLDIVCNT_42M;
|
return LVDPLLCR_PLLDIVCNT_42M;
|
||||||
else if (freq < 85000)
|
else if (freq < 85000)
|
||||||
pllcr = LVDPLLCR_PLLDIVCNT_85M;
|
return LVDPLLCR_PLLDIVCNT_85M;
|
||||||
else if (freq < 128000)
|
else if (freq < 128000)
|
||||||
pllcr = LVDPLLCR_PLLDIVCNT_128M;
|
return LVDPLLCR_PLLDIVCNT_128M;
|
||||||
else
|
else
|
||||||
pllcr = LVDPLLCR_PLLDIVCNT_148M;
|
return LVDPLLCR_PLLDIVCNT_148M;
|
||||||
|
|
||||||
rcar_lvds_write(lvds, LVDPLLCR, pllcr);
|
|
||||||
|
|
||||||
/* Turn all the channels on. */
|
|
||||||
rcar_lvds_write(lvds, LVDCR1,
|
|
||||||
LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
|
|
||||||
LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
|
|
||||||
LVDCR1_CLKSTBY_GEN3);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Turn the PLL on, set it to LVDS normal mode, wait for the startup
|
|
||||||
* delay and turn the output on.
|
|
||||||
*/
|
|
||||||
lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PLLON;
|
|
||||||
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
|
||||||
|
|
||||||
lvdcr0 |= LVDCR0_PWD;
|
|
||||||
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
|
||||||
|
|
||||||
usleep_range(100, 150);
|
|
||||||
|
|
||||||
lvdcr0 |= LVDCR0_LVRES;
|
|
||||||
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
|
static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
|
||||||
struct rcar_du_crtc *rcrtc)
|
struct rcar_du_crtc *rcrtc)
|
||||||
{
|
{
|
||||||
|
const struct drm_display_mode *mode = &rcrtc->crtc.mode;
|
||||||
|
u32 lvdpllcr;
|
||||||
u32 lvdhcr;
|
u32 lvdhcr;
|
||||||
|
u32 lvdcr0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (lvds->enabled)
|
if (lvds->enabled)
|
||||||
|
@ -163,11 +100,46 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
|
||||||
|
|
||||||
rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
|
rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
|
||||||
|
|
||||||
/* Perform generation-specific initialization. */
|
/* PLL clock configuration. */
|
||||||
if (lvds->dev->info->gen < 3)
|
if (lvds->dev->info->gen < 3)
|
||||||
rcar_du_lvdsenc_start_gen2(lvds, rcrtc);
|
lvdpllcr = rcar_lvds_lvdpllcr_gen2(mode->clock);
|
||||||
else
|
else
|
||||||
rcar_du_lvdsenc_start_gen3(lvds, rcrtc);
|
lvdpllcr = rcar_lvds_lvdpllcr_gen3(mode->clock);
|
||||||
|
rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
|
||||||
|
|
||||||
|
/* Set the LVDS mode and select the input. */
|
||||||
|
lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT;
|
||||||
|
if (rcrtc->index == 2)
|
||||||
|
lvdcr0 |= LVDCR0_DUSEL;
|
||||||
|
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
||||||
|
|
||||||
|
/* Turn all the channels on. */
|
||||||
|
rcar_lvds_write(lvds, LVDCR1,
|
||||||
|
LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
|
||||||
|
LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
|
||||||
|
|
||||||
|
if (lvds->dev->info->gen < 3) {
|
||||||
|
/* Enable LVDS operation and turn the bias circuitry on. */
|
||||||
|
lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN;
|
||||||
|
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn the PLL on. */
|
||||||
|
lvdcr0 |= LVDCR0_PLLON;
|
||||||
|
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
||||||
|
|
||||||
|
if (lvds->dev->info->gen > 2) {
|
||||||
|
/* Set LVDS normal mode. */
|
||||||
|
lvdcr0 |= LVDCR0_PWD;
|
||||||
|
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for the startup delay. */
|
||||||
|
usleep_range(100, 150);
|
||||||
|
|
||||||
|
/* Turn the output on. */
|
||||||
|
lvdcr0 |= LVDCR0_LVRES;
|
||||||
|
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
|
||||||
|
|
||||||
lvds->enabled = true;
|
lvds->enabled = true;
|
||||||
|
|
||||||
|
@ -203,17 +175,11 @@ int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
|
||||||
void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
|
void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
|
||||||
struct drm_display_mode *mode)
|
struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
struct rcar_du_device *rcdu = lvds->dev;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The internal LVDS encoder has a restricted clock frequency operating
|
* The internal LVDS encoder has a restricted clock frequency operating
|
||||||
* range (30MHz to 150MHz on Gen2, 25.175MHz to 148.5MHz on Gen3). Clamp
|
* range (31MHz to 148.5MHz). Clamp the clock accordingly.
|
||||||
* the clock accordingly.
|
|
||||||
*/
|
*/
|
||||||
if (rcdu->info->gen < 3)
|
mode->clock = clamp(mode->clock, 31000, 148500);
|
||||||
mode->clock = clamp(mode->clock, 30000, 150000);
|
|
||||||
else
|
|
||||||
mode->clock = clamp(mode->clock, 25175, 148500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
|
void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
|
||||||
|
|
|
@ -45,7 +45,6 @@ static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p)
|
||||||
* @format: information about the pixel format used by the plane
|
* @format: information about the pixel format used by the plane
|
||||||
* @sg_tables: scatter-gather tables for the frame buffer memory
|
* @sg_tables: scatter-gather tables for the frame buffer memory
|
||||||
* @alpha: value of the plane alpha property
|
* @alpha: value of the plane alpha property
|
||||||
* @zpos: value of the plane zpos property
|
|
||||||
*/
|
*/
|
||||||
struct rcar_du_vsp_plane_state {
|
struct rcar_du_vsp_plane_state {
|
||||||
struct drm_plane_state state;
|
struct drm_plane_state state;
|
||||||
|
@ -54,7 +53,6 @@ struct rcar_du_vsp_plane_state {
|
||||||
struct sg_table sg_tables[3];
|
struct sg_table sg_tables[3];
|
||||||
|
|
||||||
unsigned int alpha;
|
unsigned int alpha;
|
||||||
unsigned int zpos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct rcar_du_vsp_plane_state *
|
static inline struct rcar_du_vsp_plane_state *
|
||||||
|
|
|
@ -26,10 +26,8 @@
|
||||||
|
|
||||||
#define LVDCR1 0x0004
|
#define LVDCR1 0x0004
|
||||||
#define LVDCR1_CKSEL (1 << 15) /* Gen2 only */
|
#define LVDCR1_CKSEL (1 << 15) /* Gen2 only */
|
||||||
#define LVDCR1_CHSTBY_GEN2(n) (3 << (2 + (n) * 2)) /* Gen2 only */
|
#define LVDCR1_CHSTBY(n) (3 << (2 + (n) * 2))
|
||||||
#define LVDCR1_CHSTBY_GEN3(n) (1 << (2 + (n) * 2)) /* Gen3 only */
|
#define LVDCR1_CLKSTBY (3 << 0)
|
||||||
#define LVDCR1_CLKSTBY_GEN2 (3 << 0) /* Gen2 only */
|
|
||||||
#define LVDCR1_CLKSTBY_GEN3 (1 << 0) /* Gen3 only */
|
|
||||||
|
|
||||||
#define LVDPLLCR 0x0008
|
#define LVDPLLCR 0x0008
|
||||||
#define LVDPLLCR_CEEN (1 << 14)
|
#define LVDPLLCR_CEEN (1 << 14)
|
||||||
|
|
Loading…
Reference in New Issue