Merge commit '1ebca99c8f1e959c86646bc3cd72aa22dabb71b0'

* commit '1ebca99c8f1e959c86646bc3cd72aa22dabb71b0':
  media: i2c: maxim4c: support subscribe hot plug detect event
  drm/rockchip: dsi2: add support PSR for mipi command mode
  drm/rockchip: dsi2: set phy mode in .loader_protect helper
  drm/rockchip: dw-dp: support external bridge
  drm/rockchip: dw-dp: support fix stream and connector
  phy: rockchip: mipi-dcphy: optimize signal
  arm64: dts: rockchip: rk3576-iotest: enable edp sound for edp2dp board
  drm/rockchip: vop2: resolution bigger than 2560 need high performance
  drm/rockchip: vop2: recover vop aclk when enter psr and suspend
  drm/rockchip: vop2: udpate linear 10bit yuv format align role
  arm64: dts: rockchip: rk3588: enable emmc command queue
  arm64: dts: rockchip: rk3576: enable emmc command queue
  mmc: sdhci-of-dwcmshc: add command queue support for rockchip SOCs
  BACKPORT: mmc: sdhci-of-dwcmshc: Implement SDHCI CQE support
  BACKPORT: mmc: sdhci-of-dwcmshc: Add error handling in dwcmshc_resume
  UPSTREAM: mmc: cqhci: Add cqhci set_tran_desc() callback
  ASoC: rk817: Fix compile warning

Change-Id: I1f33e6d6e1b5afed0a25d9bdc979ba78ae1f09bc
This commit is contained in:
Tao Huang
2024-06-04 20:46:51 +08:00
18 changed files with 714 additions and 64 deletions

View File

@@ -37,6 +37,10 @@
status = "okay";
};
&edp_sound {
status = "okay";
};
&hdmi {
status = "disabled";
};
@@ -66,6 +70,10 @@
status = "disabled";
};
&sai6 {
status = "okay";
};
&vp0 {
assigned-clocks = <&cru DCLK_VP0_SRC>;
assigned-clock-parents = <&cru PLL_VPLL>;

View File

@@ -3993,6 +3993,7 @@
<&cru SRST_T_EMMC>;
reset-names = "core", "bus", "axi", "block", "timer";
max-frequency = <200000000>;
supports-cqe;
status = "disabled";
};

View File

@@ -5711,6 +5711,7 @@
<&cru SRST_T_EMMC>;
reset-names = "core", "bus", "axi", "block", "timer";
max-frequency = <200000000>;
supports-cqe;
status = "disabled";
};

View File

