diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 7b90827bd73d..1b701b1133cb 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -33,6 +33,7 @@ #include "analogix_dp_core.h" #include "analogix_dp_reg.h" +#include "../../rockchip/rockchip_drm_drv.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -53,6 +54,9 @@ struct bridge_init { struct device_node *node; }; +static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *adj_mode); + static bool analogix_dp_bandwidth_ok(struct analogix_dp_device *dp, const struct drm_display_mode *mode, unsigned int rate, unsigned int lanes) @@ -1443,6 +1447,32 @@ static void analogix_dp_connector_force(struct drm_connector *connector) extcon_set_state_sync(dp->extcon, EXTCON_DISP_DP, false); } +static int +analogix_dp_atomic_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct rockchip_drm_private *private = connector->dev->dev_private; + struct analogix_dp_device *dp = to_dp(connector); + + if (property == private->split_area_prop) { + switch (dp->split_area) { + case 1: + *val = ROCKCHIP_DRM_SPLIT_LEFT_SIDE; + break; + case 2: + *val = ROCKCHIP_DRM_SPLIT_RIGHT_SIDE; + break; + default: + *val = ROCKCHIP_DRM_SPLIT_UNSET; + break; + } + } + + return 0; +} + static const struct drm_connector_funcs analogix_dp_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = analogix_dp_connector_detect, @@ -1451,6 +1481,7 @@ static const struct drm_connector_funcs analogix_dp_connector_funcs = { .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .force = analogix_dp_connector_force, + .atomic_get_property = analogix_dp_atomic_connector_get_property, }; static int analogix_dp_bridge_attach(struct drm_bridge *bridge, @@ -1481,6 +1512,7 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge, if (!dp->plat_data->skip_connector) { int connector_type = DRM_MODE_CONNECTOR_eDP; + struct rockchip_drm_private *private; if (dp->plat_data->bridge && dp->plat_data->bridge->type != DRM_MODE_CONNECTOR_Unknown) @@ -1500,6 +1532,13 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge, return ret; } + private = connector->dev->dev_private; + + if (dp->split_area) + drm_object_attach_property(&connector->base, + private->split_area_prop, + dp->split_area); + drm_connector_helper_add(connector, &analogix_dp_connector_helper_funcs); drm_connector_attach_encoder(connector, encoder); @@ -1576,13 +1615,17 @@ analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state; + struct drm_crtc_state *old_crtc_state, *new_crtc_state; crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); + + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); + analogix_dp_bridge_mode_set(bridge, &new_crtc_state->adjusted_mode); + /* Don't touch the panel if we're coming back from PSR */ if (old_crtc_state && old_crtc_state->self_refresh_active) return; @@ -1791,7 +1834,6 @@ analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, } static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *orig_mode, const struct drm_display_mode *adj_mode) { struct analogix_dp_device *dp = bridge->driver_private; @@ -1911,7 +1953,7 @@ analogix_dp_bridge_mode_valid(struct drm_bridge *bridge, drm_mode_copy(&m, mode); - if (dp->plat_data->split_mode) + if (dp->plat_data->split_mode || dp->plat_data->dual_connector_split) dp->plat_data->convert_to_origin_mode(&m); max_link_rate = min_t(u32, dp->video_info.max_link_rate, @@ -1935,7 +1977,6 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = { .atomic_enable = analogix_dp_bridge_atomic_enable, .atomic_disable = analogix_dp_bridge_atomic_disable, .atomic_post_disable = analogix_dp_bridge_atomic_post_disable, - .mode_set = analogix_dp_bridge_mode_set, .attach = analogix_dp_bridge_attach, .detach = analogix_dp_bridge_detach, .mode_valid = analogix_dp_bridge_mode_valid, @@ -2074,6 +2115,9 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) return ret; } + if (device_property_read_u32(dp->dev, "split-area", &dp->split_area)) + dp->split_area = 0; + return 0; } diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index f5d0c25f31ec..87c9cefbce1b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -195,6 +195,8 @@ struct analogix_dp_device { struct analogix_dp_plat_data *plat_data; struct extcon_dev *extcon; struct analogix_dp_compliance compliance; + + u32 split_area; }; /* analogix_dp_reg.c */ diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 54b65177fc84..603b7867723b 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -447,6 +447,16 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, } else { s->output_if |= dp->id ? VOP_OUTPUT_IF_eDP1 : VOP_OUTPUT_IF_eDP0; } + + if (dp->plat_data.dual_connector_split) { + s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CONNECTOR_SPLIT_MODE; + + if (dp->plat_data.left_display) + s->output_if_left_panel |= dp->id ? + VOP_OUTPUT_IF_eDP1 : + VOP_OUTPUT_IF_eDP0; + } + s->output_bpc = di->bpc; s->bus_flags = di->bus_flags; s->tv_state = &conn_state->tv; @@ -688,6 +698,12 @@ static int rockchip_dp_probe(struct platform_device *pdev) device_property_read_u32(dev, "min-refresh-rate", &dp->min_refresh_rate); device_property_read_u32(dev, "max-refresh-rate", &dp->max_refresh_rate); + if (dp->data->split_mode && device_property_read_bool(dev, "dual-connector-split")) { + dp->plat_data.dual_connector_split = true; + if (device_property_read_bool(dev, "left-display")) + dp->plat_data.left_display = true; + } + ret = component_add(dev, &rockchip_dp_component_ops); if (ret) goto err_dp_remove; diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c index eea85ec5d1f4..83c186eccd95 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c @@ -274,6 +274,11 @@ struct dw_mipi_dsi2 { struct rockchip_drm_sub_dev sub_dev; struct gpio_desc *te_gpio; + + /* split with other display interface */ + bool dual_connector_split; + bool left_display; + u32 split_area; }; static inline struct dw_mipi_dsi2 *host_to_dsi2(struct mipi_dsi_host *host) @@ -447,7 +452,8 @@ static void dw_mipi_dsi2_post_disable(struct dw_mipi_dsi2 *dsi2) dw_mipi_dsi2_post_disable(dsi2->slave); } -static void dw_mipi_dsi2_encoder_disable(struct drm_encoder *encoder) +static void dw_mipi_dsi2_encoder_atomic_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder); struct drm_crtc *crtc = encoder->crtc; @@ -834,9 +840,53 @@ static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2) dw_mipi_dsi2_enable(dsi2->slave); } -static void dw_mipi_dsi2_encoder_enable(struct drm_encoder *encoder) +static int dw_mipi_dsi2_encoder_mode_set(struct dw_mipi_dsi2 *dsi2, + struct drm_atomic_state *state) +{ + struct drm_encoder *encoder = &dsi2->encoder; + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + const struct drm_display_mode *adjusted_mode; + struct drm_display_mode *mode = &dsi2->mode; + + connector = drm_atomic_get_new_connector_for_encoder(state, encoder); + if (!connector) + return -ENODEV; + + conn_state = drm_atomic_get_new_connector_state(state, connector); + if (!conn_state) + return -ENODEV; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (!crtc_state) { + dev_err(dsi2->dev, "failed to get crtc state\n"); + return -ENODEV; + } + + adjusted_mode = &crtc_state->adjusted_mode; + drm_mode_copy(mode, adjusted_mode); + + if (dsi2->dual_connector_split) + drm_mode_convert_to_origin_mode(mode); + + if (dsi2->slave) + drm_mode_copy(&dsi2->slave->mode, mode); + + return 0; +} + +static void dw_mipi_dsi2_encoder_atomic_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder); + int ret; + + ret = dw_mipi_dsi2_encoder_mode_set(dsi2, state); + if (ret) { + dev_err(dsi2->dev, "failed to set dsi2 mode\n"); + return; + } dw_mipi_dsi2_get_lane_rate(dsi2); @@ -864,8 +914,8 @@ static void dw_mipi_dsi2_encoder_enable(struct drm_encoder *encoder) static int dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); @@ -914,6 +964,15 @@ dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder, s->output_if |= VOP_OUTPUT_IF_MIPI1; } + if (dsi2->dual_connector_split) { + s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CONNECTOR_SPLIT_MODE; + + if (dsi2->left_display) + s->output_if_left_panel |= dsi2->id ? + VOP_OUTPUT_IF_MIPI1 : + VOP_OUTPUT_IF_MIPI0; + } + if (dsi2->dsc_enable) { s->dsc_enable = 1; s->dsc_sink_cap.version_major = dsi2->version_major; @@ -930,18 +989,6 @@ dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder, return 0; } -static void -dw_mipi_dsi2_encoder_atomic_mode_set(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *connector_state) -{ - struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder); - - drm_mode_copy(&dsi2->mode, &crtc_state->adjusted_mode); - if (dsi2->slave) - drm_mode_copy(&dsi2->slave->mode, &crtc_state->adjusted_mode); -} - static void dw_mipi_dsi2_loader_protect(struct dw_mipi_dsi2 *dsi2, bool on) { if (on) { @@ -977,10 +1024,9 @@ static int dw_mipi_dsi2_encoder_loader_protect(struct drm_encoder *encoder, static const struct drm_encoder_helper_funcs dw_mipi_dsi2_encoder_helper_funcs = { - .enable = dw_mipi_dsi2_encoder_enable, - .disable = dw_mipi_dsi2_encoder_disable, + .atomic_enable = dw_mipi_dsi2_encoder_atomic_enable, + .atomic_disable = dw_mipi_dsi2_encoder_atomic_disable, .atomic_check = dw_mipi_dsi2_encoder_atomic_check, - .atomic_mode_set = dw_mipi_dsi2_encoder_atomic_mode_set, }; static int dw_mipi_dsi2_connector_get_modes(struct drm_connector *connector) @@ -1062,6 +1108,32 @@ static void dw_mipi_dsi2_drm_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); } +static int +dw_mipi_dsi2_atomic_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct rockchip_drm_private *private = connector->dev->dev_private; + struct dw_mipi_dsi2 *dsi2 = con_to_dsi2(connector); + + if (property == private->split_area_prop) { + switch (dsi2->split_area) { + case 1: + *val = ROCKCHIP_DRM_SPLIT_LEFT_SIDE; + break; + case 2: + *val = ROCKCHIP_DRM_SPLIT_RIGHT_SIDE; + break; + default: + *val = ROCKCHIP_DRM_SPLIT_UNSET; + break; + } + } + + return 0; +} + static const struct drm_connector_funcs dw_mipi_dsi2_atomic_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = dw_mipi_dsi2_connector_detect, @@ -1069,6 +1141,7 @@ static const struct drm_connector_funcs dw_mipi_dsi2_atomic_connector_funcs = { .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_get_property = dw_mipi_dsi2_atomic_connector_get_property, }; static int dw_mipi_dsi2_dual_channel_probe(struct dw_mipi_dsi2 *dsi2) @@ -1215,8 +1288,16 @@ connector_cleanup: static int dw_mipi_dsi2_register_sub_dev(struct dw_mipi_dsi2 *dsi2, struct drm_connector *connector) { + struct rockchip_drm_private *private; struct device *dev = dsi2->dev; + private = connector->dev->dev_private; + + if (dsi2->split_area) + drm_object_attach_property(&connector->base, + private->split_area_prop, + dsi2->split_area); + dsi2->sub_dev.connector = connector; dsi2->sub_dev.of_node = dev->of_node; dsi2->sub_dev.loader_protect = dw_mipi_dsi2_encoder_loader_protect; @@ -1541,6 +1622,16 @@ static int dw_mipi_dsi2_probe(struct platform_device *pdev) dsi2->pdata = of_device_get_match_data(dev); platform_set_drvdata(pdev, dsi2); + if (device_property_read_bool(dev, "dual-connector-split")) { + dsi2->dual_connector_split = true; + + if (device_property_read_bool(dev, "left-display")) + dsi2->left_display = true; + } + + if (device_property_read_u32(dev, "split-area", &dsi2->split_area)) + dsi2->split_area = 0; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 1921b526f58d..ddb27d358701 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -140,6 +140,7 @@ void drm_mode_convert_to_split_mode(struct drm_display_mode *mode) hbp = mode->htotal - mode->hsync_end; mode->clock *= 2; + mode->crtc_clock *= 2; mode->hdisplay = hactive * 2; mode->hsync_start = mode->hdisplay + hfp * 2; mode->hsync_end = mode->hsync_start + hsync * 2; @@ -158,6 +159,7 @@ void drm_mode_convert_to_origin_mode(struct drm_display_mode *mode) hbp = mode->htotal - mode->hsync_end; mode->clock /= 2; + mode->crtc_clock /= 2; mode->hdisplay = hactive / 2; mode->hsync_start = mode->hdisplay + hfp / 2; mode->hsync_end = mode->hsync_start + hsync / 2; diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c index 0c5761b3b0e6..ef4a586ea50c 100644 --- a/drivers/mtd/nand/spi/fmsh.c +++ b/drivers/mtd/nand/spi/fmsh.c @@ -80,6 +80,31 @@ static const struct mtd_ooblayout_ops fm25s01_ooblayout = { .free = fm25s01_ooblayout_free, }; +/* + * ecc bits: 0xC0[4,6] + * [0b000], No bit errors were detected; + * [0b001] and [0b011], 1~6 Bit errors were detected and corrected. Not + * reach Flipping Bits; + * [0b101], Bit error count equals the bit flip + * detection threshold + * [0b010], Multiple bit errors were detected and + * not corrected. + * others, Reserved. + */ +static int fm25s01bi3_ecc_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + struct nand_device *nand = spinand_to_nand(spinand); + u8 eccsr = (status & GENMASK(6, 4)) >> 4; + + if (eccsr <= 1 || eccsr == 3) + return eccsr; + else if (eccsr == 5) + return nanddev_get_ecc_requirements(nand)->strength; + else + return -EBADMSG; +} + static const struct spinand_info fmsh_spinand_table[] = { SPINAND_INFO("FM25S01A", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), @@ -97,11 +122,11 @@ static const struct spinand_info fmsh_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 1, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)), SPINAND_INFO("FM25S01", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, @@ -110,13 +135,22 @@ static const struct spinand_info fmsh_spinand_table[] = { SPINAND_ECCINFO(&fm25s01_ooblayout, NULL)), SPINAND_INFO("FM25LS01", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA5), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, SPINAND_ECCINFO(&fm25s01_ooblayout, NULL)), + SPINAND_INFO("FM25S01BI3", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fm25s01_ooblayout, fm25s01bi3_ecc_ecc_get_status)), }; static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = { diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c index bb2e517755fb..403c33157c37 100644 --- a/drivers/mtd/nand/spi/foresee.c +++ b/drivers/mtd/nand/spi/foresee.c @@ -115,6 +115,24 @@ static const struct spinand_info foresee_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)), + SPINAND_INFO("F35UQA002G-WWT", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x62), + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)), + SPINAND_INFO("F35UQA001G-WWT", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x61), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)), }; static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = { diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index e912503a9149..09f0dfeff6e8 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -43,6 +43,11 @@ struct analogix_dp_plat_data { bool ssc; bool split_mode; + + /* split with other display interface */ + bool dual_connector_split; + bool left_display; + struct analogix_dp_device *left; struct analogix_dp_device *right;