Commit 5e03abc5 authored by Benjamin Gaignard's avatar Benjamin Gaignard

drm: sti: enable auxiliary CRTC

For stih407 SoC enable the second mixer to get two CRTC.
Allow GPD planes and encoders to be connected to this new CRTC.
Cursor plane can only be set on first CRTC.
GPD clocks needed change the parent clock depending on which
CRTC GPD are used.
Signed-off-by: default avatarBenjamin Gaignard <benjamin.gaignard@linaro.org>
parent 7f2d479c
...@@ -24,14 +24,15 @@ ...@@ -24,14 +24,15 @@
* stiH407 compositor properties * stiH407 compositor properties
*/ */
struct sti_compositor_data stih407_compositor_data = { struct sti_compositor_data stih407_compositor_data = {
.nb_subdev = 6, .nb_subdev = 7,
.subdev_desc = { .subdev_desc = {
{STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100}, {STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100},
{STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200}, {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200},
{STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300}, {STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300},
{STI_GPD_SUBDEV, (int)STI_GDP_3, 0x400}, {STI_GPD_SUBDEV, (int)STI_GDP_3, 0x400},
{STI_VID_SUBDEV, (int)STI_VID_0, 0x700}, {STI_VID_SUBDEV, (int)STI_VID_0, 0x700},
{STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00} {STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00},
{STI_MIXER_AUX_SUBDEV, STI_MIXER_AUX, 0xD00},
}, },
}; };
...@@ -102,21 +103,21 @@ static int sti_compositor_bind(struct device *dev, struct device *master, ...@@ -102,21 +103,21 @@ static int sti_compositor_bind(struct device *dev, struct device *master,
enum sti_layer_type type = desc & STI_LAYER_TYPE_MASK; enum sti_layer_type type = desc & STI_LAYER_TYPE_MASK;
enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY; enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY;
if (compo->mixer[crtc]) if (crtc < compo->nb_mixers)
plane_type = DRM_PLANE_TYPE_PRIMARY; plane_type = DRM_PLANE_TYPE_PRIMARY;
switch (type) { switch (type) {
case STI_CUR: case STI_CUR:
cursor = sti_drm_plane_init(drm_dev, cursor = sti_drm_plane_init(drm_dev,
compo->layer[i], compo->layer[i],
(1 << crtc) - 1, 1, DRM_PLANE_TYPE_CURSOR);
DRM_PLANE_TYPE_CURSOR);
break; break;
case STI_GDP: case STI_GDP:
case STI_VID: case STI_VID:
primary = sti_drm_plane_init(drm_dev, primary = sti_drm_plane_init(drm_dev,
compo->layer[i], compo->layer[i],
(1 << crtc) - 1, plane_type); (1 << compo->nb_mixers) - 1,
plane_type);
plane++; plane++;
break; break;
case STI_BCK: case STI_BCK:
...@@ -124,7 +125,7 @@ static int sti_compositor_bind(struct device *dev, struct device *master, ...@@ -124,7 +125,7 @@ static int sti_compositor_bind(struct device *dev, struct device *master,
} }
/* The first planes are reserved for primary planes*/ /* The first planes are reserved for primary planes*/
if (compo->mixer[crtc]) { if (crtc < compo->nb_mixers) {
sti_drm_crtc_init(drm_dev, compo->mixer[crtc], sti_drm_crtc_init(drm_dev, compo->mixer[crtc],
primary, cursor); primary, cursor);
crtc++; crtc++;
......
...@@ -64,7 +64,6 @@ struct sti_compositor_data { ...@@ -64,7 +64,6 @@ struct sti_compositor_data {
* @layer: array of layers * @layer: array of layers
* @nb_mixers: number of mixers for this compositor * @nb_mixers: number of mixers for this compositor
* @nb_layers: number of layers (GDP,VID,...) for this compositor * @nb_layers: number of layers (GDP,VID,...) for this compositor
* @enable: true if compositor is enable else false
* @vtg_vblank_nb: callback for VTG VSYNC notification * @vtg_vblank_nb: callback for VTG VSYNC notification
*/ */
struct sti_compositor { struct sti_compositor {
...@@ -83,7 +82,6 @@ struct sti_compositor { ...@@ -83,7 +82,6 @@ struct sti_compositor {
struct sti_layer *layer[STI_MAX_LAYER]; struct sti_layer *layer[STI_MAX_LAYER];
int nb_mixers; int nb_mixers;
int nb_layers; int nb_layers;
bool enable;
struct notifier_block vtg_vblank_nb; struct notifier_block vtg_vblank_nb;
}; };
......
...@@ -28,7 +28,7 @@ static void sti_drm_crtc_prepare(struct drm_crtc *crtc) ...@@ -28,7 +28,7 @@ static void sti_drm_crtc_prepare(struct drm_crtc *crtc)
struct device *dev = mixer->dev; struct device *dev = mixer->dev;
struct sti_compositor *compo = dev_get_drvdata(dev); struct sti_compositor *compo = dev_get_drvdata(dev);
compo->enable = true; mixer->enabled = true;
/* Prepare and enable the compo IP clock */ /* Prepare and enable the compo IP clock */
if (mixer->id == STI_MIXER_MAIN) { if (mixer->id == STI_MIXER_MAIN) {
...@@ -200,7 +200,7 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc) ...@@ -200,7 +200,7 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
struct sti_compositor *compo = dev_get_drvdata(dev); struct sti_compositor *compo = dev_get_drvdata(dev);
struct sti_layer *layer; struct sti_layer *layer;
if (!compo->enable) if (!mixer->enabled)
return; return;
DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
...@@ -237,7 +237,7 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc) ...@@ -237,7 +237,7 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
clk_disable_unprepare(compo->clk_compo_aux); clk_disable_unprepare(compo->clk_compo_aux);
} }
compo->enable = false; mixer->enabled = false;
} }
static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
...@@ -399,6 +399,7 @@ bool sti_drm_crtc_is_main(struct drm_crtc *crtc) ...@@ -399,6 +399,7 @@ bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
return false; return false;
} }
EXPORT_SYMBOL(sti_drm_crtc_is_main);
int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
struct drm_plane *primary, struct drm_plane *cursor) struct drm_plane *primary, struct drm_plane *cursor)
......
...@@ -83,6 +83,8 @@ struct sti_gdp_node_list { ...@@ -83,6 +83,8 @@ struct sti_gdp_node_list {
* *
* @layer: layer structure * @layer: layer structure
* @clk_pix: pixel clock for the current gdp * @clk_pix: pixel clock for the current gdp
* @clk_main_parent: gdp parent clock if main path used
* @clk_aux_parent: gdp parent clock if aux path used
* @vtg_field_nb: callback for VTG FIELD (top or bottom) notification * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification
* @is_curr_top: true if the current node processed is the top field * @is_curr_top: true if the current node processed is the top field
* @node_list: array of node list * @node_list: array of node list
...@@ -90,6 +92,8 @@ struct sti_gdp_node_list { ...@@ -90,6 +92,8 @@ struct sti_gdp_node_list {
struct sti_gdp { struct sti_gdp {
struct sti_layer layer; struct sti_layer layer;
struct clk *clk_pix; struct clk *clk_pix;
struct clk *clk_main_parent;
struct clk *clk_aux_parent;
struct notifier_block vtg_field_nb; struct notifier_block vtg_field_nb;
bool is_curr_top; bool is_curr_top;
struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK]; struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK];
...@@ -307,6 +311,17 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) ...@@ -307,6 +311,17 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare)
/* Set and enable gdp clock */ /* Set and enable gdp clock */
if (gdp->clk_pix) { if (gdp->clk_pix) {
struct clk *clkp;
/* According to the mixer used, the gdp pixel clock
* should have a different parent clock. */
if (layer->mixer_id == STI_MIXER_MAIN)
clkp = gdp->clk_main_parent;
else
clkp = gdp->clk_aux_parent;
if (clkp)
clk_set_parent(gdp->clk_pix, clkp);
res = clk_set_rate(gdp->clk_pix, rate); res = clk_set_rate(gdp->clk_pix, rate);
if (res < 0) { if (res < 0) {
DRM_ERROR("Cannot set rate (%dHz) for gdp\n", DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
...@@ -521,6 +536,14 @@ static void sti_gdp_init(struct sti_layer *layer) ...@@ -521,6 +536,14 @@ static void sti_gdp_init(struct sti_layer *layer)
gdp->clk_pix = devm_clk_get(layer->dev, clk_name); gdp->clk_pix = devm_clk_get(layer->dev, clk_name);
if (IS_ERR(gdp->clk_pix)) if (IS_ERR(gdp->clk_pix))
DRM_ERROR("Cannot get %s clock\n", clk_name); DRM_ERROR("Cannot get %s clock\n", clk_name);
gdp->clk_main_parent = devm_clk_get(layer->dev, "main_parent");
if (IS_ERR(gdp->clk_main_parent))
DRM_ERROR("Cannot get main_parent clock\n");
gdp->clk_aux_parent = devm_clk_get(layer->dev, "aux_parent");
if (IS_ERR(gdp->clk_aux_parent))
DRM_ERROR("Cannot get aux_parent clock\n");
} }
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
* @id: id of the mixer * @id: id of the mixer
* @drm_crtc: crtc object link to the mixer * @drm_crtc: crtc object link to the mixer
* @pending_event: set if a flip event is pending on crtc * @pending_event: set if a flip event is pending on crtc
* @enabled: to know if the mixer is active or not
*/ */
struct sti_mixer { struct sti_mixer {
struct device *dev; struct device *dev;
...@@ -30,6 +31,7 @@ struct sti_mixer { ...@@ -30,6 +31,7 @@ struct sti_mixer {
int id; int id;
struct drm_crtc drm_crtc; struct drm_crtc drm_crtc;
struct drm_pending_vblank_event *pending_event; struct drm_pending_vblank_event *pending_event;
bool enabled;
}; };
const char *sti_mixer_to_str(struct sti_mixer *mixer); const char *sti_mixer_to_str(struct sti_mixer *mixer);
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include "sti_drm_crtc.h"
/* glue registers */ /* glue registers */
#define TVO_CSC_MAIN_M0 0x000 #define TVO_CSC_MAIN_M0 0x000
#define TVO_CSC_MAIN_M1 0x004 #define TVO_CSC_MAIN_M1 0x004
...@@ -96,7 +98,7 @@ ...@@ -96,7 +98,7 @@
#define TVO_SYNC_HD_DCS_SHIFT 8 #define TVO_SYNC_HD_DCS_SHIFT 8
#define ENCODER_MAIN_CRTC_MASK BIT(0) #define ENCODER_CRTC_MASK (BIT(0) | BIT(1))
/* enum listing the supported output data format */ /* enum listing the supported output data format */
enum sti_tvout_video_out_type { enum sti_tvout_video_out_type {
...@@ -404,7 +406,7 @@ static void sti_hda_encoder_commit(struct drm_encoder *encoder) ...@@ -404,7 +406,7 @@ static void sti_hda_encoder_commit(struct drm_encoder *encoder)
{ {
struct sti_tvout *tvout = to_sti_tvout(encoder); struct sti_tvout *tvout = to_sti_tvout(encoder);
tvout_hda_start(tvout, true); tvout_hda_start(tvout, sti_drm_crtc_is_main(encoder->crtc));
} }
static void sti_hda_encoder_disable(struct drm_encoder *encoder) static void sti_hda_encoder_disable(struct drm_encoder *encoder)
...@@ -441,7 +443,7 @@ static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev, ...@@ -441,7 +443,7 @@ static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev,
drm_encoder = (struct drm_encoder *) encoder; drm_encoder = (struct drm_encoder *) encoder;
drm_encoder->possible_crtcs = ENCODER_MAIN_CRTC_MASK; drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
drm_encoder->possible_clones = 1 << 0; drm_encoder->possible_clones = 1 << 0;
drm_encoder_init(dev, drm_encoder, drm_encoder_init(dev, drm_encoder,
...@@ -456,7 +458,7 @@ static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) ...@@ -456,7 +458,7 @@ static void sti_hdmi_encoder_commit(struct drm_encoder *encoder)
{ {
struct sti_tvout *tvout = to_sti_tvout(encoder); struct sti_tvout *tvout = to_sti_tvout(encoder);
tvout_hdmi_start(tvout, true); tvout_hdmi_start(tvout, sti_drm_crtc_is_main(encoder->crtc));
} }
static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) static void sti_hdmi_encoder_disable(struct drm_encoder *encoder)
...@@ -490,7 +492,7 @@ static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev, ...@@ -490,7 +492,7 @@ static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev,
drm_encoder = (struct drm_encoder *) encoder; drm_encoder = (struct drm_encoder *) encoder;
drm_encoder->possible_crtcs = ENCODER_MAIN_CRTC_MASK; drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
drm_encoder->possible_clones = 1 << 1; drm_encoder->possible_clones = 1 << 1;
drm_encoder_init(dev, drm_encoder, drm_encoder_init(dev, drm_encoder,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment