#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_encoder.h"
+#include "exynos_drm_display.h"
#define MAX_EDID 256
#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
struct exynos_drm_connector {
struct drm_connector drm_connector;
uint32_t encoder_id;
- struct exynos_drm_manager *manager;
+ struct exynos_drm_display *display;
};
/* convert exynos_video_timings to drm_display_mode */
struct exynos_drm_panel_info *panel)
{
struct fb_videomode *timing = &panel->timing;
- DRM_DEBUG_KMS("%s\n", __FILE__);
+ DRM_DEBUG_KMS("[MODE:%d:%s]\n", DRM_BASE_ID(mode), mode->name);
mode->clock = timing->pixclock / 1000;
mode->vrefresh = timing->refresh;
convert_to_video_timing(struct fb_videomode *timing,
struct drm_display_mode *mode)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
+ DRM_DEBUG_KMS("[MODE:%d:%s]\n", DRM_BASE_ID(mode), mode->name);
memset(timing, 0, sizeof(*timing));
timing->vmode |= FB_VMODE_DOUBLE;
}
-static int exynos_drm_connector_get_modes(struct drm_connector *connector)
+static struct exynos_drm_display *display_from_connector(
+ struct drm_connector *connector)
{
- struct exynos_drm_connector *exynos_connector =
- to_exynos_connector(connector);
- struct exynos_drm_manager *manager = exynos_connector->manager;
- struct exynos_drm_display_ops *display_ops = manager->display_ops;
- unsigned int count;
+ return to_exynos_connector(connector)->display;
+}
- DRM_DEBUG_KMS("%s\n", __FILE__);
+static int exynos_drm_connector_get_edid(struct drm_connector *connector)
+{
+ struct exynos_drm_display *display = display_from_connector(connector);
+ int ret;
+ struct edid *edid;
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", DRM_BASE_ID(connector),
+ drm_get_connector_name(connector));
+
+ if (!display->panel_ops->get_edid)
+ return -EINVAL;
+
+ edid = display->panel_ops->get_edid(display->panel_ctx, connector);
+ if (IS_ERR_OR_NULL(edid)) {
+ ret = PTR_ERR(edid);
+ edid = NULL;
+ DRM_ERROR("Panel operation get_edid failed %d\n", ret);
+ goto out;
+ }
- if (!display_ops) {
- DRM_DEBUG_KMS("display_ops is null.\n");
- return 0;
+ ret = drm_mode_connector_update_edid_property(connector, edid);
+ if (ret) {
+ DRM_ERROR("update edid property failed(%d)\n", ret);
+ goto out;
}
+ ret = drm_add_edid_modes(connector, edid);
+ if (ret < 0) {
+ DRM_ERROR("Add edid modes failed %d\n", ret);
+ goto out;
+ }
+
+out:
+ connector->display_info.raw_edid = NULL;
+ kfree(edid);
+ return ret;
+}
+
+static int exynos_drm_connector_get_panel(struct drm_connector *connector)
+{
+ struct exynos_drm_display *display = display_from_connector(connector);
+ struct drm_display_mode *mode;
+ struct exynos_drm_panel_info *panel;
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", DRM_BASE_ID(connector),
+ drm_get_connector_name(connector));
+
+ if (!display->controller_ops->get_panel)
+ return -EINVAL;
+
+ panel = display->controller_ops->get_panel(display->controller_ctx);
+
+ mode = drm_mode_create(connector->dev);
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+ convert_to_display_mode(mode, panel);
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static int exynos_drm_connector_get_modes(struct drm_connector *connector)
+{
+ int ret;
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", DRM_BASE_ID(connector),
+ drm_get_connector_name(connector));
+
/*
- * if get_edid() exists then get_edid() callback of hdmi side
- * is called to get edid data through i2c interface else
- * get timing from the FIMD driver(display controller).
- *
- * P.S. in case of lcd panel, count is always 1 if success
- * because lcd panel has only one mode.
+ * First try getting modes from EDID. If that doesn't yield any results,
+ * fall back to the panel call.
*/
- if (display_ops->get_edid) {
- int ret;
- void *edid;
-
- edid = kzalloc(MAX_EDID, GFP_KERNEL);
- if (!edid) {
- DRM_ERROR("failed to allocate edid\n");
- return 0;
- }
-
- ret = display_ops->get_edid(manager->dev, connector,
- edid, MAX_EDID);
- if (ret < 0) {
- DRM_ERROR("failed to get edid data.\n");
- kfree(edid);
- edid = NULL;
- return 0;
- }
-
- drm_mode_connector_update_edid_property(connector, edid);
- count = drm_add_edid_modes(connector, edid);
-
- kfree(connector->display_info.raw_edid);
- connector->display_info.raw_edid = edid;
- } else {
- struct drm_display_mode *mode = drm_mode_create(connector->dev);
- struct exynos_drm_panel_info *panel;
-
- if (display_ops->get_panel)
- panel = display_ops->get_panel(manager->dev);
- else {
- drm_mode_destroy(connector->dev, mode);
- return 0;
- }
-
- convert_to_display_mode(mode, panel);
- connector->display_info.width_mm = mode->width_mm;
- connector->display_info.height_mm = mode->height_mm;
-
- mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
- drm_mode_set_name(mode);
- drm_mode_probed_add(connector, mode);
-
- count = 1;
- }
+ ret = exynos_drm_connector_get_edid(connector);
+ if (ret > 0)
+ return ret;
- return count;
+ return exynos_drm_connector_get_panel(connector);
}
static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct exynos_drm_connector *exynos_connector =
- to_exynos_connector(connector);
- struct exynos_drm_manager *manager = exynos_connector->manager;
- struct exynos_drm_display_ops *display_ops = manager->display_ops;
+ struct exynos_drm_display *display = display_from_connector(connector);
struct fb_videomode timing;
int ret = MODE_BAD;
- DRM_DEBUG_KMS("%s\n", __FILE__);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] [MODE:%d:%s]\n",
+ DRM_BASE_ID(connector),
+ drm_get_connector_name(connector), DRM_BASE_ID(mode),
+ mode->name);
convert_to_video_timing(&timing, mode);
- if (display_ops && display_ops->check_timing)
- if (!display_ops->check_timing(manager->dev, (void *)&timing))
- ret = MODE_OK;
+ if (!display->panel_ops->check_timing)
+ return ret;
+
+ if (!display->panel_ops->check_timing(display->panel_ctx, &timing))
+ ret = MODE_OK;
return ret;
}
struct drm_mode_object *obj;
struct drm_encoder *encoder;
- DRM_DEBUG_KMS("%s\n", __FILE__);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", DRM_BASE_ID(connector),
+ drm_get_connector_name(connector));
obj = drm_mode_object_find(dev, exynos_connector->encoder_id,
DRM_MODE_OBJECT_ENCODER);
encoder = obj_to_encoder(obj);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] == [ENCODER:%d:%s]\n",
+ DRM_BASE_ID(connector),
+ drm_get_connector_name(connector),
+ DRM_BASE_ID(encoder), drm_get_encoder_name(encoder));
+
return encoder;
}
+struct drm_bridge *exynos_drm_best_bridge(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_bridge *bridge;
+
+ list_for_each_entry(bridge, &dev->mode_config.bridge_list, head) {
+ if (bridge->connector_type == connector->connector_type)
+ return bridge;
+ }
+ return NULL;
+}
+
static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
.get_modes = exynos_drm_connector_get_modes,
.mode_valid = exynos_drm_connector_mode_valid,
.best_encoder = exynos_drm_best_encoder,
+ .best_bridge = exynos_drm_best_bridge,
};
static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
unsigned int max_width, unsigned int max_height)
{
- struct exynos_drm_connector *exynos_connector =
- to_exynos_connector(connector);
- struct exynos_drm_manager *manager = exynos_connector->manager;
- struct exynos_drm_manager_ops *ops = manager->ops;
+ struct exynos_drm_display *display = display_from_connector(connector);
+ int ret;
unsigned int width, height;
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] %d x %d\n", DRM_BASE_ID(connector),
+ drm_get_connector_name(connector), max_width,
+ max_height);
+
width = max_width;
height = max_height;
/*
- * if specific driver want to find desired_mode using maxmum
+ * If the specific driver wants to find desired_mode using maximum
* resolution then get max width and height from that driver.
*/
- if (ops && ops->get_max_resol)
- ops->get_max_resol(manager->dev, &width, &height);
+ if (display->panel_ops->get_max_res)
+ display->panel_ops->get_max_res(display->panel_ctx, &width,
+ &height);
- return drm_helper_probe_single_connector_modes(connector, width,
+ ret = drm_helper_probe_single_connector_modes(connector, width,
height);
+ if (ret < 0) {
+ DRM_ERROR("Failed to probe connector modes ret=%d\n", ret);
+ return ret;
+ }
+
+ if (display->controller_ops->adjust_modes)
+ display->controller_ops->adjust_modes(display->controller_ctx,
+ connector);
+
+ return ret;
}
/* get detection status of display device. */
static enum drm_connector_status
exynos_drm_connector_detect(struct drm_connector *connector, bool force)
{
- struct exynos_drm_connector *exynos_connector =
- to_exynos_connector(connector);
- struct exynos_drm_manager *manager = exynos_connector->manager;
- struct exynos_drm_display_ops *display_ops =
- manager->display_ops;
- enum drm_connector_status status = connector_status_disconnected;
-
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- if (display_ops && display_ops->is_connected) {
- if (display_ops->is_connected(manager->dev))
- status = connector_status_connected;
- else
- status = connector_status_disconnected;
- }
+ struct exynos_drm_display *display = display_from_connector(connector);
+ enum drm_connector_status status;
+
+ if (display->panel_ops->is_connected &&
+ display->panel_ops->is_connected(display->panel_ctx))
+ status = connector_status_connected;
+ else
+ status = connector_status_disconnected;
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force: %d == %s\n",
+ DRM_BASE_ID(connector),
+ drm_get_connector_name(connector), force,
+ drm_get_connector_status_name(status));
return status;
}
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
- DRM_DEBUG_KMS("%s\n", __FILE__);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", DRM_BASE_ID(connector),
+ drm_get_connector_name(connector));
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
struct drm_encoder *encoder)
{
struct exynos_drm_connector *exynos_connector;
- struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+ struct exynos_drm_display *display = exynos_drm_get_display(encoder);
struct drm_connector *connector;
int type;
int err;
- DRM_DEBUG_KMS("%s\n", __FILE__);
+ DRM_DEBUG_KMS("[DEV:%s] [ENCODER:%d:%s]\n", dev->devname,
+ DRM_BASE_ID(encoder), drm_get_encoder_name(encoder));
exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
if (!exynos_connector) {
}
connector = &exynos_connector->drm_connector;
+ connector->dpms = DRM_MODE_DPMS_OFF;
- switch (manager->display_ops->type) {
- case EXYNOS_DISPLAY_TYPE_HDMI:
+ switch (display->display_type) {
+ case EXYNOS_DRM_DISPLAY_TYPE_MIXER:
type = DRM_MODE_CONNECTOR_HDMIA;
connector->interlace_allowed = true;
connector->polled = DRM_CONNECTOR_POLL_HPD;
break;
- case EXYNOS_DISPLAY_TYPE_VIDI:
+ case EXYNOS_DRM_DISPLAY_TYPE_VIDI:
type = DRM_MODE_CONNECTOR_VIRTUAL;
connector->polled = DRM_CONNECTOR_POLL_HPD;
break;
+ case EXYNOS_DRM_DISPLAY_TYPE_FIMD:
+ type = DRM_MODE_CONNECTOR_eDP;
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ break;
default:
type = DRM_MODE_CONNECTOR_Unknown;
break;
goto err_connector;
exynos_connector->encoder_id = encoder->base.id;
- exynos_connector->manager = manager;
+ exynos_connector->display = display;
connector->encoder = encoder;
err = drm_mode_connector_attach_encoder(connector, encoder);
goto err_sysfs;
}
- DRM_DEBUG_KMS("connector has been created\n");
+ DRM_DEBUG_KMS("New [CONNECTOR:%d:%s] attached to [ENCODER:%d:%s]\n",
+ DRM_BASE_ID(connector),
+ drm_get_connector_name(connector),
+ DRM_BASE_ID(encoder), drm_get_encoder_name(encoder));
return connector;