Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 282553
b: refs/heads/master
c: ec05da9
h: refs/heads/master
i:
  282551: 348e4d3
v: v3
  • Loading branch information
Inki Dae committed Dec 21, 2011
1 parent 909cac5 commit f820bd0
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 84 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a794d57da8031a45fed4e4cb71a999694ba02f7e
refs/heads/master: ec05da959acc5da8d51207060d9af672ae837321
58 changes: 52 additions & 6 deletions trunk/drivers/gpu/drm/exynos/exynos_drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@
* drm framework doesn't support multiple irq yet.
* we can refer to the crtc to current hardware interrupt occured through
* this pipe value.
* @dpms: store the crtc dpms value
*/
struct exynos_drm_crtc {
struct drm_crtc drm_crtc;
struct exynos_drm_overlay overlay;
unsigned int pipe;
unsigned int dpms;
};

static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
Expand Down Expand Up @@ -153,26 +155,37 @@ static int exynos_drm_crtc_update(struct drm_crtc *crtc)

static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);

DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);

if (exynos_crtc->dpms == mode) {
DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
return;
}

mutex_lock(&dev->struct_mutex);

switch (mode) {
case DRM_MODE_DPMS_ON:
exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
exynos_drm_encoder_crtc_commit);
exynos_drm_fn_encoder(crtc, &mode,
exynos_drm_encoder_crtc_dpms);
exynos_crtc->dpms = mode;
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
/* TODO */
exynos_drm_fn_encoder(crtc, NULL,
exynos_drm_encoder_crtc_disable);
exynos_drm_fn_encoder(crtc, &mode,
exynos_drm_encoder_crtc_dpms);
exynos_crtc->dpms = mode;
break;
default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
DRM_ERROR("unspecified mode %d\n", mode);
break;
}

mutex_unlock(&dev->struct_mutex);
}

static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
Expand All @@ -188,6 +201,28 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)

DRM_DEBUG_KMS("%s\n", __FILE__);

/*
* when set_crtc is requested from user or at booting time,
* crtc->commit would be called without dpms call so if dpms is
* no power on then crtc->dpms should be called
* with DRM_MODE_DPMS_ON for the hardware power to be on.
*/
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
int mode = DRM_MODE_DPMS_ON;

/*
* enable hardware(power on) to all encoders hdmi connected
* to current crtc.
*/
exynos_drm_crtc_dpms(crtc, mode);
/*
* enable dma to all encoders connected to current crtc and
* lcd panel.
*/
exynos_drm_fn_encoder(crtc, &mode,
exynos_drm_encoder_dpms_from_crtc);
}

exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
exynos_drm_encoder_crtc_commit);
}
Expand Down Expand Up @@ -344,6 +379,7 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
}

exynos_crtc->pipe = nr;
exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
crtc = &exynos_crtc->drm_crtc;

private->crtc[nr] = crtc;
Expand All @@ -357,9 +393,14 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[crtc]);

DRM_DEBUG_KMS("%s\n", __FILE__);

if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return -EPERM;

exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
exynos_drm_enable_vblank);

Expand All @@ -369,9 +410,14 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[crtc]);

DRM_DEBUG_KMS("%s\n", __FILE__);

if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return;

exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
exynos_drm_disable_vblank);
}
Expand Down
6 changes: 4 additions & 2 deletions trunk/drivers/gpu/drm/exynos/exynos_drm_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,19 @@ struct exynos_drm_display_ops {
/*
* Exynos drm manager ops
*
* @dpms: control device power.
* @apply: set timing, vblank and overlay data to registers.
* @mode_set: convert drm_display_mode to hw specific display mode and
* would be called by encoder->mode_set().
* @commit: set current hw specific display mode to hw.
* @disable: disable hardware specific display mode.
* @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt.
*/
struct exynos_drm_manager_ops {
void (*dpms)(struct device *subdrv_dev, int mode);
void (*apply)(struct device *subdrv_dev);
void (*mode_set)(struct device *subdrv_dev, void *mode);
void (*commit)(struct device *subdrv_dev);
void (*disable)(struct device *subdrv_dev);
int (*enable_vblank)(struct device *subdrv_dev);
void (*disable_vblank)(struct device *subdrv_dev);
};
Expand Down
109 changes: 83 additions & 26 deletions trunk/drivers/gpu/drm/exynos/exynos_drm_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,49 +42,68 @@
* @drm_encoder: encoder object.
* @manager: specific encoder has its own manager to control a hardware
* appropriately and we can access a hardware drawing on this manager.
* @dpms: store the encoder dpms value.
*/
struct exynos_drm_encoder {
struct drm_encoder drm_encoder;
struct exynos_drm_manager *manager;
int dpms;
};

static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
static void exynos_drm_display_power(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct drm_connector *connector;
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);

list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder == encoder) {
struct exynos_drm_display_ops *display_ops =
manager->display_ops;

DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
connector->base.id, mode);
if (display_ops && display_ops->power_on)
display_ops->power_on(manager->dev, mode);
}
}
}

