Skip to content

Commit

Permalink
drm: sti: add Compositor
Browse files Browse the repository at this point in the history
Compositor control all the input sub-device (VID, GDP)
and the mixer(s).
It is the main entry point for composition.
Layer interface is used to control the abstracted layers.

Add debug in mixer and GDP.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Reviewed-by: Rob Clark <robdclark@gmail.com>
  • Loading branch information
Benjamin Gaignard committed Jul 30, 2014
1 parent e21e219 commit d219673
Show file tree
Hide file tree
Showing 7 changed files with 566 additions and 1 deletion.
1 change: 1 addition & 0 deletions drivers/gpu/drm/sti/Kconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
config DRM_STI
tristate "DRM Support for STMicroelectronics SoC stiH41x Series"
depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM)
select DRM_KMS_CMA_HELPER
help
Choose this option to enable DRM on STM stiH41x chipset
4 changes: 3 additions & 1 deletion drivers/gpu/drm/sti/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
sticompositor-y := \
sti_layer.o \
sti_mixer.o \
sti_gdp.o \
sti_vid.o
sti_vid.o \
sti_compositor.o

stihdmi-y := sti_hdmi.o \
sti_hdmi_tx3g0c55phy.o \
Expand Down
236 changes: 236 additions & 0 deletions drivers/gpu/drm/sti/sti_compositor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/

#include <linux/component.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset.h>

#include <drm/drmP.h>

#include "sti_compositor.h"
#include "sti_gdp.h"
#include "sti_vtg.h"

/*
* stiH407 compositor properties
*/
struct sti_compositor_data stih407_compositor_data = {
.nb_subdev = 6,
.subdev_desc = {
{STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100},
{STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200},
{STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300},
{STI_GPD_SUBDEV, (int)STI_GDP_3, 0x400},
{STI_VID_SUBDEV, (int)STI_VID_0, 0x700},
{STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00}
},
};

/*
* stiH416 compositor properties
* Note:
* on stih416 MIXER_AUX has a different base address from MIXER_MAIN
* Moreover, GDPx is different for Main and Aux Mixer. So this subdev map does
* not fit for stiH416 if we want to enable the MIXER_AUX.
*/
struct sti_compositor_data stih416_compositor_data = {
.nb_subdev = 3,
.subdev_desc = {
{STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100},
{STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200},
{STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00}
},
};

static int sti_compositor_init_subdev(struct sti_compositor *compo,
struct sti_compositor_subdev_descriptor *desc,
unsigned int array_size)
{
unsigned int i, mixer_id = 0, layer_id = 0;

for (i = 0; i < array_size; i++) {
switch (desc[i].type) {
case STI_MIXER_MAIN_SUBDEV:
case STI_MIXER_AUX_SUBDEV:
compo->mixer[mixer_id++] =
sti_mixer_create(compo->dev, desc[i].id,
compo->regs + desc[i].offset);
break;
case STI_GPD_SUBDEV:
case STI_VID_SUBDEV:
compo->layer[layer_id++] =
sti_layer_create(compo->dev, desc[i].id,
compo->regs + desc[i].offset);
break;
/* case STI_CURSOR_SUBDEV : TODO */
default:
DRM_ERROR("Unknow subdev compoment type\n");
return 1;
}

}
compo->nb_mixers = mixer_id;
compo->nb_layers = layer_id;

return 0;
}

static int sti_compositor_bind(struct device *dev, struct device *master,
void *data)
{
struct sti_compositor *compo = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
unsigned int i, crtc = 0, plane = 0;

drm_vblank_init(drm_dev, crtc);
/* Allow usage of vblank without having to call drm_irq_install */
drm_dev->irq_enabled = 1;


DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n",
crtc, plane);
DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n");

return 0;
}

static void sti_compositor_unbind(struct device *dev, struct device *master,
void *data)
{
/* do nothing */
}

static const struct component_ops sti_compositor_ops = {
.bind = sti_compositor_bind,
.unbind = sti_compositor_unbind,
};

static const struct of_device_id compositor_of_match[] = {
{
.compatible = "st,stih416-compositor",
.data = &stih416_compositor_data,
}, {
.compatible = "st,stih407-compositor",
.data = &stih407_compositor_data,
}, {
/* end node */
}
};
MODULE_DEVICE_TABLE(of, compositor_of_match);

static int sti_compositor_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *vtg_np;
struct sti_compositor *compo;
struct resource *res;
int err;

compo = devm_kzalloc(dev, sizeof(*compo), GFP_KERNEL);
if (!compo) {
DRM_ERROR("Failed to allocate compositor context\n");
return -ENOMEM;
}
compo->dev = dev;

/* populate data structure depending on compatibility */
BUG_ON(!of_match_node(compositor_of_match, np)->data);

memcpy(&compo->data, of_match_node(compositor_of_match, np)->data,
sizeof(struct sti_compositor_data));