@@ -418,12 +418,14 @@ struct dw_dp_mst_enc {
struct dw_dp_video video;
struct dw_dp_audio *audio;
struct device_node *port_node;
struct drm_bridge *next_bridge;
DECLARE_BITMAP(sdp_reg_bank, SDP_REG_BANK_SIZE);
struct dw_dp_mst_conn *mst_conn;
struct dw_dp *dp;
int stream_id;
int fix_port_num;
bool active;
};
@@ -488,6 +490,7 @@ struct dw_dp {
bool is_loader_protect;
bool support_mst;
bool is_mst;
bool is_fix_port;
int mst_port_num;
int active_mst_links;
struct drm_dp_mst_topology_mgr mst_mgr;
@@ -1306,6 +1309,7 @@ static int dw_dp_mst_info_dump(struct seq_file *s, void *data)
struct dw_dp *dp = node->info_ent->data;
struct dw_dp_mst_conn *mst_conn;
struct drm_property_blob *path_blob;
int i;
if (dp->mst_mgr.cbs) {
drm_dp_mst_dump_topology(s, &dp->mst_mgr);
@@ -1321,6 +1325,17 @@ static int dw_dp_mst_info_dump(struct seq_file *s, void *data)
(char *)path_blob->data);
}
seq_puts(s, "\n");
if (dp->is_fix_port) {
seq_puts(s, "\n*** Fix port info ***\n");
seq_puts(s, "stream id | port num\n");
for (i = 0; i < dp->mst_port_num; i++) {
if (!dp->mst_enc[i].dp)
continue;
seq_printf(s, "%-16d %d\n", dp->mst_enc[i].stream_id,
dp->mst_enc[i].fix_port_num);
}
}
}
return 0;
@@ -3250,14 +3265,39 @@ static const struct drm_connector_funcs dw_dp_mst_connector_funcs = {
.early_unregister = dw_dp_mst_connector_early_unregister,
};
static struct drm_bridge *dw_dp_mst_connector_get_bridge(struct dw_dp_mst_conn *mst_conn)
{
struct dw_dp *dp = mst_conn->dp;
int i;
if (!dp->is_fix_port)
return NULL;
for (i = 0; i < dp->mst_port_num; i++)
if (dp->mst_enc[i].fix_port_num == mst_conn->port->port_num)
return dp->mst_enc[i].next_bridge;
return NULL;
}
static int dw_dp_mst_connector_get_modes(struct drm_connector *connector)
{
struct dw_dp_mst_conn *mst_conn = container_of(connector,
struct dw_dp_mst_conn, connector);
struct dw_dp *dp = mst_conn->dp;
struct drm_bridge *bridge;
struct edid *edid;
int num_modes = 0;
if (dp->is_fix_port) {
bridge = dw_dp_mst_connector_get_bridge(mst_conn);
if (bridge) {
num_modes = drm_bridge_get_modes(bridge, connector);
if (num_modes)
return num_modes;
}
}
edid = drm_dp_mst_get_edid(connector, &dp->mst_mgr, mst_conn->port);
if (edid) {
drm_connector_update_edid_property(connector, edid);
@@ -3924,6 +3964,8 @@ dw_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_p
for (i = 0; i < dp->mst_port_num; i++) {
if (!of_device_is_available(dp->mst_enc[i].port_node))
continue;
if (dp->is_fix_port && dp->mst_enc[i].fix_port_num != port->port_num)
continue;
ret = drm_connector_attach_encoder(&mst_conn->connector, &dp->mst_enc[i].encoder);
if (ret)
goto err;
@@ -3979,6 +4021,57 @@ dw_dp_create_fake_mst_encoders(struct dw_dp *dp)
return true;
}
static int dw_dp_mst_get_fix_port(struct dw_dp *dp)
{
char *prop_name = "rockchip,mst-fixed-ports";
int elem_len, ret, i;
int elem_data[DPTX_MAX_STREAMS];
if (!device_property_present(dp->dev, prop_name))
return 0;
elem_len = device_property_count_u32(dp->dev, prop_name);
if (dp->mst_port_num != elem_len)
return -EINVAL;
ret = device_property_read_u32_array(dp->dev, prop_name, elem_data, elem_len);
if (ret)
return -EINVAL;
dp->is_fix_port = true;
for (i = 0; i < dp->mst_port_num; i++)
dp->mst_enc[i].fix_port_num = elem_data[i];
return 0;
}
static int dw_dp_mst_find_ext_bridges(struct dw_dp *dp)
{
struct dw_dp_mst_enc *mst_enc;
int i, ret;
for (i = 0; i < dp->mst_port_num; i++) {
mst_enc = &dp->mst_enc[i];
if (!of_device_is_available(dp->mst_enc[i].port_node))
continue;
ret = drm_of_find_panel_or_bridge(mst_enc->port_node, 2, -1, NULL,
&mst_enc->next_bridge);
if (ret < 0 && ret != -ENODEV)
return ret;
if (mst_enc->next_bridge) {
ret = drm_bridge_attach(&mst_enc->encoder, mst_enc->next_bridge, NULL, 0);
if (ret) {
DRM_DEV_ERROR(dp->dev, "failed to attach next bridge: %d\n", ret);
return ret;
}
}
}
return 0;
}
static int dw_dp_mst_encoder_init(struct dw_dp *dp, int conn_base_id)
{
int ret;
@@ -3989,6 +4082,13 @@ static int dw_dp_mst_encoder_init(struct dw_dp *dp, int conn_base_id)
INIT_LIST_HEAD(&dp->mst_conn_list);
dp->mst_mgr.cbs = &mst_cbs;
dw_dp_create_fake_mst_encoders(dp);
ret = dw_dp_mst_get_fix_port(dp);
if (ret)
return ret;
ret = dw_dp_mst_find_ext_bridges(dp);
if (ret)
return ret;
ret = drm_dp_mst_topology_mgr_init(&dp->mst_mgr, dp->encoder.dev,
&dp->aux, 16, dp->mst_port_num, conn_base_id);
if (ret)
@@ -4025,7 +4125,9 @@ static int dw_dp_connector_init(struct dw_dp *dp)
drm_connector_attach_encoder(connector, bridge->encoder);
dw_dp_mst_encoder_init(dp, connector->base.id);
ret = dw_dp_mst_encoder_init(dp, connector->base.id);
if (ret)
return ret;
prop = drm_property_create_enum(connector->dev, 0, RK_IF_PROP_COLOR_DEPTH,
color_depth_enum_list,
ARRAY_SIZE(color_depth_enum_list));

View File

@@ -282,6 +282,9 @@ struct dw_mipi_dsi2 {
bool dual_connector_split;
bool left_display;
u32 split_area;
bool support_psr;
bool enabled;
};
static inline struct dw_mipi_dsi2 *host_to_dsi2(struct mipi_dsi_host *host)
@@ -318,6 +321,14 @@ static void grf_field_write(struct dw_mipi_dsi2 *dsi2, enum grf_reg_fields index
regmap_write(dsi2->grf, reg, (val << lsb) | (GENMASK(msb, lsb) << 16));
}
static int dw_mipi_dsi2_is_cmd_mode(struct dw_mipi_dsi2 *dsi2)
{
if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO))
return true;
return false;
}
static int cri_fifos_wait_avail(struct dw_mipi_dsi2 *dsi2)
{
u32 sts, mask;
@@ -432,53 +443,95 @@ static void dw_mipi_dsi2_set_cmd_mode(struct dw_mipi_dsi2 *dsi2)
mode, mode & COMMAND_MODE,
1000, MODE_STATUS_TIMEOUT_US);
if (ret < 0)
dev_err(dsi2->dev, "failed to enter data stream mode\n");
dev_err(dsi2->dev, "failed to enter command mode\n");
}
static void dw_mipi_dsi2_disable(struct dw_mipi_dsi2 *dsi2)
{
if (!dsi2->enabled)
goto out;
regmap_write(dsi2->regmap, DSI2_IPI_PIX_PKT_CFG, 0);
dw_mipi_dsi2_set_cmd_mode(dsi2);
out:
if (dsi2->slave)
dw_mipi_dsi2_disable(dsi2->slave);
}
static void dw_mipi_dsi2_post_disable(struct dw_mipi_dsi2 *dsi2)
{
if (!dsi2->enabled)
goto out;
dw_mipi_dsi2_irq_enable(dsi2, 0);
regmap_write(dsi2->regmap, DSI2_PWR_UP, RESET);
mipi_dcphy_power_off(dsi2);
pm_runtime_put(dsi2->dev);
out:
if (dsi2->slave)
dw_mipi_dsi2_post_disable(dsi2->slave);
}
static struct drm_crtc *dw_mipi_dsi2_get_new_crtc(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;
connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
if (!connector)
return NULL;
conn_state = drm_atomic_get_new_connector_state(state, connector);
if (!conn_state)
return NULL;
return conn_state->crtc;
}
static void dw_mipi_dsi2_encoder_atomic_disable(struct drm_encoder *encoder,
struct drm_atomic_state *state)
struct drm_atomic_state *old_state)
{
struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder);
struct drm_crtc *crtc = encoder->crtc;
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
struct rockchip_crtc_state *s = to_rockchip_crtc_state(encoder->crtc->state);
struct drm_crtc *new_crtc;
struct drm_crtc_state *new_crtc_state = NULL;
if (dsi2->panel)
drm_panel_disable(dsi2->panel);
new_crtc = dw_mipi_dsi2_get_new_crtc(dsi2, old_state);
if (new_crtc)
new_crtc_state = drm_atomic_get_new_crtc_state(old_state, new_crtc);
if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO))
if (new_crtc_state && new_crtc_state->self_refresh_active)
dev_dbg(dsi2->dev, "%s:%d: psr entry\n", __func__, __LINE__);
if (!new_crtc_state || !new_crtc_state->self_refresh_active) {
if (dsi2->panel)
drm_panel_disable(dsi2->panel);
}
if (dw_mipi_dsi2_is_cmd_mode(dsi2))
rockchip_drm_crtc_standby(encoder->crtc, 1);
dw_mipi_dsi2_disable(dsi2);
if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO))
if (dw_mipi_dsi2_is_cmd_mode(dsi2))
rockchip_drm_crtc_standby(encoder->crtc, 0);
if (dsi2->panel)
drm_panel_unprepare(dsi2->panel);
if (!new_crtc_state || !new_crtc_state->self_refresh_active) {
if (dsi2->panel)
drm_panel_unprepare(dsi2->panel);
}
dw_mipi_dsi2_post_disable(dsi2);
if (!crtc->state->active_changed)
dsi2->enabled = false;
if (dsi2->slave)
dsi2->slave->enabled = false;
if (!encoder->crtc->state->active_changed)
return;
if (dsi2->slave)
@@ -749,7 +802,7 @@ static void dw_mipi_dsi2_ipi_set(struct dw_mipi_dsi2 *dsi2)
* if the controller is intended to operate in data stream mode,
* no more steps are required.
*/
if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO))
if (dw_mipi_dsi2_is_cmd_mode(dsi2))
return;
vact = mode->crtc_vdisplay;
@@ -811,6 +864,9 @@ dw_mipi_dsi2_work_mode(struct dw_mipi_dsi2 *dsi2, u32 mode)
static void dw_mipi_dsi2_pre_enable(struct dw_mipi_dsi2 *dsi2)
{
if (dsi2->enabled)
goto out;
pm_runtime_get_sync(dsi2->dev);
dw_mipi_dsi2_host_softrst(dsi2);
@@ -827,6 +883,7 @@ static void dw_mipi_dsi2_pre_enable(struct dw_mipi_dsi2 *dsi2)
regmap_write(dsi2->regmap, DSI2_PWR_UP, POWER_UP);
dw_mipi_dsi2_set_cmd_mode(dsi2);
out:
if (dsi2->slave)
dw_mipi_dsi2_pre_enable(dsi2->slave);
}
@@ -853,6 +910,9 @@ static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2)
u32 mode;
int ret;
if (dsi2->enabled)
goto out;
dw_mipi_dsi2_clk_management(dsi2);
dw_mipi_dsi2_ipi_set(dsi2);
@@ -870,6 +930,7 @@ static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2)
else
dw_mipi_dsi2_set_data_stream_mode(dsi2);
out:
if (dsi2->slave)
dw_mipi_dsi2_enable(dsi2->slave);
}
@@ -943,8 +1004,19 @@ 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);
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state = NULL;
int ret;
crtc = dw_mipi_dsi2_get_new_crtc(dsi2, state);
if (crtc)
old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
if (old_crtc_state && old_crtc_state->self_refresh_active) {
rockchip_drm_crtc_standby(encoder->crtc, 1);
dev_dbg(dsi2->dev, "%s:%d: psr exit\n", __func__, __LINE__);
}
ret = dw_mipi_dsi2_encoder_mode_set(dsi2, state);
if (ret) {
dev_err(dsi2->dev, "failed to set dsi2 mode\n");
@@ -961,13 +1033,24 @@ static void dw_mipi_dsi2_encoder_atomic_enable(struct drm_encoder *encoder,
dw_mipi_dsi2_pre_enable(dsi2);
if (dsi2->panel)
drm_panel_prepare(dsi2->panel);
if (!(old_crtc_state && old_crtc_state->self_refresh_active)) {
if (dsi2->panel)
drm_panel_prepare(dsi2->panel);
}
dw_mipi_dsi2_enable(dsi2);
if (dsi2->panel)
drm_panel_enable(dsi2->panel);
if (old_crtc_state && old_crtc_state->self_refresh_active)
rockchip_drm_crtc_standby(encoder->crtc, 0);
dsi2->enabled = true;
if (dsi2->slave)
dsi2->slave->enabled = true;
if (!(old_crtc_state && old_crtc_state->self_refresh_active)) {
if (dsi2->panel)
drm_panel_enable(dsi2->panel);
}
DRM_DEV_INFO(dsi2->dev, "final DSI-Link bandwidth: %u x %d %s\n",
dsi2->lane_hs_rate,
@@ -1014,7 +1097,7 @@ dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder,
s->color_encoding = DRM_COLOR_YCBCR_BT709;
s->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)) {
if (dw_mipi_dsi2_is_cmd_mode(dsi2)) {
s->output_flags |= ROCKCHIP_OUTPUT_MIPI_DS_MODE;
s->soft_te = dsi2->te_gpio ? true : false;
s->hold_mode = dsi2->disable_hold_mode ? false : true;
@@ -1057,18 +1140,26 @@ dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder,
static void dw_mipi_dsi2_loader_protect(struct dw_mipi_dsi2 *dsi2, bool on)
{
if (dsi2->dcphy)
if (!dsi2->c_option)
phy_set_mode(dsi2->dcphy, PHY_MODE_MIPI_DPHY);
if (on) {
pm_runtime_get_sync(dsi2->dev);
phy_init(dsi2->dcphy);
dsi2->phy_enabled = true;
if (dsi2->dcphy)
dsi2->dcphy->power_count++;
dsi2->enabled = true;
} else {
pm_runtime_put(dsi2->dev);
phy_exit(dsi2->dcphy);
dsi2->phy_enabled = false;
if (dsi2->dcphy)
dsi2->dcphy->power_count--;
dsi2->enabled = false;
}
if (dsi2->slave)
@@ -1152,9 +1243,36 @@ dw_mipi_dsi2_connector_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
static int dw_mipi_dsi2_connector_atomic_check(struct drm_connector *connector,
struct drm_atomic_state *state)
{
struct dw_mipi_dsi2 *dsi2 = con_to_dsi2(connector);
struct drm_connector_state *conn_state;
struct drm_crtc_state *crtc_state;
conn_state = drm_atomic_get_new_connector_state(state, connector);
if (WARN_ON(!conn_state))
return -ENODEV;
conn_state->self_refresh_aware = dsi2->support_psr && dw_mipi_dsi2_is_cmd_mode(dsi2);
if (!conn_state->crtc)
return 0;
crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
if (!crtc_state)
return 0;
if (crtc_state->self_refresh_active && !dw_mipi_dsi2_is_cmd_mode(dsi2))
return -EINVAL;
return 0;
}
static struct drm_connector_helper_funcs dw_mipi_dsi2_connector_helper_funcs = {
.get_modes = dw_mipi_dsi2_connector_get_modes,
.mode_valid = dw_mipi_dsi2_connector_mode_valid,
.atomic_check = dw_mipi_dsi2_connector_atomic_check,
};
static enum drm_connector_status
@@ -1257,6 +1375,7 @@ static int dw_mipi_dsi2_dual_channel_probe(struct dw_mipi_dsi2 *dsi2)
dsi2->slave->channel = dsi2->channel;
dsi2->slave->format = dsi2->format;
dsi2->slave->mode_flags = dsi2->mode_flags;
dsi2->slave->support_psr = dsi2->support_psr;
}
return 0;
@@ -1668,6 +1787,7 @@ static ssize_t dw_mipi_dsi2_transfer(struct dw_mipi_dsi2 *dsi2,
u32 val;
u32 mode;
pm_runtime_get_sync(dsi2->dev);
dw_mipi_dsi2_clk_management(dsi2);
regmap_update_bits(dsi2->regmap, DSI2_DSI_VID_TX_CFG, LPDT_DISPLAY_CMD_EN,
msg->flags & MIPI_DSI_MSG_USE_LPM ? LPDT_DISPLAY_CMD_EN : 0);
@@ -1676,12 +1796,12 @@ static ssize_t dw_mipi_dsi2_transfer(struct dw_mipi_dsi2 *dsi2,
ret = mipi_dsi_create_packet(&packet, msg);
if (ret) {
DRM_DEV_ERROR(dsi2->dev, "failed to create packet: %d\n", ret);
return ret;
goto err;
}
ret = cri_fifos_wait_avail(dsi2);
if (ret)
return ret;
goto err;
/* Send payload */
while (DIV_ROUND_UP(packet.payload_length, 4)) {
@@ -1708,18 +1828,24 @@ static ssize_t dw_mipi_dsi2_transfer(struct dw_mipi_dsi2 *dsi2,
ret = cri_fifos_wait_avail(dsi2);
if (ret)
return ret;
goto err;
if (msg->rx_len) {
ret = dw_mipi_dsi2_read_from_fifo(dsi2, msg);
if (ret < 0)
return ret;
goto err;
}
pm_runtime_put(dsi2->dev);
if (dsi2->slave)
dw_mipi_dsi2_transfer(dsi2->slave, msg);
return msg->tx_len;
err:
pm_runtime_put(dsi2->dev);
return ret;
}
static ssize_t dw_mipi_dsi2_host_transfer(struct mipi_dsi_host *host,
@@ -1774,6 +1900,12 @@ static int dw_mipi_dsi2_probe(struct platform_device *pdev)
if (device_property_read_u32(dev, "split-area", &dsi2->split_area))
dsi2->split_area = 0;
dsi2->support_psr = device_property_read_bool(dev, "support-psr");
if (dsi2->support_psr && dsi2->auto_calc_mode) {
dsi2->auto_calc_mode = false;
dev_info(dev, "disable auto-calculation-mode in PSR mode\n");
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))

View File

@@ -200,7 +200,8 @@ static int rockchip_drm_aclk_adjust(struct drm_device *dev,
funcs = priv->crtc_funcs[drm_crtc_index(crtc)];
if (funcs && funcs->set_aclk) {
if (vop_bw_info->plane_num_4k || crtc_num > 1 ||
crtc->state->adjusted_mode.crtc_hdisplay > 4096) {
crtc->state->adjusted_mode.crtc_hdisplay > 2560 ||
crtc->state->adjusted_mode.crtc_vdisplay > 2560) {
funcs->set_aclk(crtc, ROCKCHIP_VOP_ACLK_ADVANCED_MODE);
priv->aclk_adjust_frame_num = 2;
} else {

View File

@@ -28,11 +28,12 @@
#define VOP2_MINOR(version) (((version) >> 16) & 0xff)
#define VOP2_BUILD(version) ((version) & 0xffff)
/* The new SOC VOP version is bigger than the old */
#define VOP_VERSION_RK3568 VOP2_VERSION(0x40, 0x15, 0x8023)
#define VOP_VERSION_RK3588 VOP2_VERSION(0x40, 0x17, 0x6786)
#define VOP_VERSION_RK3528 VOP2_VERSION(0x50, 0x17, 0x1263)
#define VOP_VERSION_RK3562 VOP2_VERSION(0x50, 0x17, 0x4350)
#define VOP_VERSION_RK3568 VOP2_VERSION(0x40, 0x15, 0x8023)
#define VOP_VERSION_RK3576 VOP2_VERSION(0x50, 0x19, 0x9765)
#define VOP_VERSION_RK3588 VOP2_VERSION(0x40, 0x17, 0x6786)
/* register one connector */
#define ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE BIT(0)

View File

@@ -4849,6 +4849,17 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
goto out;
}
/*
* Usperspace not commit new frame for long time will triggle driver enter
* psr mode, If userspace directly close display at next time and without
* any new frame commit, driver will not exit psr, at this case we need to
* recover aclk here.
*/
if (vop2->aclk_rate_reset) {
clk_set_rate(vop2->aclk, vop2->aclk_current_freq);
vop2->aclk_rate_reset = false;
}
vop2_lock(vop2);
DRM_DEV_INFO(vop2->dev, "Crtc atomic disable vp%d\n", vp->id);
VOP_MODULE_SET(vop2, vp, almost_full_or_en, 0);
@@ -5914,9 +5925,18 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s
}
}
if (is_linear_10bit_yuv(fb->format->format) && actual_w & 0x3) {
DRM_WARN("vp%d %s actual_w[%d] should align as 4 pixel when is linear 10 bit yuv format\n", vp->id, win->name, actual_w);
actual_w = ALIGN_DOWN(actual_w, 4);
/*
* At RK356X/RK3588/RK3562/RK3528 linear 10bit yuv format actual_w should align as 4 pixel,
* from RK3576 linear 10bit yuv format actual_w should align as 2 pixel.
*/
if (is_linear_10bit_yuv(fb->format->format)) {
if (vop2->version < VOP_VERSION_RK3576 && actual_w & 0x3) {
DRM_WARN("vp%d %s actual_w[%d] should align as 4 pixel when is linear 10 bit yuv format\n", vp->id, win->name, actual_w);
actual_w = ALIGN_DOWN(actual_w, 4);
} else if (vop2->version >= VOP_VERSION_RK3576 && actual_w & 0x1) {
DRM_WARN("vp%d %s actual_w[%d] should align as 2 pixel when is linear 10 bit yuv format\n", vp->id, win->name, actual_w);
actual_w = ALIGN_DOWN(actual_w, 2);
}
}
act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff);
@@ -7700,7 +7720,7 @@ static size_t vop2_crtc_bandwidth(struct drm_crtc *crtc,
act_w = drm_rect_width(&pstate->src) >> 16;
act_h = drm_rect_height(&pstate->src) >> 16;
if (pstate->fb->format->is_yuv && (act_w >= 3840 || act_h >= 3840))
if (pstate->fb->format->is_yuv && (act_w > 2560 || act_h > 2560))
vop_bw_info->plane_num_4k++;
bpp = rockchip_drm_get_bpp(pstate->fb->format);

View File

@@ -136,6 +136,20 @@ static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
return -ENODEV;
}
static void maxim4c_hot_plug_event_report(maxim4c_t *maxim4c, int data)
{
struct v4l2_subdev *sd = &maxim4c->subdev;
struct device *dev = &maxim4c->client->dev;
struct v4l2_event evt_hot_plug = {
.type = V4L2_EVENT_HOT_PLUG,
.u.data[0] = data,
};
dev_dbg(dev, "%s data %d\n", __func__, data);
v4l2_event_queue(sd->devnode, &evt_hot_plug);
}
static irqreturn_t maxim4c_hot_plug_detect_irq_handler(int irq, void *dev_id)
{
maxim4c_t *maxim4c = dev_id;
@@ -223,6 +237,7 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
dev_dbg(dev, "lock state: current = 0x%02x, last = 0x%02x\n",
curr_lock_state, last_lock_state);
maxim4c_hot_plug_event_report(maxim4c, curr_lock_state);
maxim4c->link_lock_state = curr_lock_state;
}

View File

@@ -9,12 +9,14 @@
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
#include <linux/regulator/consumer.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-fwnode.h>
@@ -32,6 +34,10 @@
/* power supply numbers */
#define MAXIM4C_NUM_SUPPLIES 2
/* Private v4l2 event */
#define V4L2_EVENT_HOT_PLUG \
(V4L2_EVENT_PRIVATE_START + 0x10)
enum {
MAXIM4C_HOT_PLUG_OUT = 0,
MAXIM4C_HOT_PLUG_IN,

View File

@@ -779,10 +779,7 @@ static int maxim4c_get_fmt(struct v4l2_subdev *sd,
fmt->format.height = mode->height;
fmt->format.code = mode->bus_fmt;
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->pad < PAD_MAX && fmt->pad >= PAD0)
fmt->reserved[0] = mode->vc[fmt->pad];
else
fmt->reserved[0] = mode->vc[PAD0];
fmt->reserved[0] = mode->vc[fmt->pad];
}
mutex_unlock(&maxim4c->mutex);
@@ -925,6 +922,17 @@ static int maxim4c_g_mbus_config(struct v4l2_subdev *sd,
}
#endif /* LINUX_VERSION_CODE */
static int maxim4c_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub)
{
switch (sub->type) {
case V4L2_EVENT_HOT_PLUG:
return v4l2_event_subscribe(fh, sub, 0, NULL);
default:
return -EINVAL;
}
}
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static const struct v4l2_subdev_internal_ops maxim4c_internal_ops = {
.open = maxim4c_open,
@@ -933,6 +941,8 @@ static const struct v4l2_subdev_internal_ops maxim4c_internal_ops = {
static const struct v4l2_subdev_core_ops maxim4c_core_ops = {
.s_power = maxim4c_s_power,
.subscribe_event = maxim4c_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
.ioctl = maxim4c_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = maxim4c_compat_ioctl32,
@@ -1062,7 +1072,7 @@ int maxim4c_v4l2_subdev_init(maxim4c_t *maxim4c)
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &maxim4c_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)

View File

@@ -225,6 +225,7 @@ config MMC_SDHCI_OF_DWCMSHC
depends on OF
depends on COMMON_CLK
select MMC_HSQ
select MMC_CQHCI
help
This selects Synopsys DesignWare Cores Mobile Storage Controller
support.

View File

@@ -474,8 +474,8 @@ static int cqhci_dma_map(struct mmc_host *host, struct mmc_request *mrq)
return sg_count;
}
static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end,
bool dma64)
void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end,
bool dma64)
{
__le32 *attr = (__le32 __force *)desc;
@@ -495,6 +495,7 @@ static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end,
dataddr[0] = cpu_to_le32(addr);
}
}
EXPORT_SYMBOL(cqhci_set_tran_desc);
static int cqhci_prep_tran_desc(struct mmc_request *mrq,
struct cqhci_host *cq_host, int tag)
@@ -522,7 +523,11 @@ static int cqhci_prep_tran_desc(struct mmc_request *mrq,
if ((i+1) == sg_count)
end = true;
cqhci_set_tran_desc(desc, addr, len, end, dma64);
if (cq_host->ops->set_tran_desc)
cq_host->ops->set_tran_desc(cq_host, &desc, addr, len, end, dma64);
else
cqhci_set_tran_desc(desc, addr, len, end, dma64);
desc += cq_host->trans_desc_len;
}

View File

@@ -290,6 +290,9 @@ struct cqhci_host_ops {
int (*program_key)(struct cqhci_host *cq_host,
const union cqhci_crypto_cfg_entry *cfg, int slot);
#endif
void (*set_tran_desc)(struct cqhci_host *cq_host, u8 **desc,
dma_addr_t addr, int len, bool end, bool dma64);
};
static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)
@@ -315,6 +318,7 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error,
int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64);
struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev);
int cqhci_deactivate(struct mmc_host *mmc);
void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, bool dma64);
static inline int cqhci_suspend(struct mmc_host *mmc)
{
return cqhci_deactivate(mmc);

View File

@@ -22,6 +22,8 @@
#include "sdhci-pltfm.h"
#include "mmc_hsq.h"
#include "cqhci.h"
#include "sdhci-cqhci.h"
#define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16)
@@ -38,12 +40,17 @@
#define DWCMSHC_ENHANCED_STROBE BIT(8)
#define DWCMSHC_EMMC_ATCTRL 0x40
/* DWC IP vendor area 2 pointer */
#define DWCMSHC_P_VENDOR_AREA2 0xea
/* Rockchip specific Registers */
#define DWCMSHC_EMMC_DLL_CTRL 0x800
#define DWCMSHC_EMMC_DLL_RXCLK 0x804
#define DWCMSHC_EMMC_DLL_TXCLK 0x808
#define DWCMSHC_EMMC_DLL_STRBIN 0x80c
#define DECMSHC_EMMC_DLL_CMDOUT 0x810
#define DECMSHC_EMMC_MISC_CON 0x81C
#define MISC_INTCLK_EN BIT(1)
#define DWCMSHC_EMMC_DLL_STATUS0 0x840
#define DWCMSHC_EMMC_DLL_STATUS1 0x844
#define DWCMSHC_EMMC_DLL_START BIT(0)
@@ -83,6 +90,10 @@
#define BOUNDARY_OK(addr, len) \
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
#define DWCMSHC_SDHCI_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \
SDHCI_TRNS_BLK_CNT_EN | \
SDHCI_TRNS_DMA)
enum dwcmshc_rk_type {
DWCMSHC_RK3568,
DWCMSHC_RK3588,
@@ -117,7 +128,9 @@ struct rk35xx_priv {
struct dwcmshc_priv {
struct clk *bus_clk;
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA1 reg */
int vendor_specific_area2; /* P_VENDOR_SPECIFIC_AREA2 reg */
void *priv; /* pointer to SoC private stuff */
};
@@ -230,6 +243,145 @@ static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
sdhci_writel(host, vendor, reg);
}
static int dwcmshc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
int err = sdhci_execute_tuning(mmc, opcode);
struct sdhci_host *host = mmc_priv(mmc);
if (err)
return err;
/*
* Tuning can leave the IP in an active state (Buffer Read Enable bit
* set) which prevents the entry to low power states (i.e. S0i3). Data
* reset will clear it.
*/
sdhci_reset(host, SDHCI_RESET_DATA);
return 0;
}
static u32 dwcmshc_cqe_irq_handler(struct sdhci_host *host, u32 intmask)
{
int cmd_error = 0;
int data_error = 0;
if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
return intmask;
cqhci_irq(host->mmc, intmask, cmd_error, data_error);
return 0;
}
static void dwcmshc_sdhci_cqe_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
u8 ctrl;
sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
sdhci_cqe_enable(mmc);
/*
* The "DesignWare Cores Mobile Storage Host Controller
* DWC_mshc / DWC_mshc_lite Databook" says:
* when Host Version 4 Enable" is 1 in Host Control 2 register,
* SDHCI_CTRL_ADMA32 bit means ADMA2 is selected.
* Selection of 32-bit/64-bit System Addressing:
* either 32-bit or 64-bit system addressing is selected by
* 64-bit Addressing bit in Host Control 2 register.
*
* On the other hand the "DesignWare Cores Mobile Storage Host
* Controller DWC_mshc / DWC_mshc_lite User Guide" says, that we have to
* set DMA_SEL to ADMA2 _only_ mode in the Host Control 2 register.
*/
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
ctrl |= SDHCI_CTRL_ADMA32;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
static void rk35xx_sdhci_cqe_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
u32 reg;
reg = sdhci_readl(host, dwc_priv->vendor_specific_area2 + CQHCI_CFG);
reg |= CQHCI_ENABLE;
sdhci_writel(host, reg, dwc_priv->vendor_specific_area2 + CQHCI_CFG);
reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
while (reg & SDHCI_DATA_AVAILABLE) {
sdhci_readl(host, SDHCI_BUFFER);
reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
}
sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
sdhci_cqe_enable(mmc);
sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
}
static void rk35xx_sdhci_cqe_disabled(struct mmc_host *mmc, bool recovery)
{
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
unsigned long flags;
u32 ctrl;
mmc->cqe_ops->cqe_wait_for_idle(mmc);
spin_lock_irqsave(&host->lock, flags);
/*
* During CQE command transfers, command complete bit gets latched.
* So s/w should clear command complete interrupt status when CQE is
* either halted or disabled. Otherwise unexpected SDCHI legacy
* interrupt gets triggered when CQE is halted/disabled.
*/
ctrl = sdhci_readl(host, SDHCI_INT_ENABLE);
ctrl |= SDHCI_INT_RESPONSE;
sdhci_writel(host, ctrl, SDHCI_INT_ENABLE);
sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
spin_unlock_irqrestore(&host->lock, flags);
sdhci_cqe_disable(mmc, recovery);
ctrl = sdhci_readl(host, dwc_priv->vendor_specific_area2 + CQHCI_CFG);
ctrl &= ~CQHCI_ENABLE;
sdhci_writel(host, ctrl, dwc_priv->vendor_specific_area2 + CQHCI_CFG);
}
static void dwcmshc_set_tran_desc(struct cqhci_host *cq_host, u8 **desc,
dma_addr_t addr, int len, bool end, bool dma64)
{
int tmplen, offset;
if (likely(!len || BOUNDARY_OK(addr, len))) {
cqhci_set_tran_desc(*desc, addr, len, end, dma64);
return;
}
offset = addr & (SZ_128M - 1);
tmplen = SZ_128M - offset;
cqhci_set_tran_desc(*desc, addr, tmplen, false, dma64);
addr += tmplen;
len -= tmplen;
*desc += cq_host->trans_desc_len;
cqhci_set_tran_desc(*desc, addr, len, end, dma64);
}
static void dwcmshc_cqhci_dumpregs(struct mmc_host *mmc)
{
sdhci_dumpregs(mmc_priv(mmc));
}
static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -375,6 +527,7 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
struct rk35xx_priv *priv = dwc_priv->priv;
u32 extra = sdhci_readl(host, DECMSHC_EMMC_MISC_CON);
if (mask & SDHCI_RESET_ALL && priv->reset) {
reset_control_assert(priv->reset);
@@ -383,12 +536,17 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
}
sdhci_reset(host, mask);
/* Enable INTERNAL CLOCK */
sdhci_writel(host, MISC_INTCLK_EN | extra, DECMSHC_EMMC_MISC_CON);
}
static void sdhci_dwcmshc_request_done(struct sdhci_host *host, struct mmc_request *mrq)
{
if (mmc_hsq_finalize_request(host->mmc, mrq))
return;
if (!(host->mmc->caps2 & MMC_CAP2_CQE)) {
if (mmc_hsq_finalize_request(host->mmc, mrq))
return;
}
mmc_request_done(host->mmc, mrq);
}
@@ -400,6 +558,7 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = {
.get_max_clock = dwcmshc_get_max_clock,
.reset = sdhci_reset,
.adma_write_desc = dwcmshc_adma_write_desc,
.irq = dwcmshc_cqe_irq_handler,
};
static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
@@ -409,6 +568,7 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.reset = rk35xx_sdhci_reset,
.adma_write_desc = dwcmshc_adma_write_desc,
.irq = dwcmshc_cqe_irq_handler,
.request_done = sdhci_dwcmshc_request_done,
};
@@ -434,6 +594,84 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
};
static const struct cqhci_host_ops dwcmshc_cqhci_ops = {
.enable = dwcmshc_sdhci_cqe_enable,
.disable = sdhci_cqe_disable,
.dumpregs = dwcmshc_cqhci_dumpregs,
.set_tran_desc = dwcmshc_set_tran_desc,
};
static const struct cqhci_host_ops rk35xx_cqhci_ops = {
.enable = rk35xx_sdhci_cqe_enable,
.disable = rk35xx_sdhci_cqe_disabled,
.dumpregs = dwcmshc_cqhci_dumpregs,
.set_tran_desc = dwcmshc_set_tran_desc,
};
static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *pdev)
{
struct cqhci_host *cq_host;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
struct rk35xx_priv *rk_priv = priv->priv;
bool dma64 = false;
u16 clk;
int err;
host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL);
if (!cq_host) {
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: not enough memory\n");
goto dsbl_cqe_caps;
}
/*
* For dwcmshc host controller we have to enable internal clock
* before access to some registers from Vendor Specific Area 2.
*/
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
if (!(clk & SDHCI_CLOCK_INT_EN)) {
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: internal clock enable error\n");
goto free_cq_host;
}
cq_host->mmio = host->ioaddr + priv->vendor_specific_area2;
if (rk_priv)
cq_host->ops = &rk35xx_cqhci_ops;
else
cq_host->ops = &dwcmshc_cqhci_ops;
/* Enable using of 128-bit task descriptors */
dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
if (dma64) {
dev_dbg(mmc_dev(host->mmc), "128-bit task descriptors\n");
cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
}
err = cqhci_init(cq_host, host->mmc, dma64);
if (err) {
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: error %d\n", err);
goto int_clock_disable;
}
dev_dbg(mmc_dev(host->mmc), "CQE init done\n");
return;
int_clock_disable:
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk &= ~SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
free_cq_host:
devm_kfree(&pdev->dev, cq_host);
dsbl_cqe_caps:
host->mmc->caps2 &= ~(MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD);
}
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
{
int err;
@@ -594,7 +832,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
const struct dwcmshc_driver_data *drv_data;
struct mmc_hsq *hsq;
int err;
u32 extra;
u32 extra, caps;
drv_data = device_get_match_data(&pdev->dev);
if (!drv_data) {
@@ -646,16 +884,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
host->mmc_host_ops.request = dwcmshc_request;
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
if (!hsq) {
err = -ENOMEM;
goto err_clk;
}
err = mmc_hsq_init(hsq, host->mmc);
if (err)
goto err_clk;
host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning;
if (drv_data->flags & RK_PLATFROM) {
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL);
@@ -679,12 +908,34 @@ static int dwcmshc_probe(struct platform_device *pdev)
goto err_clk;
}
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
if (caps & SDHCI_CAN_64BIT_V4)
sdhci_enable_v4_mode(host);
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
err = sdhci_setup_host(host);
if (err)
goto err_clk;
/* Setup Command Queue Engine if enabled */
if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
priv->vendor_specific_area2 =
sdhci_readw(host, DWCMSHC_P_VENDOR_AREA2);
dwcmshc_cqhci_init(host, pdev);
} else {
hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
if (!hsq) {
err = -ENOMEM;
goto err_setup_host;
}
err = mmc_hsq_init(hsq, host->mmc);
if (err)
goto err_setup_host;
}
if (rk_priv)
dwcmshc_rk35xx_postinit(host, priv);
@@ -750,7 +1001,13 @@ static int dwcmshc_suspend(struct device *dev)
struct rk35xx_priv *rk_priv = priv->priv;
int ret;
mmc_hsq_suspend(host->mmc);
if (host->mmc->caps2 & MMC_CAP2_CQE) {
ret = cqhci_suspend(host->mmc);
if (ret)
return ret;
} else {
mmc_hsq_suspend(host->mmc);
}
ret = sdhci_suspend_host(host);
if (ret)
@@ -782,21 +1039,40 @@ static int dwcmshc_resume(struct device *dev)
if (!IS_ERR(priv->bus_clk)) {
ret = clk_prepare_enable(priv->bus_clk);
if (ret)
return ret;
goto disable_clk;
}
if (rk_priv) {
ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS,
rk_priv->rockchip_clks);
if (ret)
return ret;
goto disable_bus_clk;
}
ret = sdhci_resume_host(host);
if (ret)
return ret;
goto disable_rockchip_clks;
return mmc_hsq_resume(host->mmc);
if (host->mmc->caps2 & MMC_CAP2_CQE) {
ret = cqhci_resume(host->mmc);
if (ret)
goto disable_rockchip_clks;
} else {
return mmc_hsq_resume(host->mmc);
}
return 0;
disable_rockchip_clks:
if (rk_priv)
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
rk_priv->rockchip_clks);
disable_bus_clk:
if (!IS_ERR(priv->bus_clk))
clk_disable_unprepare(priv->bus_clk);
disable_clk:
clk_disable_unprepare(pltfm_host->clk);
return ret;
}
static int dwcmshc_runtime_suspend(struct device *dev)

