diff options
Diffstat (limited to 'drivers/gpu/drm/ast/ast_mode.c')
-rw-r--r-- | drivers/gpu/drm/ast/ast_mode.c | 426 |
1 files changed, 310 insertions, 116 deletions
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 956c8982192b..45b56b39ad47 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -40,6 +40,7 @@ #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_vram_helper.h> +#include <drm/drm_managed.h> #include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> @@ -471,7 +472,10 @@ static void ast_set_color_reg(struct ast_private *ast, static void ast_set_crtthd_reg(struct ast_private *ast) { /* Set Threshold */ - if (ast->chip == AST2300 || ast->chip == AST2400 || + if (ast->chip == AST2600) { + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0xe0); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0xa0); + } else if (ast->chip == AST2300 || ast->chip == AST2400 || ast->chip == AST2500) { ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78); ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60); @@ -801,11 +805,11 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state); struct drm_framebuffer *fb = new_state->fb; struct ast_private *ast = to_ast_private(plane->dev); - struct dma_buf_map dst_map = + struct iosys_map dst_map = ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].map; u64 dst_off = ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].off; - struct dma_buf_map src_map = shadow_plane_state->data[0]; + struct iosys_map src_map = shadow_plane_state->data[0]; unsigned int offset_x, offset_y; u16 x, y; u8 x_offset, y_offset; @@ -883,7 +887,7 @@ static void ast_cursor_plane_destroy(struct drm_plane *plane) struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); size_t i; struct drm_gem_vram_object *gbo; - struct dma_buf_map map; + struct iosys_map map; for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) { gbo = ast_cursor_plane->hwc[i].gbo; @@ -910,7 +914,7 @@ static int ast_cursor_plane_init(struct ast_private *ast) struct drm_plane *cursor_plane = &ast_cursor_plane->base; size_t size, i; struct drm_gem_vram_object *gbo; - struct dma_buf_map map; + struct iosys_map map; int ret; s64 off; @@ -1002,6 +1006,71 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) } } +static enum drm_mode_status +ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) +{ + struct ast_private *ast = to_ast_private(crtc->dev); + enum drm_mode_status status; + uint32_t jtemp; + + if (ast->support_wide_screen) { + if ((mode->hdisplay == 1680) && (mode->vdisplay == 1050)) + return MODE_OK; + if ((mode->hdisplay == 1280) && (mode->vdisplay == 800)) + return MODE_OK; + if ((mode->hdisplay == 1440) && (mode->vdisplay == 900)) + return MODE_OK; + if ((mode->hdisplay == 1360) && (mode->vdisplay == 768)) + return MODE_OK; + if ((mode->hdisplay == 1600) && (mode->vdisplay == 900)) + return MODE_OK; + + if ((ast->chip == AST2100) || (ast->chip == AST2200) || + (ast->chip == AST2300) || (ast->chip == AST2400) || + (ast->chip == AST2500)) { + if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080)) + return MODE_OK; + + if ((mode->hdisplay == 1920) && (mode->vdisplay == 1200)) { + jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff); + if (jtemp & 0x01) + return MODE_NOMODE; + else + return MODE_OK; + } + } + } + + status = MODE_NOMODE; + + switch (mode->hdisplay) { + case 640: + if (mode->vdisplay == 480) + status = MODE_OK; + break; + case 800: + if (mode->vdisplay == 600) + status = MODE_OK; + break; + case 1024: + if (mode->vdisplay == 768) + status = MODE_OK; + break; + case 1280: + if (mode->vdisplay == 1024) + status = MODE_OK; + break; + case 1600: + if (mode->vdisplay == 1200) + status = MODE_OK; + break; + default: + break; + } + + return status; +} + static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { @@ -1104,6 +1173,7 @@ ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, } static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { + .mode_valid = ast_crtc_helper_mode_valid, .atomic_check = ast_crtc_helper_atomic_check, .atomic_flush = ast_crtc_helper_atomic_flush, .atomic_enable = ast_crtc_helper_atomic_enable, @@ -1184,128 +1254,229 @@ static int ast_crtc_init(struct drm_device *dev) } /* - * Encoder + * VGA Connector */ -static int ast_encoder_init(struct drm_device *dev) +static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) { - struct ast_private *ast = to_ast_private(dev); - struct drm_encoder *encoder = &ast->encoder; + struct ast_vga_connector *ast_vga_connector = to_ast_vga_connector(connector); + struct edid *edid; + int count; + + if (!ast_vga_connector->i2c) + goto err_drm_connector_update_edid_property; + + edid = drm_get_edid(connector, &ast_vga_connector->i2c->adapter); + if (!edid) + goto err_drm_connector_update_edid_property; + + count = drm_add_edid_modes(connector, edid); + kfree(edid); + + return count; + +err_drm_connector_update_edid_property: + drm_connector_update_edid_property(connector, NULL); + return 0; +} + +static const struct drm_connector_helper_funcs ast_vga_connector_helper_funcs = { + .get_modes = ast_vga_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs ast_vga_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int ast_vga_connector_init(struct drm_device *dev, + struct ast_vga_connector *ast_vga_connector) +{ + struct drm_connector *connector = &ast_vga_connector->base; + int ret; + + ast_vga_connector->i2c = ast_i2c_create(dev); + if (!ast_vga_connector->i2c) + drm_err(dev, "failed to add ddc bus for connector\n"); + + if (ast_vga_connector->i2c) + ret = drm_connector_init_with_ddc(dev, connector, &ast_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &ast_vga_connector->i2c->adapter); + else + ret = drm_connector_init(dev, connector, &ast_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA); + if (ret) + return ret; + + drm_connector_helper_add(connector, &ast_vga_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + + return 0; +} + +static int ast_vga_output_init(struct ast_private *ast) +{ + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.vga.encoder; + struct ast_vga_connector *ast_vga_connector = &ast->output.vga.vga_connector; + struct drm_connector *connector = &ast_vga_connector->base; int ret; ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC); if (ret) return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); - encoder->possible_crtcs = 1; + ret = ast_vga_connector_init(dev, ast_vga_connector); + if (ret) + return ret; + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; return 0; } /* - * Connector + * SIL164 Connector */ -static int ast_get_modes(struct drm_connector *connector) +static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector) +{ + struct ast_sil164_connector *ast_sil164_connector = to_ast_sil164_connector(connector); + struct edid *edid; + int count; + + if (!ast_sil164_connector->i2c) + goto err_drm_connector_update_edid_property; + + edid = drm_get_edid(connector, &ast_sil164_connector->i2c->adapter); + if (!edid) + goto err_drm_connector_update_edid_property; + + count = drm_add_edid_modes(connector, edid); + kfree(edid); + + return count; + +err_drm_connector_update_edid_property: + drm_connector_update_edid_property(connector, NULL); + return 0; +} + +static const struct drm_connector_helper_funcs ast_sil164_connector_helper_funcs = { + .get_modes = ast_sil164_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs ast_sil164_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int ast_sil164_connector_init(struct drm_device *dev, + struct ast_sil164_connector *ast_sil164_connector) { - struct ast_connector *ast_connector = to_ast_connector(connector); - struct ast_private *ast = to_ast_private(connector->dev); - struct edid *edid = NULL; - bool flags = false; + struct drm_connector *connector = &ast_sil164_connector->base; int ret; - if (ast->tx_chip_type == AST_TX_DP501) { - ast->dp501_maxclk = 0xff; - edid = kmalloc(128, GFP_KERNEL); - if (!edid) - return -ENOMEM; + ast_sil164_connector->i2c = ast_i2c_create(dev); + if (!ast_sil164_connector->i2c) + drm_err(dev, "failed to add ddc bus for connector\n"); - flags = ast_dp501_read_edid(connector->dev, (u8 *)edid); - if (flags) - ast->dp501_maxclk = ast_get_dp501_max_clk(connector->dev); - else - kfree(edid); - } - if (!flags && ast_connector->i2c) - edid = drm_get_edid(connector, &ast_connector->i2c->adapter); - if (edid) { - drm_connector_update_edid_property(&ast_connector->base, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); + if (ast_sil164_connector->i2c) + ret = drm_connector_init_with_ddc(dev, connector, &ast_sil164_connector_funcs, + DRM_MODE_CONNECTOR_DVII, + &ast_sil164_connector->i2c->adapter); + else + ret = drm_connector_init(dev, connector, &ast_sil164_connector_funcs, + DRM_MODE_CONNECTOR_DVII); + if (ret) return ret; - } - drm_connector_update_edid_property(&ast_connector->base, NULL); + + drm_connector_helper_add(connector, &ast_sil164_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + return 0; } -static enum drm_mode_status ast_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static int ast_sil164_output_init(struct ast_private *ast) { - struct ast_private *ast = to_ast_private(connector->dev); - int flags = MODE_NOMODE; - uint32_t jtemp; + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.sil164.encoder; + struct ast_sil164_connector *ast_sil164_connector = &ast->output.sil164.sil164_connector; + struct drm_connector *connector = &ast_sil164_connector->base; + int ret; - if (ast->support_wide_screen) { - if ((mode->hdisplay == 1680) && (mode->vdisplay == 1050)) - return MODE_OK; - if ((mode->hdisplay == 1280) && (mode->vdisplay == 800)) - return MODE_OK; - if ((mode->hdisplay == 1440) && (mode->vdisplay == 900)) - return MODE_OK; - if ((mode->hdisplay == 1360) && (mode->vdisplay == 768)) - return MODE_OK; - if ((mode->hdisplay == 1600) && (mode->vdisplay == 900)) - return MODE_OK; + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); - if ((ast->chip == AST2100) || (ast->chip == AST2200) || - (ast->chip == AST2300) || (ast->chip == AST2400) || - (ast->chip == AST2500)) { - if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080)) - return MODE_OK; + ret = ast_sil164_connector_init(dev, ast_sil164_connector); + if (ret) + return ret; - if ((mode->hdisplay == 1920) && (mode->vdisplay == 1200)) { - jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff); - if (jtemp & 0x01) - return MODE_NOMODE; - else - return MODE_OK; - } - } - } - switch (mode->hdisplay) { - case 640: - if (mode->vdisplay == 480) - flags = MODE_OK; - break; - case 800: - if (mode->vdisplay == 600) - flags = MODE_OK; - break; - case 1024: - if (mode->vdisplay == 768) - flags = MODE_OK; - break; - case 1280: - if (mode->vdisplay == 1024) - flags = MODE_OK; - break; - case 1600: - if (mode->vdisplay == 1200) - flags = MODE_OK; - break; - default: - return flags; - } + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; - return flags; + return 0; } -static const struct drm_connector_helper_funcs ast_connector_helper_funcs = { - .get_modes = ast_get_modes, - .mode_valid = ast_mode_valid, +/* + * DP501 Connector + */ + +static int ast_dp501_connector_helper_get_modes(struct drm_connector *connector) +{ + void *edid; + bool succ; + int count; + + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!edid) + goto err_drm_connector_update_edid_property; + + succ = ast_dp501_read_edid(connector->dev, edid); + if (!succ) + goto err_kfree; + + drm_connector_update_edid_property(connector, edid); + count = drm_add_edid_modes(connector, edid); + kfree(edid); + + return count; + +err_kfree: + kfree(edid); +err_drm_connector_update_edid_property: + drm_connector_update_edid_property(connector, NULL); + return 0; +} + +static const struct drm_connector_helper_funcs ast_dp501_connector_helper_funcs = { + .get_modes = ast_dp501_connector_helper_get_modes, }; -static const struct drm_connector_funcs ast_connector_funcs = { +static const struct drm_connector_funcs ast_dp501_connector_funcs = { .reset = drm_atomic_helper_connector_reset, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = drm_connector_cleanup, @@ -1313,33 +1484,45 @@ static const struct drm_connector_funcs ast_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int ast_connector_init(struct drm_device *dev) +static int ast_dp501_connector_init(struct drm_device *dev, struct drm_connector *connector) { - struct ast_private *ast = to_ast_private(dev); - struct ast_connector *ast_connector = &ast->connector; - struct drm_connector *connector = &ast_connector->base; - struct drm_encoder *encoder = &ast->encoder; - - ast_connector->i2c = ast_i2c_create(dev); - if (!ast_connector->i2c) - drm_err(dev, "failed to add ddc bus for connector\n"); + int ret; - if (ast_connector->i2c) - drm_connector_init_with_ddc(dev, connector, &ast_connector_funcs, - DRM_MODE_CONNECTOR_VGA, - &ast_connector->i2c->adapter); - else - drm_connector_init(dev, connector, &ast_connector_funcs, - DRM_MODE_CONNECTOR_VGA); + ret = drm_connector_init(dev, connector, &ast_dp501_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); + if (ret) + return ret; - drm_connector_helper_add(connector, &ast_connector_helper_funcs); + drm_connector_helper_add(connector, &ast_dp501_connector_helper_funcs); connector->interlace_allowed = 0; connector->doublescan_allowed = 0; connector->polled = DRM_CONNECTOR_POLL_CONNECT; - drm_connector_attach_encoder(connector, encoder); + return 0; +} + +static int ast_dp501_output_init(struct ast_private *ast) +{ + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.dp501.encoder; + struct drm_connector *connector = &ast->output.dp501.connector; + int ret; + + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = ast_dp501_connector_init(dev, connector); + if (ret) + return ret; + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; return 0; } @@ -1348,8 +1531,7 @@ static int ast_connector_init(struct drm_device *dev) * Mode config */ -static const struct drm_mode_config_helper_funcs -ast_mode_config_helper_funcs = { +static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; @@ -1401,8 +1583,20 @@ int ast_mode_config_init(struct ast_private *ast) return ret; ast_crtc_init(dev); - ast_encoder_init(dev); - ast_connector_init(dev); + + switch (ast->tx_chip_type) { + case AST_TX_NONE: + ret = ast_vga_output_init(ast); + break; + case AST_TX_SIL164: + ret = ast_sil164_output_init(ast); + break; + case AST_TX_DP501: + ret = ast_dp501_output_init(ast); + break; + } + if (ret) + return ret; drm_mode_config_reset(dev); |