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
This commit is contained in:
commit
f20780f3e8
|
@ -6,12 +6,6 @@ config DRM_STI
|
||||||
select DRM_GEM_CMA_HELPER
|
select DRM_GEM_CMA_HELPER
|
||||||
select DRM_KMS_CMA_HELPER
|
select DRM_KMS_CMA_HELPER
|
||||||
select DRM_PANEL
|
select DRM_PANEL
|
||||||
select FW_LOADER_USER_HELPER_FALLBACK
|
select FW_LOADER
|
||||||
help
|
help
|
||||||
Choose this option to enable DRM on STM stiH41x chipset
|
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
|
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
sticompositor-y := \
|
sti-drm-y := \
|
||||||
sti_mixer.o \
|
sti_mixer.o \
|
||||||
sti_gdp.o \
|
sti_gdp.o \
|
||||||
sti_vid.o \
|
sti_vid.o \
|
||||||
sti_cursor.o \
|
sti_cursor.o \
|
||||||
sti_compositor.o \
|
sti_compositor.o \
|
||||||
sti_crtc.o \
|
sti_crtc.o \
|
||||||
sti_plane.o
|
sti_plane.o \
|
||||||
|
sti_crtc.o \
|
||||||
stihdmi-y := sti_hdmi.o \
|
sti_plane.o \
|
||||||
|
sti_hdmi.o \
|
||||||
sti_hdmi_tx3g0c55phy.o \
|
sti_hdmi_tx3g0c55phy.o \
|
||||||
sti_hdmi_tx3g4c28phy.o \
|
sti_hdmi_tx3g4c28phy.o \
|
||||||
|
sti_dvo.o \
|
||||||
stidvo-y := sti_dvo.o \
|
sti_awg_utils.o \
|
||||||
sti_awg_utils.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_DRM_STI) = \
|
|
||||||
sti_vtg.o \
|
sti_vtg.o \
|
||||||
sti_vtac.o \
|
sti_vtac.o \
|
||||||
stihdmi.o \
|
|
||||||
sti_hda.o \
|
sti_hda.o \
|
||||||
sti_tvout.o \
|
sti_tvout.o \
|
||||||
sticompositor.o \
|
|
||||||
sti_hqvdp.o \
|
sti_hqvdp.o \
|
||||||
stidvo.o \
|
|
||||||
sti_drv.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;
|
mux = 0;
|
||||||
data_enable = 0;
|
data_enable = 0;
|
||||||
arg = (arg << 22) >> 22;
|
|
||||||
arg &= (0x3ff);
|
arg &= (0x3ff);
|
||||||
break;
|
break;
|
||||||
case REPEAT:
|
case REPEAT:
|
||||||
|
@ -77,14 +76,12 @@ static int awg_generate_instr(enum opcode opcode,
|
||||||
|
|
||||||
mux = 0;
|
mux = 0;
|
||||||
data_enable = 0;
|
data_enable = 0;
|
||||||
arg = (arg << 22) >> 22;
|
|
||||||
arg &= (0x3ff);
|
arg &= (0x3ff);
|
||||||
break;
|
break;
|
||||||
case JUMP:
|
case JUMP:
|
||||||
mux = 0;
|
mux = 0;
|
||||||
data_enable = 0;
|
data_enable = 0;
|
||||||
arg |= 0x40; /* for jump instruction 7th bit is 1 */
|
arg |= 0x40; /* for jump instruction 7th bit is 1 */
|
||||||
arg = (arg << 22) >> 22;
|
|
||||||
arg &= 0x3ff;
|
arg &= 0x3ff;
|
||||||
break;
|
break;
|
||||||
case STOP:
|
case STOP:
|
||||||
|
@ -94,7 +91,6 @@ static int awg_generate_instr(enum opcode opcode,
|
||||||
case RPTSET:
|
case RPTSET:
|
||||||
case RPLSET:
|
case RPLSET:
|
||||||
case HOLD:
|
case HOLD:
|
||||||
arg = (arg << 24) >> 24;
|
|
||||||
arg &= (0x0ff);
|
arg &= (0x0ff);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -263,7 +263,7 @@ static int sti_compositor_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver sti_compositor_driver = {
|
struct platform_driver sti_compositor_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sti-compositor",
|
.name = "sti-compositor",
|
||||||
.of_match_table = compositor_of_match,
|
.of_match_table = compositor_of_match,
|
||||||
|
@ -272,8 +272,6 @@ static struct platform_driver sti_compositor_driver = {
|
||||||
.remove = sti_compositor_remove,
|
.remove = sti_compositor_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(sti_compositor_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
MODULE_LICENSE("GPL");
|
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,
|
.enable = sti_crtc_enable,
|
||||||
.disable = sti_crtc_disabling,
|
.disable = sti_crtc_disabling,
|
||||||
.mode_fixup = sti_crtc_mode_fixup,
|
.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,
|
int sti_crtc_vblank_cb(struct notifier_block *nb,
|
||||||
unsigned long event, void *data)
|
unsigned long event, void *data)
|
||||||
{
|
{
|
||||||
struct drm_device *drm_dev;
|
|
||||||
struct sti_compositor *compo =
|
struct sti_compositor *compo =
|
||||||
container_of(nb, struct sti_compositor, vtg_vblank_nb);
|
container_of(nb, struct sti_compositor, vtg_vblank_nb);
|
||||||
int *crtc = data;
|
struct drm_crtc *crtc = data;
|
||||||
|
struct sti_mixer *mixer;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct sti_private *priv;
|
struct sti_private *priv;
|
||||||
|
unsigned int pipe;
|
||||||
|
|
||||||
drm_dev = compo->mixer[*crtc]->drm_crtc.dev;
|
priv = crtc->dev->dev_private;
|
||||||
priv = drm_dev->dev_private;
|
pipe = drm_crtc_index(crtc);
|
||||||
|
mixer = compo->mixer[pipe];
|
||||||
|
|
||||||
if ((event != VTG_TOP_FIELD_EVENT) &&
|
if ((event != VTG_TOP_FIELD_EVENT) &&
|
||||||
(event != VTG_BOTTOM_FIELD_EVENT)) {
|
(event != VTG_BOTTOM_FIELD_EVENT)) {
|
||||||
|
@ -270,30 +272,30 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_handle_vblank(drm_dev, *crtc);
|
drm_crtc_handle_vblank(crtc);
|
||||||
|
|
||||||
spin_lock_irqsave(&drm_dev->event_lock, flags);
|
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||||
if (compo->mixer[*crtc]->pending_event) {
|
if (mixer->pending_event) {
|
||||||
drm_send_vblank_event(drm_dev, -1,
|
drm_crtc_send_vblank_event(crtc, mixer->pending_event);
|
||||||
compo->mixer[*crtc]->pending_event);
|
drm_crtc_vblank_put(crtc);
|
||||||
drm_vblank_put(drm_dev, *crtc);
|
mixer->pending_event = NULL;
|
||||||
compo->mixer[*crtc]->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;
|
struct drm_plane *p;
|
||||||
|
|
||||||
/* Disable mixer only if all overlay planes (GDP and VDP)
|
/* Disable mixer only if all overlay planes (GDP and VDP)
|
||||||
* are disabled */
|
* 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);
|
struct sti_plane *plane = to_sti_plane(p);
|
||||||
|
|
||||||
if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
|
if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
|
||||||
if (plane->status != STI_PLANE_DISABLED)
|
if (plane->status != STI_PLANE_DISABLED)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
|
sti_crtc_disable(crtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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_private *dev_priv = dev->dev_private;
|
||||||
struct sti_compositor *compo = dev_priv->compo;
|
struct sti_compositor *compo = dev_priv->compo;
|
||||||
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
|
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
|
||||||
|
struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
|
||||||
|
|
||||||
DRM_DEBUG_DRIVER("\n");
|
DRM_DEBUG_DRIVER("\n");
|
||||||
|
|
||||||
if (sti_vtg_register_client(pipe == STI_MIXER_MAIN ?
|
if (sti_vtg_register_client(pipe == STI_MIXER_MAIN ?
|
||||||
compo->vtg_main : compo->vtg_aux,
|
compo->vtg_main : compo->vtg_aux,
|
||||||
vtg_vblank_nb, pipe)) {
|
vtg_vblank_nb, crtc)) {
|
||||||
DRM_ERROR("Cannot register VTG notifier\n");
|
DRM_ERROR("Cannot register VTG notifier\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sti_crtc_enable_vblank);
|
|
||||||
|
|
||||||
void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
|
void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
|
||||||
{
|
{
|
||||||
struct sti_private *priv = drm_dev->dev_private;
|
struct sti_private *priv = drm_dev->dev_private;
|
||||||
struct sti_compositor *compo = priv->compo;
|
struct sti_compositor *compo = priv->compo;
|
||||||
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
|
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
|
||||||
|
struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
|
||||||
|
|
||||||
DRM_DEBUG_DRIVER("\n");
|
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 */
|
/* free the resources of the pending requests */
|
||||||
if (compo->mixer[pipe]->pending_event) {
|
if (compo->mixer[pipe]->pending_event) {
|
||||||
drm_vblank_put(drm_dev, pipe);
|
drm_crtc_vblank_put(crtc);
|
||||||
compo->mixer[pipe]->pending_event = NULL;
|
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,
|
.set_config = drm_atomic_helper_set_config,
|
||||||
.page_flip = drm_atomic_helper_page_flip,
|
.page_flip = drm_atomic_helper_page_flip,
|
||||||
.destroy = sti_crtc_destroy,
|
.destroy = sti_crtc_destroy,
|
||||||
|
@ -357,7 +359,6 @@ bool sti_crtc_is_main(struct drm_crtc *crtc)
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sti_crtc_is_main);
|
|
||||||
|
|
||||||
int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
|
int sti_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)
|
||||||
|
|
|
@ -107,7 +107,7 @@ static int sti_atomic_commit(struct drm_device *drm,
|
||||||
return 0;
|
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,
|
.fb_create = drm_fb_cma_create,
|
||||||
.atomic_check = drm_atomic_helper_check,
|
.atomic_check = drm_atomic_helper_check,
|
||||||
.atomic_commit = sti_atomic_commit,
|
.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
|
* this value would be used to check framebuffer size limitation
|
||||||
* at drm_mode_addfb().
|
* at drm_mode_addfb().
|
||||||
*/
|
*/
|
||||||
dev->mode_config.max_width = STI_MAX_FB_HEIGHT;
|
dev->mode_config.max_width = STI_MAX_FB_WIDTH;
|
||||||
dev->mode_config.max_height = STI_MAX_FB_WIDTH;
|
dev->mode_config.max_height = STI_MAX_FB_HEIGHT;
|
||||||
|
|
||||||
dev->mode_config.funcs = &sti_mode_config_funcs;
|
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);
|
drm_mode_config_reset(dev);
|
||||||
|
|
||||||
#ifdef CONFIG_DRM_STI_FBDEV
|
|
||||||
drm_fbdev_cma_init(dev, 32,
|
drm_fbdev_cma_init(dev, 32,
|
||||||
dev->mode_config.num_crtc,
|
dev->mode_config.num_crtc,
|
||||||
dev->mode_config.num_connector);
|
dev->mode_config.num_connector);
|
||||||
#endif
|
|
||||||
return 0;
|
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_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
|
|
|
@ -32,4 +32,13 @@ struct sti_private {
|
||||||
} commit;
|
} 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
|
#endif
|
||||||
|
|
|
@ -329,7 +329,8 @@ struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector)
|
||||||
return dvo_connector->encoder;
|
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,
|
.get_modes = sti_dvo_connector_get_modes,
|
||||||
.mode_valid = sti_dvo_connector_mode_valid,
|
.mode_valid = sti_dvo_connector_mode_valid,
|
||||||
.best_encoder = sti_dvo_best_encoder,
|
.best_encoder = sti_dvo_best_encoder,
|
||||||
|
@ -364,7 +365,7 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector)
|
||||||
kfree(dvo_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,
|
.dpms = drm_atomic_helper_connector_dpms,
|
||||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||||
.detect = sti_dvo_connector_detect,
|
.detect = sti_dvo_connector_detect,
|
||||||
|
@ -557,8 +558,6 @@ struct platform_driver sti_dvo_driver = {
|
||||||
.remove = sti_dvo_remove,
|
.remove = sti_dvo_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(sti_dvo_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -492,7 +492,7 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
|
||||||
/* Register gdp callback */
|
/* Register gdp callback */
|
||||||
if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ?
|
if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ?
|
||||||
compo->vtg_main : compo->vtg_aux,
|
compo->vtg_main : compo->vtg_aux,
|
||||||
&gdp->vtg_field_nb, mixer->id)) {
|
&gdp->vtg_field_nb, crtc)) {
|
||||||
DRM_ERROR("Cannot register VTG notifier\n");
|
DRM_ERROR("Cannot register VTG notifier\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -589,7 +589,8 @@ struct drm_encoder *sti_hda_best_encoder(struct drm_connector *connector)
|
||||||
return hda_connector->encoder;
|
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,
|
.get_modes = sti_hda_connector_get_modes,
|
||||||
.mode_valid = sti_hda_connector_mode_valid,
|
.mode_valid = sti_hda_connector_mode_valid,
|
||||||
.best_encoder = sti_hda_best_encoder,
|
.best_encoder = sti_hda_best_encoder,
|
||||||
|
@ -611,7 +612,7 @@ static void sti_hda_connector_destroy(struct drm_connector *connector)
|
||||||
kfree(hda_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,
|
.dpms = drm_atomic_helper_connector_dpms,
|
||||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||||
.detect = sti_hda_connector_detect,
|
.detect = sti_hda_connector_detect,
|
||||||
|
@ -784,8 +785,6 @@ struct platform_driver sti_hda_driver = {
|
||||||
.remove = sti_hda_remove,
|
.remove = sti_hda_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(sti_hda_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -628,7 +628,8 @@ struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector)
|
||||||
return hdmi_connector->encoder;
|
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,
|
.get_modes = sti_hdmi_connector_get_modes,
|
||||||
.mode_valid = sti_hdmi_connector_mode_valid,
|
.mode_valid = sti_hdmi_connector_mode_valid,
|
||||||
.best_encoder = sti_hdmi_best_encoder,
|
.best_encoder = sti_hdmi_best_encoder,
|
||||||
|
@ -663,7 +664,7 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector)
|
||||||
kfree(hdmi_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,
|
.dpms = drm_atomic_helper_connector_dpms,
|
||||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||||
.detect = sti_hdmi_connector_detect,
|
.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);
|
encoder = sti_hdmi_find_encoder(drm_dev);
|
||||||
if (!encoder)
|
if (!encoder)
|
||||||
goto err_adapt;
|
return -EINVAL;
|
||||||
|
|
||||||
connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
|
connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
|
||||||
if (!connector)
|
if (!connector)
|
||||||
goto err_adapt;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
||||||
connector->hdmi = hdmi;
|
connector->hdmi = hdmi;
|
||||||
|
|
||||||
bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
|
bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
|
||||||
if (!bridge)
|
if (!bridge)
|
||||||
goto err_adapt;
|
return -EINVAL;
|
||||||
|
|
||||||
bridge->driver_private = hdmi;
|
bridge->driver_private = hdmi;
|
||||||
bridge->funcs = &sti_hdmi_bridge_funcs;
|
bridge->funcs = &sti_hdmi_bridge_funcs;
|
||||||
|
@ -748,8 +748,7 @@ err_sysfs:
|
||||||
drm_connector_unregister(drm_connector);
|
drm_connector_unregister(drm_connector);
|
||||||
err_connector:
|
err_connector:
|
||||||
drm_connector_cleanup(drm_connector);
|
drm_connector_cleanup(drm_connector);
|
||||||
err_adapt:
|
|
||||||
put_device(&hdmi->ddc_adapt->dev);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,13 +793,10 @@ static int sti_hdmi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0);
|
ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0);
|
||||||
if (ddc) {
|
if (ddc) {
|
||||||
hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc);
|
hdmi->ddc_adapt = of_get_i2c_adapter_by_node(ddc);
|
||||||
if (!hdmi->ddc_adapt) {
|
|
||||||
of_node_put(ddc);
|
|
||||||
return -EPROBE_DEFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
of_node_put(ddc);
|
of_node_put(ddc);
|
||||||
|
if (!hdmi->ddc_adapt)
|
||||||
|
return -EPROBE_DEFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdmi->dev = pdev->dev;
|
hdmi->dev = pdev->dev;
|
||||||
|
@ -809,24 +805,29 @@ static int sti_hdmi_probe(struct platform_device *pdev)
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg");
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg");
|
||||||
if (!res) {
|
if (!res) {
|
||||||
DRM_ERROR("Invalid hdmi resource\n");
|
DRM_ERROR("Invalid hdmi resource\n");
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto release_adapter;
|
||||||
}
|
}
|
||||||
hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
|
hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
|
||||||
if (!hdmi->regs)
|
if (!hdmi->regs) {
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto release_adapter;
|
||||||
|
}
|
||||||
|
|
||||||
if (of_device_is_compatible(np, "st,stih416-hdmi")) {
|
if (of_device_is_compatible(np, "st,stih416-hdmi")) {
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||||
"syscfg");
|
"syscfg");
|
||||||
if (!res) {
|
if (!res) {
|
||||||
DRM_ERROR("Invalid syscfg resource\n");
|
DRM_ERROR("Invalid syscfg resource\n");
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto release_adapter;
|
||||||
}
|
}
|
||||||
hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
|
hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
|
||||||
resource_size(res));
|
resource_size(res));
|
||||||
if (!hdmi->syscfg)
|
if (!hdmi->syscfg) {
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto release_adapter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hdmi->phy_ops = (struct hdmi_phy_ops *)
|
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");
|
hdmi->clk_pix = devm_clk_get(dev, "pix");
|
||||||
if (IS_ERR(hdmi->clk_pix)) {
|
if (IS_ERR(hdmi->clk_pix)) {
|
||||||
DRM_ERROR("Cannot get hdmi_pix clock\n");
|
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");
|
hdmi->clk_tmds = devm_clk_get(dev, "tmds");
|
||||||
if (IS_ERR(hdmi->clk_tmds)) {
|
if (IS_ERR(hdmi->clk_tmds)) {
|
||||||
DRM_ERROR("Cannot get hdmi_tmds clock\n");
|
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");
|
hdmi->clk_phy = devm_clk_get(dev, "phy");
|
||||||
if (IS_ERR(hdmi->clk_phy)) {
|
if (IS_ERR(hdmi->clk_phy)) {
|
||||||
DRM_ERROR("Cannot get hdmi_phy clock\n");
|
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");
|
hdmi->clk_audio = devm_clk_get(dev, "audio");
|
||||||
if (IS_ERR(hdmi->clk_audio)) {
|
if (IS_ERR(hdmi->clk_audio)) {
|
||||||
DRM_ERROR("Cannot get hdmi_audio clock\n");
|
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;
|
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);
|
hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DRM_ERROR("Failed to register HDMI interrupt\n");
|
DRM_ERROR("Failed to register HDMI interrupt\n");
|
||||||
return ret;
|
goto release_adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdmi->reset = devm_reset_control_get(dev, "hdmi");
|
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);
|
platform_set_drvdata(pdev, hdmi);
|
||||||
|
|
||||||
return component_add(&pdev->dev, &sti_hdmi_ops);
|
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)
|
static int sti_hdmi_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev);
|
struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
if (hdmi->ddc_adapt)
|
i2c_put_adapter(hdmi->ddc_adapt);
|
||||||
put_device(&hdmi->ddc_adapt->dev);
|
|
||||||
|
|
||||||
component_del(&pdev->dev, &sti_hdmi_ops);
|
component_del(&pdev->dev, &sti_hdmi_ops);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,8 +910,6 @@ struct platform_driver sti_hdmi_driver = {
|
||||||
.remove = sti_hdmi_remove,
|
.remove = sti_hdmi_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(sti_hdmi_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -628,6 +628,153 @@ static void sti_hqvdp_init(struct sti_hqvdp *hqvdp)
|
||||||
memset(hqvdp->hqvdp_cmd, 0, size);
|
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,
|
static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
|
||||||
struct drm_plane_state *oldstate)
|
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);
|
sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
|
||||||
|
|
||||||
if (first_prepare) {
|
if (first_prepare) {
|
||||||
|
/* Start HQVDP XP70 coprocessor */
|
||||||
|
sti_hqvdp_start_xp70(hqvdp);
|
||||||
|
|
||||||
/* Prevent VTG shutdown */
|
/* Prevent VTG shutdown */
|
||||||
if (clk_prepare_enable(hqvdp->clk_pix_main)) {
|
if (clk_prepare_enable(hqvdp->clk_pix_main)) {
|
||||||
DRM_ERROR("Failed to prepare/enable pix main clk\n");
|
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 */
|
/* Register VTG Vsync callback to handle bottom fields */
|
||||||
if (sti_vtg_register_client(hqvdp->vtg,
|
if (sti_vtg_register_client(hqvdp->vtg,
|
||||||
&hqvdp->vtg_nb,
|
&hqvdp->vtg_nb,
|
||||||
mixer->id)) {
|
crtc)) {
|
||||||
DRM_ERROR("Cannot register VTG notifier\n");
|
DRM_ERROR("Cannot register VTG notifier\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -836,168 +986,16 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
|
||||||
return &hqvdp->plane.drm_plane;
|
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)
|
int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
|
||||||
{
|
{
|
||||||
struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
|
struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
|
||||||
struct drm_device *drm_dev = data;
|
struct drm_device *drm_dev = data;
|
||||||
struct drm_plane *plane;
|
struct drm_plane *plane;
|
||||||
int err;
|
|
||||||
|
|
||||||
DRM_DEBUG_DRIVER("\n");
|
DRM_DEBUG_DRIVER("\n");
|
||||||
|
|
||||||
hqvdp->drm_dev = drm_dev;
|
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 */
|
/* Create HQVDP plane once xp70 is initialized */
|
||||||
plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0);
|
plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0);
|
||||||
if (!plane)
|
if (!plane)
|
||||||
|
@ -1090,8 +1088,6 @@ struct platform_driver sti_hqvdp_driver = {
|
||||||
.remove = sti_hqvdp_remove,
|
.remove = sti_hqvdp_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(sti_hqvdp_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
#include "sti_mixer.h"
|
#include "sti_mixer.h"
|
||||||
#include "sti_vtg.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 */
|
/* Identity: G=Y , B=Cb , R=Cr */
|
||||||
static const u32 mixerColorSpaceMatIdentity[] = {
|
static const u32 mixerColorSpaceMatIdentity[] = {
|
||||||
0x10000000, 0x00000000, 0x10000000, 0x00001000,
|
0x10000000, 0x00000000, 0x10000000, 0x00001000,
|
||||||
|
@ -58,7 +63,6 @@ const char *sti_mixer_to_str(struct sti_mixer *mixer)
|
||||||
return "<UNKNOWN MIXER>";
|
return "<UNKNOWN MIXER>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sti_mixer_to_str);
|
|
||||||
|
|
||||||
static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
|
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,
|
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, rgb);
|
||||||
|
|
||||||
sti_mixer_reg_write(mixer, GAM_MIXER_BKC, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sti_mixer_set_background_area(struct sti_mixer *mixer,
|
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_AVO, ydo << 16 | xdo);
|
||||||
sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
|
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_area(mixer, mode);
|
||||||
sti_mixer_set_background_status(mixer, true);
|
sti_mixer_set_background_status(mixer, true);
|
||||||
|
|
|
@ -42,7 +42,6 @@ const char *sti_plane_to_str(struct sti_plane *plane)
|
||||||
return "<UNKNOWN PLANE>";
|
return "<UNKNOWN PLANE>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sti_plane_to_str);
|
|
||||||
|
|
||||||
static void sti_plane_destroy(struct drm_plane *drm_plane)
|
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,
|
plane->drm_plane.base.id,
|
||||||
sti_plane_to_str(plane), plane->zorder);
|
sti_plane_to_str(plane), plane->zorder);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sti_plane_init_property);
|
|
||||||
|
|
||||||
struct drm_plane_funcs sti_plane_helpers_funcs = {
|
struct drm_plane_funcs sti_plane_helpers_funcs = {
|
||||||
.update_plane = drm_atomic_helper_update_plane,
|
.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_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_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,
|
.remove = sti_tvout_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(sti_tvout_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -216,8 +216,6 @@ struct platform_driver sti_vtac_driver = {
|
||||||
.remove = sti_vtac_remove,
|
.remove = sti_vtac_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(sti_vtac_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -79,7 +79,7 @@ LIST_HEAD(vtg_lookup);
|
||||||
* @irq: VTG irq
|
* @irq: VTG irq
|
||||||
* @type: VTG type (main or aux)
|
* @type: VTG type (main or aux)
|
||||||
* @notifier_list: notifier callback
|
* @notifier_list: notifier callback
|
||||||
* @crtc_id: the crtc id for vblank event
|
* @crtc: the CRTC for vblank event
|
||||||
* @slave: slave vtg
|
* @slave: slave vtg
|
||||||
* @link: List node to link the structure in lookup list
|
* @link: List node to link the structure in lookup list
|
||||||
*/
|
*/
|
||||||
|
@ -90,7 +90,7 @@ struct sti_vtg {
|
||||||
int irq;
|
int irq;
|
||||||
u32 irq_status;
|
u32 irq_status;
|
||||||
struct raw_notifier_head notifier_list;
|
struct raw_notifier_head notifier_list;
|
||||||
int crtc_id;
|
struct drm_crtc *crtc;
|
||||||
struct sti_vtg *slave;
|
struct sti_vtg *slave;
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
};
|
};
|
||||||
|
@ -110,7 +110,6 @@ struct sti_vtg *of_vtg_find(struct device_node *np)
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(of_vtg_find);
|
|
||||||
|
|
||||||
static void vtg_reset(struct sti_vtg *vtg)
|
static void vtg_reset(struct sti_vtg *vtg)
|
||||||
{
|
{
|
||||||
|
@ -242,7 +241,6 @@ void sti_vtg_set_config(struct sti_vtg *vtg,
|
||||||
else
|
else
|
||||||
vtg_enable_irq(vtg);
|
vtg_enable_irq(vtg);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sti_vtg_set_config);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sti_vtg_get_line_number
|
* 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;
|
return start_line + y;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sti_vtg_get_line_number);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sti_vtg_get_pixel_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;
|
return mode.htotal - mode.hsync_start + x;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sti_vtg_get_pixel_number);
|
|
||||||
|
|
||||||
int sti_vtg_register_client(struct sti_vtg *vtg,
|
int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb,
|
||||||
struct notifier_block *nb, int crtc_id)
|
struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
if (vtg->slave)
|
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);
|
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)
|
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);
|
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)
|
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) ?
|
event = (vtg->irq_status & VTG_IRQ_TOP) ?
|
||||||
VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT;
|
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;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -406,8 +400,6 @@ struct platform_driver sti_vtg_driver = {
|
||||||
.remove = vtg_remove,
|
.remove = vtg_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(sti_vtg_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
|
||||||
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -17,8 +17,8 @@ struct notifier_block;
|
||||||
struct sti_vtg *of_vtg_find(struct device_node *np);
|
struct sti_vtg *of_vtg_find(struct device_node *np);
|
||||||
void sti_vtg_set_config(struct sti_vtg *vtg,
|
void sti_vtg_set_config(struct sti_vtg *vtg,
|
||||||
const struct drm_display_mode *mode);
|
const struct drm_display_mode *mode);
|
||||||
int sti_vtg_register_client(struct sti_vtg *vtg,
|
int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb,
|
||||||
struct notifier_block *nb, int crtc_id);
|
struct drm_crtc *crtc);
|
||||||
int sti_vtg_unregister_client(struct sti_vtg *vtg,
|
int sti_vtg_unregister_client(struct sti_vtg *vtg,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue