/* * This DSI can only be paired with bridges that do config through i2c * which is ADV 7535 in the KMB EVM
*/ static ssize_t kmb_dsi_host_transfer(struct mipi_dsi_host *host, conststruct mipi_dsi_msg *msg)
{ return 0;
}
/* Find ADV7535 node and initialize it */
dsi_out = of_graph_get_endpoint_by_regs(dev->of_node, 0, 1); if (!dsi_out) {
DRM_ERROR("Failed to get dsi_out node info from DT\n"); return -EINVAL;
}
encoder_node = of_graph_get_remote_port_parent(dsi_out); if (!encoder_node) {
of_node_put(dsi_out);
DRM_ERROR("Failed to get bridge info from DT\n"); return -EINVAL;
} /* Locate drm bridge from the hdmi encoder DT node */
adv_bridge = of_drm_find_bridge(encoder_node);
of_node_put(dsi_out);
of_node_put(encoder_node); if (!adv_bridge) {
DRM_DEBUG("Wait for external bridge driver DT\n"); return -EPROBE_DEFER;
}
switch (data_type) { case DSI_LP_DT_PPS_YCBCR420_12B:
data_type_param.size_constraint_pixels = 2;
data_type_param.size_constraint_bytes = 3; switch (data_mode) { /* Case 0 not supported according to MDK */ case 1: case 2: case 3:
data_type_param.pixels_per_pclk = 2;
data_type_param.bits_per_pclk = 24; break; default:
DRM_ERROR("DSI: Invalid data_mode %d\n", data_mode); return -EINVAL;
} break; case DSI_LP_DT_PPS_YCBCR422_16B:
data_type_param.size_constraint_pixels = 2;
data_type_param.size_constraint_bytes = 4; switch (data_mode) { /* Case 0 and 1 not supported according * to MDK
*/ case 2:
data_type_param.pixels_per_pclk = 1;
data_type_param.bits_per_pclk = 16; break; case 3:
data_type_param.pixels_per_pclk = 2;
data_type_param.bits_per_pclk = 32; break; default:
DRM_ERROR("DSI: Invalid data_mode %d\n", data_mode); return -EINVAL;
} break; case DSI_LP_DT_LPPS_YCBCR422_20B: case DSI_LP_DT_PPS_YCBCR422_24B:
data_type_param.size_constraint_pixels = 2;
data_type_param.size_constraint_bytes = 6; switch (data_mode) { /* Case 0 not supported according to MDK */ case 1: case 2: case 3:
data_type_param.pixels_per_pclk = 1;
data_type_param.bits_per_pclk = 24; break; default:
DRM_ERROR("DSI: Invalid data_mode %d\n", data_mode); return -EINVAL;
} break; case DSI_LP_DT_PPS_RGB565_16B:
data_type_param.size_constraint_pixels = 1;
data_type_param.size_constraint_bytes = 2; switch (data_mode) { case 0: case 1:
data_type_param.pixels_per_pclk = 1;
data_type_param.bits_per_pclk = 16; break; case 2: case 3:
data_type_param.pixels_per_pclk = 2;
data_type_param.bits_per_pclk = 32; break; default:
DRM_ERROR("DSI: Invalid data_mode %d\n", data_mode); return -EINVAL;
} break; case DSI_LP_DT_PPS_RGB666_18B:
data_type_param.size_constraint_pixels = 4;
data_type_param.size_constraint_bytes = 9;
data_type_param.bits_per_pclk = 18;
data_type_param.pixels_per_pclk = 1; break; case DSI_LP_DT_LPPS_RGB666_18B: case DSI_LP_DT_PPS_RGB888_24B:
data_type_param.size_constraint_pixels = 1;
data_type_param.size_constraint_bytes = 3;
data_type_param.bits_per_pclk = 24;
data_type_param.pixels_per_pclk = 1; break; case DSI_LP_DT_PPS_RGB101010_30B:
data_type_param.size_constraint_pixels = 4;
data_type_param.size_constraint_bytes = 15;
data_type_param.bits_per_pclk = 30;
data_type_param.pixels_per_pclk = 1; break; default:
DRM_ERROR("DSI: Invalid data_type %d\n", data_type); return -EINVAL;
}
*params = data_type_param; return 0;
}
static u32 compute_wc(u32 width_px, u8 size_constr_p, u8 size_constr_b)
{ /* Calculate the word count for each long packet */ return (((width_px / size_constr_p) * size_constr_b) & 0xffff);
}
static u32 compute_unpacked_bytes(u32 wc, u8 bits_per_pclk)
{ /* Number of PCLK cycles needed to transfer a line * with each PCLK cycle, 4 Bytes are sent through the PPL module
*/ return ((wc * 8) / bits_per_pclk) * 4;
}
ret = mipi_get_datatype_params(frame_scfg->data_type,
frame_scfg->data_mode,
&data_type_parameters); if (ret) return ret;
/* Packet width has to be a multiple of the minimum packet width * (in pixels) set for each data type
*/ if (frame_scfg->width_pixels %
data_type_parameters.size_constraint_pixels != 0) return -EINVAL;
/* 500 Mhz system clock minus 50 to account for the difference in * MIPI clock speed in RTL tests
*/ if (kmb_dsi->sys_clk_mhz == SYSCLK_500) {
sysclk = kmb_dsi->sys_clk_mhz - CLK_DIFF_LOW;
} else { /* 700 Mhz clk*/
sysclk = kmb_dsi->sys_clk_mhz - CLK_DIFF_HI;
}
/* PPL-Pixel Packing Layer, LLP-Low Level Protocol * Frame genartor timing parameters are clocked on the system clock, * whereas as the equivalent parameters in the LLP blocks are clocked * on LLP Tx clock from the D-PHY - BYTE clock
*/
/* horizontal active (ha) */
reg_adr = MIPI_TXm_HS_H_ACTIVEn(ctrl_no, frame_gen);
/* convert h_active which is wc in bytes to cycles */
val = (fg_cfg->h_active * sysclk * 1000) /
((fg_cfg->lane_rate_mbps / 8) * fg_cfg->active_lanes);
val /= 1000;
kmb_write_mipi(kmb_dsi, reg_adr, val);
/* Calculate the total frame generator number of * lines based on it's active sections
*/ for (i = 0; i < MIPI_TX_FRAME_GEN_SECTIONS; i++) { if (fg_cfg->sections[i])
fg_num_lines += fg_cfg->sections[i]->height_lines;
}
if (ctrl_cfg->tx_ctrl_cfg.tx_always_use_hact)
sync_cfg |= ALWAYS_USE_HACT(fg_en); if (ctrl_cfg->tx_ctrl_cfg.tx_hact_wait_stop)
sync_cfg |= HACT_WAIT_STOP(fg_en);
/* This is the order to initialize MIPI TX: * 1. set frame section parameters * 2. set frame specific parameters * 3. connect lcd to mipi * 4. multi channel fifo cfg * 5. set mipitxcctrlcfg
*/
/* Find valid frame, assume only one valid frame */ if (!frame) continue;
/* Frame Section configuration */ /* TODO - assume there is only one valid section in a frame, * so bits_per_pclk and word_count are only set once
*/ for (sect = 0; sect < MIPI_CTRL_VIRTUAL_CHANNELS; sect++) { if (!frame->sections[sect]) continue;
ret = mipi_tx_fg_section_cfg(kmb_dsi, frame_id, sect,
frame->sections[sect],
&bits_per_pclk,
&word_count); if (ret) return ret;
}
/* Set frame specific parameters */
mipi_tx_fg_cfg(kmb_dsi, frame_id, ctrl_cfg->active_lanes,
bits_per_pclk, word_count,
ctrl_cfg->lane_rate_mbps, frame);
active_vchannels++;
/* Stop iterating as only one virtual channel * shall be used for LCD connection
*/ break;
}
staticvoid test_mode_send(struct kmb_dsi *kmb_dsi, u32 dphy_no,
u32 test_code, u32 test_data)
{ /* Steps to send test code: * - set testclk HIGH * - set testdin with test code * - set testen HIGH * - set testclk LOW * - set testen LOW
*/
/* Set testclk high */
SET_DPHY_TEST_CTRL1_CLK(kmb_dsi, dphy_no);
/* Set testdin */
SET_TEST_DIN0_3(kmb_dsi, dphy_no, test_code);
/* Set testen high */
SET_DPHY_TEST_CTRL1_EN(kmb_dsi, dphy_no);
/* Set testclk low */
CLR_DPHY_TEST_CTRL1_CLK(kmb_dsi, dphy_no);
/* Set testen low */
CLR_DPHY_TEST_CTRL1_EN(kmb_dsi, dphy_no);
if (test_code) { /* Steps to send test data: * - set testen LOW * - set testclk LOW * - set testdin with data * - set testclk HIGH
*/
/* Set testen low */
CLR_DPHY_TEST_CTRL1_EN(kmb_dsi, dphy_no);
/* Set testclk low */
CLR_DPHY_TEST_CTRL1_CLK(kmb_dsi, dphy_no);
/* Set data in testdin */
kmb_write_mipi(kmb_dsi,
DPHY_TEST_DIN0_3 + ((dphy_no / 0x4) * 0x4),
test_data << ((dphy_no % 4) * 8));
/* Set testclk high */
SET_DPHY_TEST_CTRL1_CLK(kmb_dsi, dphy_no);
}
}
/* Search pll n parameter */ for (n = PLL_N_MIN; n <= PLL_N_MAX; n++) { /* Calculate the pll input frequency division ratio * multiply by 1000 for precision - * no floating point, add n for rounding
*/
div = ((ref_clk_mhz * 1000) + n) / (n + 1);
/* Found a valid n parameter */ if ((div < 2000 || div > 8000)) continue;
/* Search pll m parameter */ for (m = PLL_M_MIN; m <= PLL_M_MAX; m++) { /* Calculate the Fvco(DPHY PLL output frequency) * using the current n,m params
*/
freq = div * (m + 2);
freq /= 1000;
/* Trim the potential pll freq to max supported */ if (freq > PLL_FVCO_MAX) continue;
delta = abs(freq - target_freq_mhz);
/* Select the best (closest to target pll freq) * n,m parameters so far
*/ if (delta < best_freq_delta) {
best_n = n;
best_m = m;
best_freq_delta = delta;
}
}
}
/* Set D-PHY in shutdown mode */ /* Assert RSTZ signal */
CLR_DPHY_INIT_CTRL0(kmb_dsi, dphy_no, RESETZ);
/* Assert SHUTDOWNZ signal */
CLR_DPHY_INIT_CTRL0(kmb_dsi, dphy_no, SHUTDOWNZ);
val = kmb_read_mipi(kmb_dsi, DPHY_INIT_CTRL0);
/* Init D-PHY_n * Pulse testclear signal to make sure the d-phy configuration * starts from a clean base
*/
CLR_DPHY_TEST_CTRL0(kmb_dsi, dphy_no);
ndelay(15);
SET_DPHY_TEST_CTRL0(kmb_dsi, dphy_no);
ndelay(15);
CLR_DPHY_TEST_CTRL0(kmb_dsi, dphy_no);
ndelay(15);
/* Set mastermacro bit - Master or slave mode */
test_code = TEST_CODE_MULTIPLE_PHY_CTRL;
/* DPHY has its own clock lane enabled (master) */ if (mode == MIPI_DPHY_MASTER)
test_data = 0x01; else
test_data = 0x00;
/* Send the test code and data */
test_mode_send(kmb_dsi, dphy_no, test_code, test_data);
/* Set the lane data rate */
set_lane_data_rate(kmb_dsi, dphy_no, cfg);
/* Send NORMAL OPERATION test code */
test_code = 0x0;
test_data = 0x0;
test_mode_send(kmb_dsi, dphy_no, test_code, test_data);
/* Configure BASEDIR for data lanes * NOTE: basedir only applies to LANE_0 of each D-PHY. * The other lanes keep their direction based on the D-PHY type, * either Rx or Tx. * bits[5:0] - BaseDir: 1 = Rx * bits[9:6] - BaseDir: 0 = Tx
*/
kmb_write_bits_mipi(kmb_dsi, DPHY_INIT_CTRL2, 0, 9, 0x03f);
ndelay(15);
/* Enable CLOCK LANE * Clock lane should be enabled regardless of the direction * set for the D-PHY (Rx/Tx)
*/
kmb_set_bit_mipi(kmb_dsi, DPHY_INIT_CTRL2, 12 + dphy_no);
/* Take D-PHY out of shutdown mode */ /* Deassert SHUTDOWNZ signal */
SET_DPHY_INIT_CTRL0(kmb_dsi, dphy_no, SHUTDOWNZ);
ndelay(15);
/* Deassert RSTZ signal */
SET_DPHY_INIT_CTRL0(kmb_dsi, dphy_no, RESETZ);
}
staticvoid dphy_wait_fsm(struct kmb_dsi *kmb_dsi, u32 dphy_no, enum dphy_tx_fsm fsm_state)
{ enum dphy_tx_fsm val = DPHY_TX_POWERDWN; int i = 0; int status = 1;
do {
test_mode_send(kmb_dsi, dphy_no, TEST_CODE_FSM_CONTROL, 0x80);
val = GET_TEST_DOUT4_7(kmb_dsi, dphy_no);
i++; if (i > TIMEOUT) {
status = 0; break;
}
} while (val != fsm_state);
staticvoid wait_pll_lock(struct kmb_dsi *kmb_dsi, u32 dphy_no)
{ int i = 0; int status = 1;
do { /* TODO-need to add a time out and return failure */
i++; if (i > TIMEOUT) {
status = 0;
dev_dbg(kmb_dsi->dev, "%s: timing out", __func__); break;
}
} while (!GET_PLL_LOCK(kmb_dsi, dphy_no));
dev_dbg(kmb_dsi->dev, "* PLL Locked for DPHY %d - %s *",
dphy_no, status ? "SUCCESS" : "FAILED");
}
kmb_dsi->clk_mipi_cfg = devm_clk_get(dev, "clk_mipi_cfg"); if (IS_ERR(kmb_dsi->clk_mipi_cfg)) {
dev_err(dev, "devm_clk_get() failed clk_mipi_cfg\n"); return PTR_ERR(kmb_dsi->clk_mipi_cfg);
} /* Set MIPI clock to 24 Mhz */
clk_set_rate(kmb_dsi->clk_mipi, KMB_MIPI_DEFAULT_CLK); if (clk_get_rate(kmb_dsi->clk_mipi) != KMB_MIPI_DEFAULT_CLK) {
dev_err(dev, "failed to set to clk_mipi to %d\n",
KMB_MIPI_DEFAULT_CLK); return -1;
}
dev_dbg(dev, "clk_mipi = %ld\n", clk_get_rate(kmb_dsi->clk_mipi));
clk = clk_get_rate(kmb_dsi->clk_mipi_ecfg); if (clk != KMB_MIPI_DEFAULT_CFG_CLK) { /* Set MIPI_ECFG clock to 24 Mhz */
clk_set_rate(kmb_dsi->clk_mipi_ecfg, KMB_MIPI_DEFAULT_CFG_CLK);
clk = clk_get_rate(kmb_dsi->clk_mipi_ecfg); if (clk != KMB_MIPI_DEFAULT_CFG_CLK) {
dev_err(dev, "failed to set to clk_mipi_ecfg to %d\n",
KMB_MIPI_DEFAULT_CFG_CLK); return -1;
}
}
clk = clk_get_rate(kmb_dsi->clk_mipi_cfg); if (clk != KMB_MIPI_DEFAULT_CFG_CLK) { /* Set MIPI_CFG clock to 24 Mhz */
clk_set_rate(kmb_dsi->clk_mipi_cfg, 24000000);
clk = clk_get_rate(kmb_dsi->clk_mipi_cfg); if (clk != KMB_MIPI_DEFAULT_CFG_CLK) {
dev_err(dev, "failed to set clk_mipi_cfg to %d\n",
KMB_MIPI_DEFAULT_CFG_CLK); return -1;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.