View File

@@ -67,6 +67,11 @@
#define DPHY_MC_GNR_CON1 0x0304
#define T_PHY_READY(x) UPDATE(x, 15, 0)
#define DPHY_MC_ANA_CON0 0x0308
#define EDGE_CON(x) UPDATE(x, 14, 12)
#define EDGE_CON_DIR(x) UPDATE(x, 9, 9)
#define EDGE_CON_EN BIT(8)
#define RES_UP(x) UPDATE(x, 7, 4)
#define RES_DN(x) UPDATE(x, 3, 0)
#define DPHY_MC_ANA_CON1 0x030c
#define DPHY_MC_ANA_CON2 0x0310
#define HS_VREG_AMP_ICON(x) UPDATE(x, 1, 0)
@@ -1594,15 +1599,25 @@ samsung_mipi_dphy_clk_lane_timing_init(struct samsung_mipi_dcphy *samsung)
{
const struct samsung_mipi_dphy_timing *timing;
unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC);
u32 val = 0;
u32 val, res_up, res_down;
timing = samsung_mipi_dphy_get_timing(samsung);
regmap_write(samsung->regmap, DPHY_MC_GNR_CON0, 0xf000);
regmap_write(samsung->regmap, DPHY_MC_ANA_CON0, 0x7133);
/*
* The Drive-Strength / Voltage-Amplitude is adjusted by adjusting the
* Driver-Up Resistor and Driver-Down Resistor.
*/
res_up = samsung->pdata->dphy_hs_drv_res_cfg->clk_hs_drv_up_ohm;
res_down = samsung->pdata->dphy_hs_drv_res_cfg->clk_hs_drv_down_ohm;
val = EDGE_CON(7) | EDGE_CON_DIR(0) | EDGE_CON_EN |
RES_UP(res_up) | RES_DN(res_down);
regmap_write(samsung->regmap, DPHY_MC_ANA_CON0, val);
if (lane_hs_rate >= 4500)
regmap_write(samsung->regmap, DPHY_MC_ANA_CON1, 0x0001);
val = 0;
/*
* Divide-by-2 Clock from Serial Clock. Use this when data rate is under
* 1500Mbps, otherwise divide-by-16 Clock from Serial Clock
@@ -1639,14 +1654,22 @@ samsung_mipi_dphy_data_lane_timing_init(struct samsung_mipi_dcphy *samsung)
{
const struct samsung_mipi_dphy_timing *timing;
unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC);
u32 val = 0;
u32 val, res_up, res_down;
timing = samsung_mipi_dphy_get_timing(samsung);
regmap_write(samsung->regmap, COMBO_MD0_ANA_CON0, 0x7133);
regmap_write(samsung->regmap, COMBO_MD1_ANA_CON0, 0x7133);
regmap_write(samsung->regmap, COMBO_MD2_ANA_CON0, 0x7133);
regmap_write(samsung->regmap, DPHY_MD3_ANA_CON0, 0x7133);
/*
* The Drive-Strength / Voltage-Amplitude is adjusted by adjusting the
* Driver-Up Resistor and Driver-Down Resistor.
*/
res_up = samsung->pdata->dphy_hs_drv_res_cfg->data_hs_drv_up_ohm;
res_down = samsung->pdata->dphy_hs_drv_res_cfg->data_hs_drv_down_ohm;
val = EDGE_CON(7) | EDGE_CON_DIR(0) | EDGE_CON_EN |
RES_UP(res_up) | RES_DN(res_down);
regmap_write(samsung->regmap, COMBO_MD0_ANA_CON0, val);
regmap_write(samsung->regmap, COMBO_MD1_ANA_CON0, val);
regmap_write(samsung->regmap, COMBO_MD2_ANA_CON0, val);
regmap_write(samsung->regmap, DPHY_MD3_ANA_CON0, val);
if (lane_hs_rate >= 4500) {
regmap_write(samsung->regmap, COMBO_MD0_ANA_CON1, 0x0001);
@@ -1655,6 +1678,7 @@ samsung_mipi_dphy_data_lane_timing_init(struct samsung_mipi_dcphy *samsung)
regmap_write(samsung->regmap, DPHY_MD3_ANA_CON1, 0x0001);
}
val = 0;
/*
* Divide-by-2 Clock from Serial Clock. Use this when data rate is under
* 1500Mbps, otherwise divide-by-16 Clock from Serial Clock
@@ -2473,12 +2497,28 @@ static const struct dev_pm_ops samsung_mipi_dcphy_pm_ops = {
samsung_mipi_dcphy_runtime_resume, NULL)
};
static const struct hs_drv_res_cfg rk3576_dphy_hs_drv_res_cfg = {
.clk_hs_drv_up_ohm = _52_OHM,
.clk_hs_drv_down_ohm = _52_OHM,
.data_hs_drv_up_ohm = _39_OHM,
.data_hs_drv_down_ohm = _39_OHM,
};
static const struct hs_drv_res_cfg rk3588_dphy_hs_drv_res_cfg = {
.clk_hs_drv_up_ohm = _34_OHM,
.clk_hs_drv_down_ohm = _34_OHM,
.data_hs_drv_up_ohm = _43_OHM,
.data_hs_drv_down_ohm = _43_OHM,
};
static const struct samsung_mipi_dcphy_plat_data rk3576_samsung_mipi_dcphy_plat_data = {
.dphy_hs_drv_res_cfg = &rk3576_dphy_hs_drv_res_cfg,
.dphy_tx_max_kbps_per_lane = 2500000L,
.cphy_tx_max_ksps_per_lane = 1700000L,
};
static const struct samsung_mipi_dcphy_plat_data rk3588_samsung_mipi_dcphy_plat_data = {
.dphy_hs_drv_res_cfg = &rk3588_dphy_hs_drv_res_cfg,
.dphy_tx_max_kbps_per_lane = 4500000L,
.cphy_tx_max_ksps_per_lane = 2000000L,
};

View File

@@ -10,7 +10,34 @@
#define MAX_NUM_CSI2_DPHY (0x2)
enum hs_drv_res_ohm {
_30_OHM = 0x8,
_31_2_OHM,
_32_5_OHM,
_34_OHM,
_35_5_OHM,
_37_OHM,
_39_OHM,
_41_OHM,
_43_OHM = 0x0,
_46_OHM,
_49_OHM,
_52_OHM,
_56_OHM,
_60_OHM,
_66_OHM,
_73_OHM,
};
struct hs_drv_res_cfg {
enum hs_drv_res_ohm clk_hs_drv_up_ohm;
enum hs_drv_res_ohm clk_hs_drv_down_ohm;
enum hs_drv_res_ohm data_hs_drv_up_ohm;
enum hs_drv_res_ohm data_hs_drv_down_ohm;
};
struct samsung_mipi_dcphy_plat_data {
const struct hs_drv_res_cfg *dphy_hs_drv_res_cfg;
u32 dphy_tx_max_kbps_per_lane;
u32 cphy_tx_max_ksps_per_lane;
};

View File

@@ -931,7 +931,7 @@ static int rk817_resume_path_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component);
DBG("%s : resume_path %ld\n", __func__, rk817->resume_path);
DBG("%s : resume_path %d\n", __func__, rk817->resume_path);
ucontrol->value.integer.value[0] = rk817->resume_path;