提交 a86773d1 编写于 作者: E Eric Anholt

drm/vc4: Add support for feeding DSI encoders from the pixel valve.

We have to set a different pixel format, which tells the hardware to
use the pix_width field that's fed in sideband from the DSI encoder to
divide the "pixel" clock.
Signed-off-by: NEric Anholt <eric@anholt.net>
Acked-by: NDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20161214194621.16499-6-eric@anholt.net
上级 d17a1bb9
...@@ -348,38 +348,40 @@ static u32 vc4_get_fifo_full_level(u32 format) ...@@ -348,38 +348,40 @@ static u32 vc4_get_fifo_full_level(u32 format)
} }
/* /*
* Returns the clock select bit for the connector attached to the * Returns the encoder attached to the CRTC.
* CRTC. *
* VC4 can only scan out to one encoder at a time, while the DRM core
* allows drivers to push pixels to more than one encoder from the
* same CRTC.
*/ */
static int vc4_get_clock_select(struct drm_crtc *crtc) static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc)
{ {
struct drm_connector *connector; struct drm_connector *connector;
drm_for_each_connector(connector, crtc->dev) { drm_for_each_connector(connector, crtc->dev) {
if (connector->state->crtc == crtc) { if (connector->state->crtc == crtc) {
struct drm_encoder *encoder = connector->encoder; return connector->encoder;
struct vc4_encoder *vc4_encoder =
to_vc4_encoder(encoder);
return vc4_encoder->clock_select;
} }
} }
return -1; return NULL;
} }
static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct drm_crtc_state *state = crtc->state; struct drm_crtc_state *state = crtc->state;
struct drm_display_mode *mode = &state->adjusted_mode; struct drm_display_mode *mode = &state->adjusted_mode;
bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
u32 format = PV_CONTROL_FORMAT_24; bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
bool debug_dump_regs = false; bool debug_dump_regs = false;
int clock_select = vc4_get_clock_select(crtc);
if (debug_dump_regs) { if (debug_dump_regs) {
DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc)); DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc));
...@@ -435,17 +437,19 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) ...@@ -435,17 +437,19 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
*/ */
CRTC_WRITE(PV_V_CONTROL, CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS | PV_VCONTROL_CONTINUOUS |
(is_dsi ? PV_VCONTROL_DSI : 0) |
PV_VCONTROL_INTERLACE | PV_VCONTROL_INTERLACE |
VC4_SET_FIELD(mode->htotal * pixel_rep / 2, VC4_SET_FIELD(mode->htotal * pixel_rep / 2,
PV_VCONTROL_ODD_DELAY)); PV_VCONTROL_ODD_DELAY));
CRTC_WRITE(PV_VSYNCD_EVEN, 0); CRTC_WRITE(PV_VSYNCD_EVEN, 0);
} else { } else {
CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS); CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS |
(is_dsi ? PV_VCONTROL_DSI : 0));
} }
CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
CRTC_WRITE(PV_CONTROL, CRTC_WRITE(PV_CONTROL,
VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | VC4_SET_FIELD(format, PV_CONTROL_FORMAT) |
VC4_SET_FIELD(vc4_get_fifo_full_level(format), VC4_SET_FIELD(vc4_get_fifo_full_level(format),
...@@ -454,7 +458,8 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) ...@@ -454,7 +458,8 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
PV_CONTROL_CLR_AT_START | PV_CONTROL_CLR_AT_START |
PV_CONTROL_TRIGGER_UNDERFLOW | PV_CONTROL_TRIGGER_UNDERFLOW |
PV_CONTROL_WAIT_HSTART | PV_CONTROL_WAIT_HSTART |
VC4_SET_FIELD(clock_select, PV_CONTROL_CLK_SELECT) | VC4_SET_FIELD(vc4_encoder->clock_select,
PV_CONTROL_CLK_SELECT) |
PV_CONTROL_FIFO_CLR | PV_CONTROL_FIFO_CLR |
PV_CONTROL_EN); PV_CONTROL_EN);
......
...@@ -190,6 +190,8 @@ ...@@ -190,6 +190,8 @@
# define PV_VCONTROL_ODD_DELAY_SHIFT 6 # define PV_VCONTROL_ODD_DELAY_SHIFT 6
# define PV_VCONTROL_ODD_FIRST BIT(5) # define PV_VCONTROL_ODD_FIRST BIT(5)
# define PV_VCONTROL_INTERLACE BIT(4) # define PV_VCONTROL_INTERLACE BIT(4)
# define PV_VCONTROL_DSI BIT(3)
# define PV_VCONTROL_COMMAND BIT(2)
# define PV_VCONTROL_CONTINUOUS BIT(1) # define PV_VCONTROL_CONTINUOUS BIT(1)
# define PV_VCONTROL_VIDEN BIT(0) # define PV_VCONTROL_VIDEN BIT(0)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册