static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
struct exynos_drm_manager_ops *manager_ops = manager->ops;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);

DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);

if (exynos_encoder->dpms == mode) {
DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
return;
}

mutex_lock(&dev->struct_mutex);

switch (mode) {
case DRM_MODE_DPMS_ON:
if (manager_ops && manager_ops->commit)
manager_ops->commit(manager->dev);
if (manager_ops && manager_ops->apply)
manager_ops->apply(manager->dev);
exynos_drm_display_power(encoder, mode);
exynos_encoder->dpms = mode;
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
/* TODO */
if (manager_ops && manager_ops->disable)
manager_ops->disable(manager->dev);
exynos_drm_display_power(encoder, mode);
exynos_encoder->dpms = mode;
break;
default:
DRM_ERROR("unspecified mode %d\n", mode);
break;
}

list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder == encoder) {
struct exynos_drm_display_ops *display_ops =
manager->display_ops;

DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
connector->base.id, mode);
if (display_ops && display_ops->power_on)
display_ops->power_on(manager->dev, mode);
}
}
mutex_unlock(&dev->struct_mutex);
}

static bool
Expand Down Expand Up @@ -169,7 +188,6 @@ static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
exynos_encoder->manager->pipe = -1;

drm_encoder_cleanup(encoder);
encoder->dev->mode_config.num_encoder--;
kfree(exynos_encoder);
}

Expand Down Expand Up @@ -199,6 +217,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
return NULL;
}

exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
exynos_encoder->manager = manager;
encoder = &exynos_encoder->drm_encoder;
encoder->possible_crtcs = possible_crtcs;
Expand Down Expand Up @@ -294,6 +313,52 @@ void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
overlay_ops->commit(manager->dev);
}

void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
int mode = *(int *)data;

DRM_DEBUG_KMS("%s\n", __FILE__);

exynos_drm_encoder_dpms(encoder, mode);

exynos_encoder->dpms = mode;
}

void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
{
struct drm_device *dev = encoder->dev;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_manager *manager = exynos_encoder->manager;
struct exynos_drm_manager_ops *manager_ops = manager->ops;
struct drm_connector *connector;
int mode = *(int *)data;

DRM_DEBUG_KMS("%s\n", __FILE__);

if (manager_ops && manager_ops->dpms)
manager_ops->dpms(manager->dev, mode);

/*
* set current dpms mode to the connector connected to
* current encoder. connector->dpms would be checked
* at drm_helper_connector_dpms()
*/
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
if (connector->encoder == encoder)
connector->dpms = mode;

/*
* if this condition is ok then it means that the crtc is already
* detached from encoder and last function for detaching is properly
* done, so clear pipe from manager to prevent repeated call.
*/
if (mode > DRM_MODE_DPMS_ON) {
if (!encoder->crtc)
manager->pipe = -1;
}
}

void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
{
struct exynos_drm_manager *manager =
Expand All @@ -315,14 +380,6 @@ void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)

if (overlay_ops && overlay_ops->disable)
overlay_ops->disable(manager->dev);

/*
* crtc is already detached from encoder and last
* function for detaching is properly done, so
* clear pipe from manager to prevent repeated call
*/
if (!encoder->crtc)
manager->pipe = -1;
}

MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
Expand Down
3 changes: 3 additions & 0 deletions trunk/drivers/gpu/drm/exynos/exynos_drm_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder,
void *data);
void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data);

Expand Down
Loading

0 comments on commit f820bd0

Please sign in to comment.