Commit f20780f3 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-sti-next-2015-11-03' of...

Merge branch 'drm-sti-next-2015-11-03' of http://git.linaro.org/people/benjamin.gaignard/kernel into drm-next

sti/drm changes

Add better support for firmware loading
lots of fixes.

* 'drm-sti-next-2015-11-03' of http://git.linaro.org/people/benjamin.gaignard/kernel:
  drm/sti: load HQVDP firmware the first time HQVDP's plane is used
  drm/sti: fix typo issue in sti_mode_config_init
  drm/sti: set mixer background color through module param
  drm/sti: Remove local fbdev emulation Kconfig option
  drm/sti: remove redundant sign extensions
  drm/sti: hdmi use of_get_i2c_adapter_by_node interface
  drm/sti: hdmi fix i2c adapter device refcounting
  drm/sti: Do not export symbols
  drm/sti: Build monolithic driver
  drm/sti: Use drm_crtc_vblank_*() API
  drm/sti: Store correct CRTC index in events
  drm/sti: Select FW_LOADER
  drm/sti: Constify function pointer structs
parents a18e2fa5 e00fe64a
......@@ -6,12 +6,6 @@ config DRM_STI
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
select DRM_PANEL
select FW_LOADER_USER_HELPER_FALLBACK
select FW_LOADER
help
Choose this option to enable DRM on STM stiH41x chipset
config DRM_STI_FBDEV
bool "DRM frame buffer device for STMicroelectronics SoC stiH41x Serie"
depends on DRM_STI
help
Choose this option to enable FBDEV on top of DRM for STM stiH41x chipset
sticompositor-y := \
sti-drm-y := \
sti_mixer.o \
sti_gdp.o \
sti_vid.o \
sti_cursor.o \
sti_compositor.o \
sti_crtc.o \
sti_plane.o
stihdmi-y := sti_hdmi.o \
sti_plane.o \
sti_crtc.o \
sti_plane.o \
sti_hdmi.o \
sti_hdmi_tx3g0c55phy.o \
sti_hdmi_tx3g4c28phy.o \
stidvo-y := sti_dvo.o \
sti_awg_utils.o
obj-$(CONFIG_DRM_STI) = \
sti_dvo.o \
sti_awg_utils.o \
sti_vtg.o \
sti_vtac.o \
stihdmi.o \
sti_hda.o \
sti_tvout.o \
sticompositor.o \
sti_hqvdp.o \
stidvo.o \
sti_drv.o
obj-$(CONFIG_DRM_STI) = sti-drm.o
......@@ -65,7 +65,6 @@ static int awg_generate_instr(enum opcode opcode,
mux = 0;
data_enable = 0;
arg = (arg << 22) >> 22;
arg &= (0x3ff);
break;
case REPEAT:
......@@ -77,14 +76,12 @@ static int awg_generate_instr(enum opcode opcode,
mux = 0;
data_enable = 0;
arg = (arg << 22) >> 22;
arg &= (0x3ff);
break;
case JUMP:
mux = 0;
data_enable = 0;
arg |= 0x40; /* for jump instruction 7th bit is 1 */
arg = (arg << 22) >> 22;
arg &= 0x3ff;
break;
case STOP:
......@@ -94,7 +91,6 @@ static int awg_generate_instr(enum opcode opcode,
case RPTSET:
case RPLSET:
case HOLD:
arg = (arg << 24) >> 24;
arg &= (0x0ff);
break;
default:
......
......@@ -263,7 +263,7 @@ static int sti_compositor_remove(struct platform_device *pdev)
return 0;
}
static struct platform_driver sti_compositor_driver = {
struct platform_driver sti_compositor_driver = {
.driver = {
.name = "sti-compositor",
.of_match_table = compositor_of_match,
......@@ -272,8 +272,6 @@ static struct platform_driver sti_compositor_driver = {
.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");
......@@ -226,7 +226,7 @@ static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
}
}
static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
.enable = sti_crtc_enable,
.disable = sti_crtc_disabling,
.mode_fixup = sti_crtc_mode_fixup,
......@@ -254,15 +254,17 @@ static int sti_crtc_set_property(struct drm_crtc *crtc,
int sti_crtc_vblank_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
struct drm_device *drm_dev;
struct sti_compositor *compo =
container_of(nb, struct sti_compositor, vtg_vblank_nb);
int *crtc = data;
struct drm_crtc *crtc = data;
struct sti_mixer *mixer;
unsigned long flags;
struct sti_private *priv;
unsigned int pipe;
drm_dev = compo->mixer[*crtc]->drm_crtc.dev;
priv = drm_dev->dev_private;
priv = crtc->dev->dev_private;
pipe = drm_crtc_index(crtc);
mixer = compo->mixer[pipe];
if ((event != VTG_TOP_FIELD_EVENT) &&
(event != VTG_BOTTOM_FIELD_EVENT)) {
......@@ -270,30 +272,30 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
return -EINVAL;
}
drm_handle_vblank(drm_dev, *crtc);
drm_crtc_handle_vblank(crtc);
spin_lock_irqsave(&drm_dev->event_lock, flags);
if (compo->mixer[*crtc]->pending_event) {
drm_send_vblank_event(drm_dev, -1,
compo->mixer[*crtc]->pending_event);
drm_vblank_put(drm_dev, *crtc);
compo->mixer[*crtc]->pending_event = NULL;
spin_lock_irqsave(&crtc->dev->event_lock, flags);
if (mixer->pending_event) {
drm_crtc_send_vblank_event(crtc, mixer->pending_event);
drm_crtc_vblank_put(crtc);
mixer->pending_event = NULL;
}
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) {
if (mixer->status == STI_MIXER_DISABLING) {
struct drm_plane *p;
/* Disable mixer only if all overlay planes (GDP and VDP)
* are disabled */
list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
list_for_each_entry(p, &crtc->dev->mode_config.plane_list,
head) {
struct sti_plane *plane = to_sti_plane(p);
if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
if (plane->status != STI_PLANE_DISABLED)
return 0;
}
sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
sti_crtc_disable(crtc);
}
return 0;
......@@ -304,25 +306,26 @@ int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
struct sti_private *dev_priv = dev->dev_private;
struct sti_compositor *compo = dev_priv->compo;
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
DRM_DEBUG_DRIVER("\n");
if (sti_vtg_register_client(pipe == STI_MIXER_MAIN ?
compo->vtg_main : compo->vtg_aux,
vtg_vblank_nb, pipe)) {
vtg_vblank_nb, crtc)) {
DRM_ERROR("Cannot register VTG notifier\n");
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(sti_crtc_enable_vblank);
void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
{
struct sti_private *priv = drm_dev->dev_private;
struct sti_compositor *compo = priv->compo;
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
DRM_DEBUG_DRIVER("\n");
......@@ -332,13 +335,12 @@ void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
/* free the resources of the pending requests */
if (compo->mixer[pipe]->pending_event) {
drm_vblank_put(drm_dev, pipe);
drm_crtc_vblank_put(crtc);
compo->mixer[pipe]->pending_event = NULL;
}
}
EXPORT_SYMBOL(sti_crtc_disable_vblank);
static struct drm_crtc_funcs sti_crtc_funcs = {
static const struct drm_crtc_funcs sti_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.destroy = sti_crtc_destroy,
......@@ -357,7 +359,6 @@ bool sti_crtc_is_main(struct drm_crtc *crtc)
return false;
}
EXPORT_SYMBOL(sti_crtc_is_main);
int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
struct drm_plane *primary, struct drm_plane *cursor)
......
......@@ -107,7 +107,7 @@ static int sti_atomic_commit(struct drm_device *drm,
return 0;
}
static struct drm_mode_config_funcs sti_mode_config_funcs = {
static const struct drm_mode_config_funcs sti_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = sti_atomic_commit,
......@@ -123,8 +123,8 @@ static void sti_mode_config_init(struct drm_device *dev)
* this value would be used to check framebuffer size limitation
* at drm_mode_addfb().
*/
dev->mode_config.max_width = STI_MAX_FB_HEIGHT;
dev->mode_config.max_height = STI_MAX_FB_WIDTH;
dev->mode_config.max_width = STI_MAX_FB_WIDTH;
dev->mode_config.max_height = STI_MAX_FB_HEIGHT;
dev->mode_config.funcs = &sti_mode_config_funcs;
}
......@@ -160,11 +160,10 @@ static int sti_load(struct drm_device *dev, unsigned long flags)
drm_mode_config_reset(dev);
#ifdef CONFIG_DRM_STI_FBDEV
drm_fbdev_cma_init(dev, 32,
dev->mode_config.num_crtc,
dev->mode_config.num_connector);
#endif
return 0;
}
......@@ -287,7 +286,29 @@ static struct platform_driver sti_platform_driver = {
},
};
module_platform_driver(sti_platform_driver);
static struct platform_driver * const drivers[] = {
&sti_tvout_driver,
&sti_vtac_driver,
&sti_hqvdp_driver,
&sti_hdmi_driver,
&sti_hda_driver,
&sti_dvo_driver,
&sti_vtg_driver,
&sti_compositor_driver,
&sti_platform_driver,
};
static int sti_drm_init(void)
{
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(sti_drm_init);
static void sti_drm_exit(void)
{
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(sti_drm_exit);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
......
......@@ -32,4 +32,13 @@ struct sti_private {
} commit;
};
extern struct platform_driver sti_tvout_driver;
extern struct platform_driver sti_vtac_driver;
extern struct platform_driver sti_hqvdp_driver;
extern struct platform_driver sti_hdmi_driver;
extern struct platform_driver sti_hda_driver;
extern struct platform_driver sti_dvo_driver;
extern struct platform_driver sti_vtg_driver;
extern struct platform_driver sti_compositor_driver;
#endif
......@@ -329,7 +329,8 @@ struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector)
return dvo_connector->encoder;
}
static struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = {
static const
struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = {
.get_modes = sti_dvo_connector_get_modes,
.mode_valid = sti_dvo_connector_mode_valid,
.best_encoder = sti_dvo_best_encoder,
......@@ -364,7 +365,7 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector)
kfree(dvo_connector);
}
static struct drm_connector_funcs sti_dvo_connector_funcs = {
static const struct drm_connector_funcs sti_dvo_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_dvo_connector_detect,
......@@ -557,8 +558,6 @@ struct platform_driver sti_dvo_driver = {
.remove = sti_dvo_remove,
};
module_platform_driver(sti_dvo_driver);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
......@@ -492,7 +492,7 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
/* Register gdp callback */
if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ?
compo->vtg_main : compo->vtg_aux,
&gdp->vtg_field_nb, mixer->id)) {
&gdp->vtg_field_nb, crtc)) {
DRM_ERROR("Cannot register VTG notifier\n");
return;
}
......
......@@ -589,7 +589,8 @@ struct drm_encoder *sti_hda_best_encoder(struct drm_connector *connector)
return hda_connector->encoder;
}
static struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = {
static const
struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = {
.get_modes = sti_hda_connector_get_modes,
.mode_valid = sti_hda_connector_mode_valid,
.best_encoder = sti_hda_best_encoder,
......@@ -611,7 +612,7 @@ static void sti_hda_connector_destroy(struct drm_connector *connector)
kfree(hda_connector);
}
static struct drm_connector_funcs sti_hda_connector_funcs = {
static const struct drm_connector_funcs sti_hda_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_hda_connector_detect,
......@@ -784,8 +785,6 @@ struct platform_driver sti_hda_driver = {
.remove = sti_hda_remove,
};
module_platform_driver(sti_hda_driver);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
......@@ -628,7 +628,8 @@ struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector)
return hdmi_connector->encoder;
}
static struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = {
static const
struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = {
.get_modes = sti_hdmi_connector_get_modes,
.mode_valid = sti_hdmi_connector_mode_valid,
.best_encoder = sti_hdmi_best_encoder,
......@@ -663,7 +664,7 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector)
kfree(hdmi_connector);
}
static struct drm_connector_funcs sti_hdmi_connector_funcs = {
static const struct drm_connector_funcs sti_hdmi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_hdmi_connector_detect,
......@@ -700,18 +701,17 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
encoder = sti_hdmi_find_encoder(drm_dev);
if (!encoder)
goto err_adapt;
return -EINVAL;
connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
if (!connector)
goto err_adapt;
return -EINVAL;
connector->hdmi = hdmi;
bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
if (!bridge)
goto err_adapt;
return -EINVAL;
bridge->driver_private = hdmi;
bridge->funcs = &sti_hdmi_bridge_funcs;
......@@ -748,8 +748,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
drm_connector_unregister(drm_connector);
err_connector:
drm_connector_cleanup(drm_connector);
err_adapt:
put_device(&hdmi->ddc_adapt->dev);
return -EINVAL;
}
......@@ -794,39 +793,41 @@ static int sti_hdmi_probe(struct platform_device *pdev)
ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0);
if (ddc) {
hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc);
if (!hdmi->ddc_adapt) {
hdmi->ddc_adapt = of_get_i2c_adapter_by_node(ddc);
of_node_put(ddc);
if (!hdmi->ddc_adapt)
return -EPROBE_DEFER;
}
of_node_put(ddc);
}
hdmi->dev = pdev->dev;
/* Get resources */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg");
if (!res) {
DRM_ERROR("Invalid hdmi resource\n");
return -ENOMEM;
ret = -ENOMEM;
goto release_adapter;
}
hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!hdmi->regs)
return -ENOMEM;
if (!hdmi->regs) {
ret = -ENOMEM;
goto release_adapter;
}
if (of_device_is_compatible(np, "st,stih416-hdmi")) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"syscfg");
if (!res) {
DRM_ERROR("Invalid syscfg resource\n");
return -ENOMEM;
ret = -ENOMEM;
goto release_adapter;
}
hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
resource_size(res));
if (!hdmi->syscfg)
return -ENOMEM;
if (!hdmi->syscfg) {
ret = -ENOMEM;
goto release_adapter;
}
}
hdmi->phy_ops = (struct hdmi_phy_ops *)
......@@ -836,25 +837,29 @@ static int sti_hdmi_probe(struct platform_device *pdev)
hdmi->clk_pix = devm_clk_get(dev, "pix");
if (IS_ERR(hdmi->clk_pix)) {
DRM_ERROR("Cannot get hdmi_pix clock\n");
return PTR_ERR(hdmi->clk_pix);
ret = PTR_ERR(hdmi->clk_pix);
goto release_adapter;
}
hdmi->clk_tmds = devm_clk_get(dev, "tmds");
if (IS_ERR(hdmi->clk_tmds)) {
DRM_ERROR("Cannot get hdmi_tmds clock\n");
return PTR_ERR(hdmi->clk_tmds);
ret = PTR_ERR(hdmi->clk_tmds);
goto release_adapter;
}
hdmi->clk_phy = devm_clk_get(dev, "phy");
if (IS_ERR(hdmi->clk_phy)) {
DRM_ERROR("Cannot get hdmi_phy clock\n");
return PTR_ERR(hdmi->clk_phy);
ret = PTR_ERR(hdmi->clk_phy);
goto release_adapter;
}
hdmi->clk_audio = devm_clk_get(dev, "audio");
if (IS_ERR(hdmi->clk_audio)) {
DRM_ERROR("Cannot get hdmi_audio clock\n");
return PTR_ERR(hdmi->clk_audio);
ret = PTR_ERR(hdmi->clk_audio);
goto release_adapter;
}
hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG;
......@@ -867,7 +872,7 @@ static int sti_hdmi_probe(struct platform_device *pdev)
hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi);
if (ret) {
DRM_ERROR("Failed to register HDMI interrupt\n");
return ret;
goto release_adapter;
}
hdmi->reset = devm_reset_control_get(dev, "hdmi");
......@@ -878,16 +883,20 @@ static int sti_hdmi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hdmi);
return component_add(&pdev->dev, &sti_hdmi_ops);
release_adapter:
i2c_put_adapter(hdmi->ddc_adapt);
return ret;
}
static int sti_hdmi_remove(struct platform_device *pdev)
{
struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev);
if (hdmi->ddc_adapt)
put_device(&hdmi->ddc_adapt->dev);
i2c_put_adapter(hdmi->ddc_adapt);
component_del(&pdev->dev, &sti_hdmi_ops);
return 0;
}
......@@ -901,8 +910,6 @@ struct platform_driver sti_hdmi_driver = {
.remove = sti_hdmi_remove,
};
module_platform_driver(sti_hdmi_driver);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
......@@ -628,6 +628,153 @@ static void sti_hqvdp_init(struct sti_hqvdp *hqvdp)
memset(hqvdp->hqvdp_cmd, 0, size);
}
static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp)
{
/* Configure Plugs (same for RD & WR) */
writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_RD_PLUG_PAGE_SIZE);
writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_RD_PLUG_MIN_OPC);
writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_RD_PLUG_MAX_OPC);
writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_RD_PLUG_MAX_CHK);
writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_RD_PLUG_MAX_MSG);
writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_RD_PLUG_MIN_SPACE);
writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_RD_PLUG_CONTROL);
writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_WR_PLUG_PAGE_SIZE);
writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_WR_PLUG_MIN_OPC);
writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_WR_PLUG_MAX_OPC);
writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_WR_PLUG_MAX_CHK);
writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_WR_PLUG_MAX_MSG);
writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_WR_PLUG_MIN_SPACE);
writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_WR_PLUG_CONTROL);
}
/**
* sti_hqvdp_start_xp70
* @hqvdp: hqvdp pointer
*
* Run the xP70 initialization sequence
*/
static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp)
{
const struct firmware *firmware;
u32 *fw_rd_plug, *fw_wr_plug, *fw_pmem, *fw_dmem;
u8 *data;
int i;
struct fw_header {
int rd_size;
int wr_size;
int pmem_size;
int dmem_size;
} *header;
DRM_DEBUG_DRIVER("\n");
if (hqvdp->xp70_initialized) {
DRM_INFO("HQVDP XP70 already initialized\n");
return;
}
/* Request firmware */
if (request_firmware(&firmware, HQVDP_FMW_NAME, hqvdp->dev)) {
DRM_ERROR("Can't get HQVDP firmware\n");
return;
}
/* Check firmware parts */
if (!firmware) {
DRM_ERROR("Firmware not available\n");
return;
}
header = (struct fw_header *)firmware->data;
if (firmware->size < sizeof(*header)) {
DRM_ERROR("Invalid firmware size (%d)\n", firmware->size);
goto out;
}
if ((sizeof(*header) + header->rd_size + header->wr_size +
header->pmem_size + header->dmem_size) != firmware->size) {
DRM_ERROR("Invalid fmw structure (%d+%d+%d+%d+%d != %d)\n",
sizeof(*header), header->rd_size, header->wr_size,
header->pmem_size, header->dmem_size,
firmware->size);
goto out;
}
data = (u8 *)firmware->data;
data += sizeof(*header);
fw_rd_plug = (void *)data;
data += header->rd_size;
fw_wr_plug = (void *)data;
data += header->wr_size;
fw_pmem = (void *)data;
data += header->pmem_size;
fw_dmem = (void *)data;
/* Enable clock */
if (clk_prepare_enable(hqvdp->clk))
DRM_ERROR("Failed to prepare/enable HQVDP clk\n");
/* Reset */
writel(SW_RESET_CTRL_FULL, hqvdp->regs + HQVDP_MBX_SW_RESET_CTRL);
for (i = 0; i < POLL_MAX_ATTEMPT; i++) {
if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1)
& STARTUP_CTRL1_RST_DONE)
break;
msleep(POLL_DELAY_MS);
}
if (i == POLL_MAX_ATTEMPT) {
DRM_ERROR("Could not reset\n");
goto out;
}
/* Init Read & Write plugs */
for (i = 0; i < header->rd_size / 4; i++)
writel(fw_rd_plug[i], hqvdp->regs + HQVDP_RD_PLUG + i * 4);
for (i = 0; i < header->wr_size / 4; i++)
writel(fw_wr_plug[i], hqvdp->regs + HQVDP_WR_PLUG + i * 4);
sti_hqvdp_init_plugs(hqvdp);
/* Authorize Idle Mode */
writel(STARTUP_CTRL1_AUTH_IDLE, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1);
/* Prevent VTG interruption during the boot */
writel(SOFT_VSYNC_SW_CTRL_IRQ, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
writel(0, hqvdp->regs + HQVDP_MBX_NEXT_CMD);
/* Download PMEM & DMEM */
for (i = 0; i < header->pmem_size / 4; i++)
writel(fw_pmem[i], hqvdp->regs + HQVDP_PMEM + i * 4);
for (i = 0; i < header->dmem_size / 4; i++)
writel(fw_dmem[i], hqvdp->regs + HQVDP_DMEM + i * 4);
/* Enable fetch */
writel(STARTUP_CTRL2_FETCH_EN, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2);
/* Wait end of boot */
for (i = 0; i < POLL_MAX_ATTEMPT; i++) {
if (readl(hqvdp->regs + HQVDP_MBX_INFO_XP70)
& INFO_XP70_FW_READY)
break;
msleep(POLL_DELAY_MS);
}
if (i == POLL_MAX_ATTEMPT) {
DRM_ERROR("Could not boot\n");
goto out;
}
/* Launch Vsync */
writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
DRM_INFO("HQVDP XP70 initialized\n");
hqvdp->xp70_initialized = true;
out:
release_firmware(firmware);
}
static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate)
{
......@@ -754,6 +901,9 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
if (first_prepare) {
/* Start HQVDP XP70 coprocessor */
sti_hqvdp_start_xp70(hqvdp);
/* Prevent VTG shutdown */
if (clk_prepare_enable(hqvdp->clk_pix_main)) {
DRM_ERROR("Failed to prepare/enable pix main clk\n");
......@@ -763,7 +913,7 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
/* Register VTG Vsync callback to handle bottom fields */
if (sti_vtg_register_client(hqvdp->vtg,
&hqvdp->vtg_nb,
mixer->id)) {
crtc)) {
DRM_ERROR("Cannot register VTG notifier\n");
return;
}
......@@ -836,168 +986,16 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
return &hqvdp->plane.drm_plane;
}
static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp)
{
/* Configure Plugs (same for RD & WR) */
writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_RD_PLUG_PAGE_SIZE);
writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_RD_PLUG_MIN_OPC);
writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_RD_PLUG_MAX_OPC);
writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_RD_PLUG_MAX_CHK);
writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_RD_PLUG_MAX_MSG);
writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_RD_PLUG_MIN_SPACE);
writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_RD_PLUG_CONTROL);
writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_WR_PLUG_PAGE_SIZE);
writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_WR_PLUG_MIN_OPC);
writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_WR_PLUG_MAX_OPC);
writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_WR_PLUG_MAX_CHK);
writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_WR_PLUG_MAX_MSG);
writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_WR_PLUG_MIN_SPACE);
writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_WR_PLUG_CONTROL);
}
/**
* sti_hqvdp_start_xp70
* @firmware: firmware found
* @ctxt: hqvdp structure
*
* Run the xP70 initialization sequence
*/
static void sti_hqvdp_start_xp70(const struct firmware *firmware, void *ctxt)
{
struct sti_hqvdp *hqvdp = ctxt;
u32 *fw_rd_plug, *fw_wr_plug, *fw_pmem, *fw_dmem;
u8 *data;
int i;
struct fw_header {
int rd_size;
int wr_size;
int pmem_size;
int dmem_size;
} *header;
DRM_DEBUG_DRIVER("\n");
if (hqvdp->xp70_initialized) {
DRM_INFO("HQVDP XP70 already initialized\n");
return;
}
/* Check firmware parts */
if (!firmware) {
DRM_ERROR("Firmware not available\n");
return;
}
header = (struct fw_header *) firmware->data;
if (firmware->size < sizeof(*header)) {
DRM_ERROR("Invalid firmware size (%d)\n", firmware->size);
goto out;
}
if ((sizeof(*header) + header->rd_size + header->wr_size +
header->pmem_size + header->dmem_size) != firmware->size) {
DRM_ERROR("Invalid fmw structure (%d+%d+%d+%d+%d != %d)\n",
sizeof(*header), header->rd_size, header->wr_size,
header->pmem_size, header->dmem_size,
firmware->size);
goto out;
}
data = (u8 *) firmware->data;
data += sizeof(*header);
fw_rd_plug = (void *) data;
data += header->rd_size;
fw_wr_plug = (void *) data;
data += header->wr_size;
fw_pmem = (void *) data;
data += header->pmem_size;
fw_dmem = (void *) data;
/* Enable clock */
if (clk_prepare_enable(hqvdp->clk))
DRM_ERROR("Failed to prepare/enable HQVDP clk\n");
/* Reset */
writel(SW_RESET_CTRL_FULL, hqvdp->regs + HQVDP_MBX_SW_RESET_CTRL);
for (i = 0; i < POLL_MAX_ATTEMPT; i++) {
if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1)
& STARTUP_CTRL1_RST_DONE)
break;
msleep(POLL_DELAY_MS);
}
if (i == POLL_MAX_ATTEMPT) {
DRM_ERROR("Could not reset\n");
goto out;
}
/* Init Read & Write plugs */
for (i = 0; i < header->rd_size / 4; i++)
writel(fw_rd_plug[i], hqvdp->regs + HQVDP_RD_PLUG + i * 4);
for (i = 0; i < header->wr_size / 4; i++)
writel(fw_wr_plug[i], hqvdp->regs + HQVDP_WR_PLUG + i * 4);
sti_hqvdp_init_plugs(hqvdp);
/* Authorize Idle Mode */
writel(STARTUP_CTRL1_AUTH_IDLE, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1);
/* Prevent VTG interruption during the boot */
writel(SOFT_VSYNC_SW_CTRL_IRQ, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
writel(0, hqvdp->regs + HQVDP_MBX_NEXT_CMD);
/* Download PMEM & DMEM */
for (i = 0; i < header->pmem_size / 4; i++)
writel(fw_pmem[i], hqvdp->regs + HQVDP_PMEM + i * 4);
for (i = 0; i < header->dmem_size / 4; i++)
writel(fw_dmem[i], hqvdp->regs + HQVDP_DMEM + i * 4);
/* Enable fetch */
writel(STARTUP_CTRL2_FETCH_EN, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2);
/* Wait end of boot */
for (i = 0; i < POLL_MAX_ATTEMPT; i++) {
if (readl(hqvdp->regs + HQVDP_MBX_INFO_XP70)
& INFO_XP70_FW_READY)
break;
msleep(POLL_DELAY_MS);
}
if (i == POLL_MAX_ATTEMPT) {
DRM_ERROR("Could not boot\n");
goto out;
}
/* Launch Vsync */
writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
DRM_INFO("HQVDP XP70 initialized\n");
hqvdp->xp70_initialized = true;
out:
release_firmware(firmware);
}
int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
{
struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
struct drm_plane *plane;
int err;
DRM_DEBUG_DRIVER("\n");
hqvdp->drm_dev = drm_dev;
/* Request for firmware */
err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
HQVDP_FMW_NAME, hqvdp->dev,
GFP_KERNEL, hqvdp, sti_hqvdp_start_xp70);
if (err) {
DRM_ERROR("Can't get HQVDP firmware\n");
return err;
}
/* Create HQVDP plane once xp70 is initialized */
plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0);
if (!plane)
......@@ -1090,8 +1088,6 @@ struct platform_driver sti_hqvdp_driver = {
.remove = sti_hqvdp_remove,
};
module_platform_driver(sti_hqvdp_driver);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
......@@ -10,6 +10,11 @@
#include "sti_mixer.h"
#include "sti_vtg.h"
/* Module parameter to set the background color of the mixer */
static unsigned int bkg_color = 0x000000;
MODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB");
module_param_named(bkgcolor, bkg_color, int, 0644);
/* Identity: G=Y , B=Cb , R=Cr */
static const u32 mixerColorSpaceMatIdentity[] = {
0x10000000, 0x00000000, 0x10000000, 0x00001000,
......@@ -58,7 +63,6 @@ const char *sti_mixer_to_str(struct sti_mixer *mixer)
return "<UNKNOWN MIXER>";
}
}
EXPORT_SYMBOL(sti_mixer_to_str);
static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
{
......@@ -81,11 +85,9 @@ void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
}
static void sti_mixer_set_background_color(struct sti_mixer *mixer,
u8 red, u8 green, u8 blue)
unsigned int rgb)
{
u32 val = (red << 16) | (green << 8) | blue;
sti_mixer_reg_write(mixer, GAM_MIXER_BKC, val);
sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb);
}
static void sti_mixer_set_background_area(struct sti_mixer *mixer,
......@@ -175,7 +177,7 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer,
sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo);
sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
sti_mixer_set_background_color(mixer, 0xFF, 0, 0);
sti_mixer_set_background_color(mixer, bkg_color);
sti_mixer_set_background_area(mixer, mode);
sti_mixer_set_background_status(mixer, true);
......
......@@ -42,7 +42,6 @@ const char *sti_plane_to_str(struct sti_plane *plane)
return "<UNKNOWN PLANE>";
}
}
EXPORT_SYMBOL(sti_plane_to_str);
static void sti_plane_destroy(struct drm_plane *drm_plane)
{
......@@ -108,7 +107,6 @@ void sti_plane_init_property(struct sti_plane *plane,
plane->drm_plane.base.id,
sti_plane_to_str(plane), plane->zorder);
}
EXPORT_SYMBOL(sti_plane_init_property);
struct drm_plane_funcs sti_plane_helpers_funcs = {
.update_plane = drm_atomic_helper_update_plane,
......@@ -119,4 +117,3 @@ struct drm_plane_funcs sti_plane_helpers_funcs = {
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};
EXPORT_SYMBOL(sti_plane_helpers_funcs);
......@@ -735,8 +735,6 @@ struct platform_driver sti_tvout_driver = {
.remove = sti_tvout_remove,
};
module_platform_driver(sti_tvout_driver);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
......@@ -216,8 +216,6 @@ struct platform_driver sti_vtac_driver = {
.remove = sti_vtac_remove,
};
module_platform_driver(sti_vtac_driver);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
......@@ -79,7 +79,7 @@ LIST_HEAD(vtg_lookup);
* @irq: VTG irq
* @type: VTG type (main or aux)
* @notifier_list: notifier callback
* @crtc_id: the crtc id for vblank event
* @crtc: the CRTC for vblank event
* @slave: slave vtg
* @link: List node to link the structure in lookup list
*/
......@@ -90,7 +90,7 @@ struct sti_vtg {
int irq;
u32 irq_status;
struct raw_notifier_head notifier_list;
int crtc_id;
struct drm_crtc *crtc;
struct sti_vtg *slave;
struct list_head link;
};
......@@ -110,7 +110,6 @@ struct sti_vtg *of_vtg_find(struct device_node *np)
}
return NULL;
}
EXPORT_SYMBOL(of_vtg_find);
static void vtg_reset(struct sti_vtg *vtg)
{
......@@ -242,7 +241,6 @@ void sti_vtg_set_config(struct sti_vtg *vtg,
else
vtg_enable_irq(vtg);
}
EXPORT_SYMBOL(sti_vtg_set_config);
/**
* sti_vtg_get_line_number
......@@ -265,7 +263,6 @@ u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y)
return start_line + y;
}
EXPORT_SYMBOL(sti_vtg_get_line_number);
/**
* sti_vtg_get_pixel_number
......@@ -281,18 +278,16 @@ u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x)
{
return mode.htotal - mode.hsync_start + x;
}
EXPORT_SYMBOL(sti_vtg_get_pixel_number);
int sti_vtg_register_client(struct sti_vtg *vtg,
struct notifier_block *nb, int crtc_id)
int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb,
struct drm_crtc *crtc)
{
if (vtg->slave)
return sti_vtg_register_client(vtg->slave, nb, crtc_id);
return sti_vtg_register_client(vtg->slave, nb, crtc);
vtg->crtc_id = crtc_id;
vtg->crtc = crtc;
return raw_notifier_chain_register(&vtg->notifier_list, nb);
}
EXPORT_SYMBOL(sti_vtg_register_client);
int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb)
{
......@@ -301,7 +296,6 @@ int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb)
return raw_notifier_chain_unregister(&vtg->notifier_list, nb);
}
EXPORT_SYMBOL(sti_vtg_unregister_client);
static irqreturn_t vtg_irq_thread(int irq, void *arg)
{
......@@ -311,7 +305,7 @@ static irqreturn_t vtg_irq_thread(int irq, void *arg)
event = (vtg->irq_status & VTG_IRQ_TOP) ?
VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT;
raw_notifier_call_chain(&vtg->notifier_list, event, &vtg->crtc_id);
raw_notifier_call_chain(&vtg->notifier_list, event, vtg->crtc);
return IRQ_HANDLED;
}
......@@ -406,8 +400,6 @@ struct platform_driver sti_vtg_driver = {
.remove = vtg_remove,
};
module_platform_driver(sti_vtg_driver);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
......@@ -17,8 +17,8 @@ struct notifier_block;
struct sti_vtg *of_vtg_find(struct device_node *np);
void sti_vtg_set_config(struct sti_vtg *vtg,
const struct drm_display_mode *mode);
int sti_vtg_register_client(struct sti_vtg *vtg,
struct notifier_block *nb, int crtc_id);
int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb,
struct drm_crtc *crtc);
int sti_vtg_unregister_client(struct sti_vtg *vtg,
struct notifier_block *nb);
......
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