/* Get Memory ressources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
DRM_ERROR("Get memory resource failed\n");
return -ENXIO;
}
compo->regs = devm_ioremap(dev, res->start, resource_size(res));
if (compo->regs == NULL) {
DRM_ERROR("Register mapping failed\n");
return -ENXIO;
}

/* Get clock resources */
compo->clk_compo_main = devm_clk_get(dev, "compo_main");
if (IS_ERR(compo->clk_compo_main)) {
DRM_ERROR("Cannot get compo_main clock\n");
return PTR_ERR(compo->clk_compo_main);
}

compo->clk_compo_aux = devm_clk_get(dev, "compo_aux");
if (IS_ERR(compo->clk_compo_aux)) {
DRM_ERROR("Cannot get compo_aux clock\n");
return PTR_ERR(compo->clk_compo_aux);
}

compo->clk_pix_main = devm_clk_get(dev, "pix_main");
if (IS_ERR(compo->clk_pix_main)) {
DRM_ERROR("Cannot get pix_main clock\n");
return PTR_ERR(compo->clk_pix_main);
}

compo->clk_pix_aux = devm_clk_get(dev, "pix_aux");
if (IS_ERR(compo->clk_pix_aux)) {
DRM_ERROR("Cannot get pix_aux clock\n");
return PTR_ERR(compo->clk_pix_aux);
}

/* Get reset resources */
compo->rst_main = devm_reset_control_get(dev, "compo-main");
/* Take compo main out of reset */
if (!IS_ERR(compo->rst_main))
reset_control_deassert(compo->rst_main);

compo->rst_aux = devm_reset_control_get(dev, "compo-aux");
/* Take compo aux out of reset */
if (!IS_ERR(compo->rst_aux))
reset_control_deassert(compo->rst_aux);

vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 0);
if (vtg_np)
compo->vtg_main = of_vtg_find(vtg_np);

vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 1);
if (vtg_np)
compo->vtg_aux = of_vtg_find(vtg_np);

/* Initialize compositor subdevices */
err = sti_compositor_init_subdev(compo, compo->data.subdev_desc,
compo->data.nb_subdev);
if (err)
return err;

platform_set_drvdata(pdev, compo);

return component_add(&pdev->dev, &sti_compositor_ops);
}

static int sti_compositor_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &sti_compositor_ops);
return 0;
}

static struct platform_driver sti_compositor_driver = {
.driver = {
.name = "sti-compositor",
.owner = THIS_MODULE,
.of_match_table = compositor_of_match,
},
.probe = sti_compositor_probe,
.remove = sti_compositor_remove,
};

module_platform_driver(sti_compositor_driver);

MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
90 changes: 90 additions & 0 deletions drivers/gpu/drm/sti/sti_compositor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/

#ifndef _STI_COMPOSITOR_H_
#define _STI_COMPOSITOR_H_

#include <linux/clk.h>
#include <linux/kernel.h>

#include "sti_layer.h"
#include "sti_mixer.h"

#define WAIT_NEXT_VSYNC_MS 50 /*ms*/

#define STI_MAX_LAYER 8
#define STI_MAX_MIXER 2

enum sti_compositor_subdev_type {
STI_MIXER_MAIN_SUBDEV,
STI_MIXER_AUX_SUBDEV,
STI_GPD_SUBDEV,
STI_VID_SUBDEV,
STI_CURSOR_SUBDEV,
};

struct sti_compositor_subdev_descriptor {
enum sti_compositor_subdev_type type;
int id;
unsigned int offset;
};

/**
* STI Compositor data structure
*
* @nb_subdev: number of subdevices supported by the compositor
* @subdev_desc: subdev list description
*/
#define MAX_SUBDEV 9
struct sti_compositor_data {
unsigned int nb_subdev;
struct sti_compositor_subdev_descriptor subdev_desc[MAX_SUBDEV];
};

/**
* STI Compositor structure
*
* @dev: driver device
* @regs: registers (main)
* @data: device data
* @clk_compo_main: clock for main compo
* @clk_compo_aux: clock for aux compo
* @clk_pix_main: pixel clock for main path
* @clk_pix_aux: pixel clock for aux path
* @rst_main: reset control of the main path
* @rst_aux: reset control of the aux path
* @mixer: array of mixers
* @vtg_main: vtg for main data path
* @vtg_aux: vtg for auxillary data path
* @layer: array of layers
* @nb_mixers: number of mixers 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
*/
struct sti_compositor {
struct device *dev;
void __iomem *regs;
struct sti_compositor_data data;
struct clk *clk_compo_main;
struct clk *clk_compo_aux;
struct clk *clk_pix_main;
struct clk *clk_pix_aux;
struct reset_control *rst_main;
struct reset_control *rst_aux;
struct sti_mixer *mixer[STI_MAX_MIXER];
struct sti_vtg *vtg_main;
struct sti_vtg *vtg_aux;
struct sti_layer *layer[STI_MAX_LAYER];
int nb_mixers;
int nb_layers;
bool enable;
struct notifier_block vtg_vblank_nb;
};

#endif
Loading

0 comments on commit d219673

Please sign in to comment.