From 8e4bff4cab0ddac6060645b0715210484d02ff40 Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Wed, 30 Aug 2017 08:25:59 +0000 Subject: Initial file dump from open source release --- drivers/video/sprdfb/dsi_1_10a/Makefile | 2 + drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c | 1216 ++++++++++++++++++++++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h | 113 ++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c | 1031 ++++++++++++++++++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h | 55 + drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c | 529 ++++++++++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h | 242 +++++ drivers/video/sprdfb/dsi_1_10a/mipi_dsih_local.h | 227 ++++ 8 files changed, 3415 insertions(+) create mode 100644 drivers/video/sprdfb/dsi_1_10a/Makefile create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h create mode 100644 drivers/video/sprdfb/dsi_1_10a/mipi_dsih_local.h (limited to 'drivers/video/sprdfb/dsi_1_10a') diff --git a/drivers/video/sprdfb/dsi_1_10a/Makefile b/drivers/video/sprdfb/dsi_1_10a/Makefile new file mode 100644 index 00000000..f5970668 --- /dev/null +++ b/drivers/video/sprdfb/dsi_1_10a/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_FB_SC8825) := mipi_dsih_api.o mipi_dsih_dphy.o mipi_dsih_hal.o +obj-$(CONFIG_FB_SCX35) := mipi_dsih_api.o mipi_dsih_dphy.o mipi_dsih_hal.o diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c new file mode 100644 index 00000000..4747338c --- /dev/null +++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.c @@ -0,0 +1,1216 @@ + +#include "mipi_dsih_api.h" +#include "mipi_dsih_hal.h" +#include "mipi_dsih_dphy.h" +#include "../sprdfb.h" +#include + +/* whether to get debug messages (1) or not (0) */ +#define DEBUG 0 + +#define PRECISION_FACTOR 1000 +#define VIDEO_PACKET_OVERHEAD 6 +#define NULL_PACKET_OVERHEAD 6 +#define SHORT_PACKET 4 +#define BLANKING_PACKET 6 +#define MAX_NULL_SIZE 1023 + +static const uint32_t mipi_dsih_supported_versions[] = {0x3130302A, 0x3130312A, 0x3131302A}; +static const uint32_t mipi_dsih_no_of_versions = sizeof(mipi_dsih_supported_versions) / sizeof(uint32_t); + +/* +func:mipi_dsih_set_lp_clock +desc:in low-power mode, max PHY frequency should smaller than 20MHz, + in synopsys IP, low-power clock divide from high-speed clock, + this function is designed to adapt low-power clock to various high-speed clock. +arithmetic: + Fhs : high-speed frequence + Flp : low-power frequence + div : mipi_dsih_hal_tx_escape_division() param, byte clock unit. + because of the 20MHz demand, Flp == Fhs/(div*8) <= 20 MHz, here 500000 present 500MHz, so MHz equal 1000 + so div >= { Fhs/(20Mhz*8) == Fhs/(20000*8) == (Fhs>>4)/10000 } +*/ +static void mipi_dsih_set_lp_clock(dsih_ctrl_t * instance) +{ + uint32_t tx_escape_division = 1; + tx_escape_division = (instance->phy_feq>>4); + tx_escape_division = (tx_escape_division+9999)/10000;//ceiling calc + printk("sprdfb: [%s]: lp frequence div:%d\n", __func__, tx_escape_division); + mipi_dsih_hal_tx_escape_division(instance, (uint8_t)tx_escape_division); +} + +dsih_error_t mipi_dsih_open(dsih_ctrl_t * instance) +{ + dsih_error_t err = OK; + uint32_t version = 0; + int i = 0; + + if (instance == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + else if ((instance->core_read_function == 0) || (instance->core_write_function == 0)) + { + return ERR_DSI_INVALID_IO; + } + else if (instance->status == INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + else if (mipi_dsih_dphy_open(&(instance->phy_instance))) + { + return ERR_DSI_PHY_INVALID; + } + else + { + instance->status = NOT_INITIALIZED; + version = mipi_dsih_hal_get_version(instance); + for (i = 0; i < mipi_dsih_no_of_versions; i++) + { + if (version == mipi_dsih_supported_versions[i]) + { + break; + } + } + /* no matching supported version has been found*/ + if (i >= mipi_dsih_no_of_versions) + { + if (instance->log_info != 0) + { + instance->log_info("sprdfb: driver does not support this core version 0x%lX", version); + } + return ERR_DSI_CORE_INCOMPATIBLE; + } + } + //mipi_dsih_hal_power(instance, 0);//Jessica + //mipi_dsih_hal_power(instance, 1);//Jessica + mipi_dsih_hal_dpi_color_mode_pol(instance, !instance->color_mode_polarity); + mipi_dsih_hal_dpi_shut_down_pol(instance, !instance->shut_down_polarity); + err = mipi_dsih_phy_hs2lp_config(instance, instance->max_hs_to_lp_cycles); + err |= mipi_dsih_phy_lp2hs_config(instance, instance->max_lp_to_hs_cycles); + err |= mipi_dsih_phy_bta_time(instance, instance->max_bta_cycles); + if (err) + { + return ERR_DSI_OVERFLOW; + } + /* by default, return to LP during ALL, unless otherwise specified*/ + mipi_dsih_hal_dpi_lp_during_hfp(instance, 1); + mipi_dsih_hal_dpi_lp_during_hbp(instance, 1); + mipi_dsih_hal_dpi_lp_during_vactive(instance, 1); + mipi_dsih_hal_dpi_lp_during_vfp(instance, 1); + mipi_dsih_hal_dpi_lp_during_vbp(instance, 1); + mipi_dsih_hal_dpi_lp_during_vsync(instance, 1); + /* by default, all commands are sent in LP */ + mipi_dsih_hal_dcs_wr_tx_type(instance, 0, 1); + mipi_dsih_hal_dcs_wr_tx_type(instance, 1, 1); + mipi_dsih_hal_dcs_wr_tx_type(instance, 3, 1); /* long packet*/ + mipi_dsih_hal_dcs_rd_tx_type(instance, 0, 1); + /*Jessica add to support max rd packet size command*/ + mipi_dsih_hal_max_rd_packet_size_type(instance, 1); + mipi_dsih_hal_gen_wr_tx_type(instance, 0, 1); + mipi_dsih_hal_gen_wr_tx_type(instance, 1, 1); + mipi_dsih_hal_gen_wr_tx_type(instance, 2, 1); + mipi_dsih_hal_gen_wr_tx_type(instance, 3, 1); /* long packet*/ + mipi_dsih_hal_gen_rd_tx_type(instance, 0, 1); + mipi_dsih_hal_gen_rd_tx_type(instance, 1, 1); + mipi_dsih_hal_gen_rd_tx_type(instance, 2, 1); + /* by default, RX_VC = 0, NO EOTp, EOTn, BTA, ECC rx and CRC rx */ + mipi_dsih_hal_gen_rd_vc(instance, 0); + mipi_dsih_hal_gen_eotp_rx_en(instance, 0); + mipi_dsih_hal_gen_eotp_tx_en(instance, 0); + mipi_dsih_hal_bta_en(instance, 0); + mipi_dsih_hal_gen_ecc_rx_en(instance, 0); + mipi_dsih_hal_gen_crc_rx_en(instance, 0); + mipi_dsih_hal_power(instance, 0);//Jessica + mipi_dsih_hal_power(instance, 1);//Jessica + /* initialize pll so escape clocks could be generated at 864MHz, 1 lane */ + /* however the high speed clock will not be requested */ + //err = mipi_dsih_dphy_configure(&(instance->phy_instance), 1, DEFAULT_BYTE_CLOCK); +#if 0 + err = mipi_dsih_dphy_configure(&(instance->phy_instance), instance->max_lanes, 190*1000); + if (err) + { + return err; /* ERR_DSI_PHY_POWERUP; */ + } +#endif + /* dividing by 6 is aimed for max PHY frequency, 1GHz */ + //mipi_dsih_hal_tx_escape_division(instance, 4); //6 //Jessica + mipi_dsih_set_lp_clock(instance); + instance->status = INITIALIZED; + return OK; +} +dsih_error_t mipi_dsih_close(dsih_ctrl_t * instance) +{ + if (instance == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (instance->status != INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + mipi_dsih_dphy_close(&(instance->phy_instance)); + mipi_dsih_hal_power(instance, 0); + return OK; +} +void mipi_dsih_allow_return_to_lp(dsih_ctrl_t * instance, int hfp, int hbp, int vactive, int vfp, int vbp, int vsync) +{ + if(0 == instance) + { + return; + } + + if (instance->status == INITIALIZED) + { + mipi_dsih_hal_dpi_lp_during_hfp(instance, hfp); + mipi_dsih_hal_dpi_lp_during_hbp(instance, hbp); + mipi_dsih_hal_dpi_lp_during_vactive(instance, vactive); + mipi_dsih_hal_dpi_lp_during_vfp(instance, vfp); + mipi_dsih_hal_dpi_lp_during_vbp(instance, vbp); + mipi_dsih_hal_dpi_lp_during_vsync(instance, vsync); + return; + } + + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid instance"); + } +} +void mipi_dsih_dcs_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read) +{ + if(0 == instance) + { + return; + } + + if (instance->status == INITIALIZED) + { + mipi_dsih_hal_dcs_wr_tx_type(instance, 0, short_write); + mipi_dsih_hal_dcs_wr_tx_type(instance, 1, short_write); + mipi_dsih_hal_dcs_wr_tx_type(instance, 3, long_write); /* long packet*/ + mipi_dsih_hal_dcs_rd_tx_type(instance, 0, short_read); + return; + } + + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid instance"); + } +} +void mipi_dsih_gen_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read) +{ + if(0 == instance) + { + return; + } + + if (instance->status == INITIALIZED) + { + mipi_dsih_hal_gen_wr_tx_type(instance, 0, short_write); + mipi_dsih_hal_gen_wr_tx_type(instance, 1, short_write); + mipi_dsih_hal_gen_wr_tx_type(instance, 2, short_write); + mipi_dsih_hal_gen_wr_tx_type(instance, 3, long_write); /* long packet*/ + mipi_dsih_hal_gen_rd_tx_type(instance, 0, short_read); + mipi_dsih_hal_gen_rd_tx_type(instance, 1, short_read); + mipi_dsih_hal_gen_rd_tx_type(instance, 2, short_read); + return; + } + + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid instance"); + } +} +/* packet handling */ +dsih_error_t mipi_dsih_enable_rx(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_hal_bta_en(instance, enable); + return OK; +} +dsih_error_t mipi_dsih_peripheral_ack(dsih_ctrl_t * instance, int enable) +{ + if (instance != 0) + { + if (instance->status == INITIALIZED) + { + mipi_dsih_hal_cmd_ack_en(instance, enable); + if (enable) + { + mipi_dsih_hal_bta_en(instance, 1); + } + return OK; + } + } + return ERR_DSI_INVALID_INSTANCE; +} +dsih_error_t mipi_dsih_tear_effect_ack(dsih_ctrl_t * instance, int enable) +{ + if (instance != 0) + { + if (instance->status == INITIALIZED) + { + mipi_dsih_hal_tear_effect_ack_en(instance, enable); + if (enable) + { + mipi_dsih_hal_bta_en(instance, 1); + } + return OK; + } + } + return ERR_DSI_INVALID_INSTANCE; +} +dsih_error_t mipi_dsih_eotp_rx(dsih_ctrl_t * instance, int enable) +{ + if (instance != 0) + { + if (instance->status == INITIALIZED) + { + mipi_dsih_hal_gen_eotp_rx_en(instance, enable); + if (enable) + { + mipi_dsih_hal_bta_en(instance, 1); + } + return OK; + } + } + return ERR_DSI_INVALID_INSTANCE; +} +dsih_error_t mipi_dsih_ecc_rx(dsih_ctrl_t * instance, int enable) +{ + if (instance != 0) + { + if (instance->status == INITIALIZED) + { + mipi_dsih_hal_gen_ecc_rx_en(instance, enable); + if (enable) + { + mipi_dsih_hal_bta_en(instance, 1); + } + return OK; + } + } + return ERR_DSI_INVALID_INSTANCE; +} +dsih_error_t mipi_dsih_eotp_tx(dsih_ctrl_t * instance, int enable) +{ + if (instance != 0) + { + if (instance->status == INITIALIZED) + { + mipi_dsih_hal_gen_eotp_tx_en(instance, enable); + return OK; + } + } + return ERR_DSI_INVALID_INSTANCE; +} +dsih_error_t mipi_dsih_dpi_video(dsih_ctrl_t * instance, dsih_dpi_video_t * video_params) +{ + dsih_error_t err_code = OK; + uint16_t bytes_per_pixel_x100 = 0; /* bpp x 100 because it can be 2.25 */ + uint16_t video_size = 0; + uint32_t ratio_clock_xPF = 0; /* holds dpi clock/byte clock times precision factor */ + uint16_t null_packet_size = 0; + uint8_t video_size_step = 1; + uint32_t hs_timeout = 0; + uint32_t total_bytes = 0; + uint32_t bytes_per_chunk = 0; + uint32_t no_of_chunks = 0; + uint32_t bytes_left = 0; + uint32_t chunk_overhead = 0; + int counter = 0; + /* check DSI controller instance */ + if ((instance == 0) || (video_params == 0)) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (instance->status != INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + /* set up phy pll to required lane clock */ + //begin--frank + //err_code = mipi_dsih_dphy_configure(&(instance->phy_instance), video_params->no_of_lanes, video_params->byte_clock * 8); + //if (err_code) + //{ + // return err_code; + //} + //end--frank + ratio_clock_xPF = (video_params->byte_clock * PRECISION_FACTOR) / (video_params->pixel_clock); + video_size = video_params->h_active_pixels; + /* set up ACKs and error reporting */ + mipi_dsih_hal_dpi_frame_ack_en(instance, video_params->receive_ack_packets); + if (video_params->receive_ack_packets) + { /* if ACK is requested, enable BTA, otherwise leave as is */ + mipi_dsih_hal_bta_en(instance, 1); + } + mipi_dsih_hal_gen_cmd_mode_en(instance, 0); + mipi_dsih_hal_dpi_video_mode_en(instance, 1); + /* get bytes per pixel and video size step (depending if loosely or not */ + switch (video_params->color_coding) + { + case COLOR_CODE_16BIT_CONFIG1: + case COLOR_CODE_16BIT_CONFIG2: + case COLOR_CODE_16BIT_CONFIG3: + bytes_per_pixel_x100 = 200; + video_size_step = 1; + break; + case COLOR_CODE_18BIT_CONFIG1: + case COLOR_CODE_18BIT_CONFIG2: + mipi_dsih_hal_dpi_18_loosely_packet_en(instance, video_params->is_18_loosely); + bytes_per_pixel_x100 = 225; + if (!video_params->is_18_loosely) + { /* 18bits per pixel and NOT loosely, packets should be multiples of 4 */ + video_size_step = 4; + /* round up active H pixels to a multiple of 4 */ + for (; (video_size % 4) != 0; video_size++) + { + ; + } + } + else + { + video_size_step = 1; + } + break; + case COLOR_CODE_24BIT: + bytes_per_pixel_x100 = 300; + video_size_step = 1; + break; + default: + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid color coding"); + } + err_code = ERR_DSI_COLOR_CODING; + break; + } + if (err_code == OK) + { + err_code = mipi_dsih_hal_dpi_color_coding(instance, video_params->color_coding); + } + if (err_code != OK) + { + return err_code; + } + mipi_dsih_hal_dpi_video_mode_type(instance, video_params->video_mode); + mipi_dsih_hal_dpi_hline(instance, (uint16_t)(((video_params->h_total_pixels) * ratio_clock_xPF) / PRECISION_FACTOR)); + mipi_dsih_hal_dpi_hbp(instance, ((video_params->h_back_porch_pixels * ratio_clock_xPF) / PRECISION_FACTOR)); + mipi_dsih_hal_dpi_hsa(instance, ((video_params->h_sync_pixels * ratio_clock_xPF) / PRECISION_FACTOR)); + mipi_dsih_hal_dpi_vactive(instance, video_params->v_active_lines); + mipi_dsih_hal_dpi_vfp(instance, video_params->v_total_lines - (video_params->v_back_porch_lines + video_params->v_sync_lines + video_params->v_active_lines)); + mipi_dsih_hal_dpi_vbp(instance, video_params->v_back_porch_lines); + mipi_dsih_hal_dpi_vsync(instance, video_params->v_sync_lines); + mipi_dsih_hal_dpi_hsync_pol(instance, !video_params->h_polarity); + mipi_dsih_hal_dpi_vsync_pol(instance, !video_params->v_polarity); + mipi_dsih_hal_dpi_dataen_pol(instance, !video_params->data_en_polarity); + /* HS timeout */ + hs_timeout = ((video_params->h_total_pixels * video_params->v_active_lines) + (DSIH_PIXEL_TOLERANCE * bytes_per_pixel_x100) / 100); + for (counter = 0x80; (counter < hs_timeout) && (counter > 2); counter--) + { + if ((hs_timeout % counter) == 0) + { + mipi_dsih_hal_timeout_clock_division(instance, counter); + mipi_dsih_hal_lp_rx_timeout(instance, (uint16_t)(hs_timeout / counter)); + mipi_dsih_hal_hs_tx_timeout(instance, (uint16_t)(hs_timeout / counter)); + break; + } + } + /* TX_ESC_CLOCK_DIV must be less than 20000KHz */ + //mipi_dsih_hal_tx_escape_division(instance, 4); //6 //Jessia + mipi_dsih_set_lp_clock(instance); + /* video packetisation */ + if (video_params->video_mode == VIDEO_BURST_WITH_SYNC_PULSES) + { /* BURST */ + mipi_dsih_hal_dpi_null_packet_en(instance, 0); + mipi_dsih_hal_dpi_multi_packet_en(instance, 0); + err_code = mipi_dsih_hal_dpi_null_packet_size(instance, 0); + err_code = err_code? err_code: mipi_dsih_hal_dpi_chunks_no(instance, 1); + err_code = err_code? err_code: mipi_dsih_hal_dpi_video_packet_size(instance, video_size); + if (err_code != OK) + { + return err_code; + } + /* BURST by default, returns to LP during ALL empty periods - energy saving */ + mipi_dsih_hal_dpi_lp_during_hfp(instance, 1); +#if defined(CONFIG_FB_LCD_SSD2075_MIPI) + mipi_dsih_hal_dpi_lp_during_hbp(instance, 0); +#else + mipi_dsih_hal_dpi_lp_during_hbp(instance, 1); +#endif + mipi_dsih_hal_dpi_lp_during_vactive(instance, 1); + mipi_dsih_hal_dpi_lp_during_vfp(instance, 1); + mipi_dsih_hal_dpi_lp_during_vbp(instance, 1); + mipi_dsih_hal_dpi_lp_during_vsync(instance, 1); +#if DEBUG + /* D E B U G */ + if (instance->log_info != 0) + { + instance->log_info("sprdfb: burst video"); + instance->log_info("sprdfb: h line time %ld", (uint16_t)((video_params->h_total_pixels * ratio_clock_xPF) / PRECISION_FACTOR)); + instance->log_info("sprdfb: video_size %ld", video_size); + } +#endif + } + else + { /* non burst transmission */ + null_packet_size = 0; + /* bytes to be sent - first as one chunk*/ + bytes_per_chunk = (bytes_per_pixel_x100 * video_params->h_active_pixels) / 100 + VIDEO_PACKET_OVERHEAD; + /* bytes being received through the DPI interface per byte clock cycle */ + total_bytes = (ratio_clock_xPF * video_params->no_of_lanes * (video_params->h_total_pixels - video_params->h_back_porch_pixels - video_params->h_sync_pixels)) / PRECISION_FACTOR; + /* check if the in pixels actually fit on the DSI link */ + if (total_bytes >= bytes_per_chunk) + { + chunk_overhead = total_bytes - bytes_per_chunk; + /* overhead higher than 1 -> enable multi packets */ + if (chunk_overhead > 1) + { /* MULTI packets */ + for (video_size = video_size_step; video_size < video_params->h_active_pixels; video_size += video_size_step) + { /* determine no of chunks */ + if ((((video_params->h_active_pixels * PRECISION_FACTOR) / video_size) % PRECISION_FACTOR) == 0) + { + no_of_chunks = video_params->h_active_pixels / video_size; + bytes_per_chunk = (bytes_per_pixel_x100 * video_size) / 100 + VIDEO_PACKET_OVERHEAD; + if (total_bytes >= (bytes_per_chunk * no_of_chunks)) + { + bytes_left = total_bytes - (bytes_per_chunk * no_of_chunks); + break; + } + } + } + /* prevent overflow (unsigned - unsigned) */ + if (bytes_left > (NULL_PACKET_OVERHEAD * no_of_chunks)) + { + null_packet_size = (bytes_left - (NULL_PACKET_OVERHEAD * no_of_chunks)) / no_of_chunks; + if (null_packet_size > MAX_NULL_SIZE) + { /* avoid register overflow */ + null_packet_size = MAX_NULL_SIZE; + } + } + } + else + { /* no multi packets */ + no_of_chunks = 1; +#if DEBUG + /* D E B U G */ + if (instance->log_info != 0) + { + instance->log_info("sprdfb: no multi no null video"); + instance->log_info("sprdfb: h line time %ld", (uint16_t)((video_params->h_total_pixels * ratio_clock_xPF) / PRECISION_FACTOR)); + instance->log_info("sprdfb: video_size %ld", video_size); + } + /************************/ +#endif + /* video size must be a multiple of 4 when not 18 loosely */ + for (video_size = video_params->h_active_pixels; (video_size % video_size_step) != 0; video_size++) + { + ; + } + } + } + else + { + instance->log_error("sprdfb: resolution cannot be sent to display through current settings"); + err_code = ERR_DSI_OVERFLOW; + } + } + err_code = err_code? err_code: mipi_dsih_hal_dpi_chunks_no(instance, no_of_chunks); + err_code = err_code? err_code: mipi_dsih_hal_dpi_video_packet_size(instance, video_size); + err_code = err_code? err_code: mipi_dsih_hal_dpi_null_packet_size(instance, null_packet_size); + mipi_dsih_hal_dpi_null_packet_en(instance, null_packet_size > 0? 1: 0); + mipi_dsih_hal_dpi_multi_packet_en(instance, (no_of_chunks > 1)? 1: 0); +#if DEBUG + /* D E B U G */ + if (instance->log_info != 0) + { + instance->log_info("sprdfb: total_bytes %d", total_bytes); + instance->log_info("sprdfb: bytes_per_chunk %d", bytes_per_chunk); + instance->log_info("sprdfb: bytes left %d", bytes_left); + instance->log_info("sprdfb: null packets %d", null_packet_size); + instance->log_info("sprdfb: chunks %ld", no_of_chunks); + instance->log_info("sprdfb: video_size %ld", video_size); + } + /************************/ +#endif + mipi_dsih_hal_dpi_video_vc(instance, video_params->virtual_channel); + mipi_dsih_dphy_no_of_lanes(&(instance->phy_instance), video_params->no_of_lanes); + /* enable high speed clock */ +// mipi_dsih_dphy_enable_hs_clk(&(instance->phy_instance), 1); + return err_code; +} +dsih_error_t mipi_dsih_dcs_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length) +{ + uint8_t packet_type = 0; +// int i = 0; + if (params == 0) + { + return ERR_DSI_OUT_OF_BOUND; + } +#if 0 + if (param_length > 2) + { + i = 2; + } + switch (params[i]) + { + case 0x39: + case 0x38: + case 0x34: + case 0x29: + case 0x28: + case 0x21: + case 0x20: + case 0x13: + case 0x12: + case 0x11: + case 0x10: + case 0x01: + case 0x00: + packet_type = 0x05; /* DCS short write no param */ + break; + case 0x3A: + case 0x36: + case 0x35: + case 0x26: + packet_type = 0x15; /* DCS short write 1 param */ + break; + case 0x44: + case 0x3C: + case 0x37: + case 0x33: + case 0x30: + case 0x2D: + case 0x2C: + case 0x2B: + case 0x2A: + packet_type = 0x39; /* DCS long write/write_LUT command packet */ + break; + default: + if (instance->log_error != 0) + { + instance->log_error("invalid DCS command"); + } + return ERR_DSI_INVALID_COMMAND; + } +#endif + switch(param_length) + { + case 1: + packet_type = 0x05; /* DCS short write no param */ + break; + case 2: + packet_type = 0x15; /* DCS short write 1 param */ + break; + default: + packet_type = 0x39; /* DCS long write/write_LUT command packet */ + break; + } + + return mipi_dsih_gen_wr_packet(instance, vc, packet_type, params, param_length); +} +void mipi_dsih_cmd_mode(dsih_ctrl_t * instance, int en) +{ + if(0 == instance) + { + return; + } + + if (instance->status == INITIALIZED) + { + if ((!mipi_dsih_hal_gen_is_cmd_mode(instance)) && en) + { /* disable video mode first */ + mipi_dsih_hal_dpi_video_mode_en(instance, 0); + mipi_dsih_hal_gen_cmd_mode_en(instance, 1); + } + else if ((mipi_dsih_hal_gen_is_cmd_mode(instance)) && !en) + { + mipi_dsih_hal_gen_cmd_mode_en(instance, 0); + } + return; + } + + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid instance"); + } +} + +void mipi_dsih_video_mode(dsih_ctrl_t * instance, int en) +{ + if(0 == instance) + { + return; + } + + if (instance->status == INITIALIZED) + { + if ((!mipi_dsih_hal_dpi_is_video_mode(instance)) && en) + { /* disable cmd mode first */ + mipi_dsih_hal_gen_cmd_mode_en(instance, 0); + mipi_dsih_hal_dpi_video_mode_en(instance, 1); + } + else if ((!mipi_dsih_hal_dpi_is_video_mode(instance)) && !en) + { + mipi_dsih_hal_dpi_video_mode_en(instance, 0); + } + return; + } + + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid instance"); + } +} + +int mipi_dsih_active_mode(dsih_ctrl_t * instance) +{ + int ret_val=0; + if (mipi_dsih_hal_gen_is_cmd_mode(instance)) + { + ret_val=ret_val|0x1; + } + if (mipi_dsih_hal_dpi_is_video_mode(instance)) + { + ret_val=ret_val|0x2; + } + return ret_val; +} + +dsih_error_t mipi_dsih_gen_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length) +{ + uint8_t data_type = 0; + switch(param_length) + { + case 0: + data_type = 0x03; + break; + case 1: + data_type = 0x13; + break; + case 2: + data_type = 0x23; + break; + default: + data_type = 0x29; + break; + } + return mipi_dsih_gen_wr_packet(instance, vc, data_type, params, param_length); +} +dsih_error_t mipi_dsih_gen_wr_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t* params, uint16_t param_length) +{ + dsih_error_t err_code = OK; + /* active delay iterator */ + int timeout = 0; + /* iterators */ + int i = 0; + int j = 0; + /* holds padding bytes needed */ + int compliment_counter = 0; + uint8_t* payload = 0; + /* temporary variable to arrange bytes into words */ + uint32_t temp = 0; + uint16_t word_count = 0; + if (instance == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (instance->status != INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + if ((params == 0) && (param_length != 0)) /* pointer NULL */ + { + return ERR_DSI_OUT_OF_BOUND; + } + if (param_length > 2) + { /* long packet - write word count to header, and the rest to payload */ + payload = params + (2 * sizeof(params[0])); + word_count = (params[1] << 8) | params[0]; + if ((param_length - 2) < word_count) + { + if (instance->log_error != 0) + { + instance->log_error("sprdfb: sent > input payload. complemented with zeroes"); + } + compliment_counter = (param_length - 2) - word_count; + } + else if ((param_length - 2) > word_count) + { + if (instance->log_error != 0) + { + instance->log_error("sprdfb: Overflow - input > sent. payload truncated"); + } + } + for (i = 0; i < (param_length - 2); i += j) + { + temp = 0; + for (j = 0; (j < 4) && ((j + i) < (param_length - 2)); j++) + { /* temp = (payload[i + 3] << 24) | (payload[i + 2] << 16) | (payload[i + 1] << 8) | payload[i]; */ + temp |= payload[i + j] << (j * 8); + } + /* check if payload Tx fifo is not full */ + for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) + { + if (!mipi_dsih_hal_gen_packet_payload(instance, temp)) + { + break; + } + } + if (!(timeout < DSIH_FIFO_ACTIVE_WAIT)) + { + return ERR_DSI_TIMEOUT; + } + } + /* if word count entered by the user more than actual parameters received + * fill with zeroes - a fail safe mechanism, otherwise controller will + * want to send data from an empty buffer */ + for (i = 0; i < compliment_counter; i++) + { + /* check if payload Tx fifo is not full */ + for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) + { + if (!mipi_dsih_hal_gen_packet_payload(instance, 0x00)) + { + break; + } + } + if (!(timeout < DSIH_FIFO_ACTIVE_WAIT)) + { + return ERR_DSI_TIMEOUT; + } + } + } + for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) + { + /* check if payload Tx fifo is not full */ + if (!mipi_dsih_hal_gen_cmd_fifo_full(instance)) + { + if (param_length == 0) + { + err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, 0x0, 0x0); + } + else if (param_length == 1) + { + err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, 0x0, params[0]); + } + else + { + err_code |= mipi_dsih_hal_gen_packet_header(instance, vc, data_type, params[1], params[0]); + } + break; + } + } + if (!(timeout < DSIH_FIFO_ACTIVE_WAIT)) + { + err_code = ERR_DSI_TIMEOUT; + } + return err_code; +} +uint16_t mipi_dsih_dcs_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t command, uint8_t bytes_to_read, uint8_t* read_buffer) +{ + if (instance == 0) + { + return 0; + } + if (instance->status != INITIALIZED) + { + return 0; + } + switch (command) + { + case 0xA8: + case 0xA1: + case 0x45: + case 0x3E: + case 0x2E: + case 0x0F: + case 0x0E: + case 0x0D: + case 0x0C: + case 0x0B: + case 0x0A: + case 0x08: + case 0x07: + case 0x06: + /* COMMAND_TYPE 0x06 - DCS Read no params refer to DSI spec p.47 */ + return mipi_dsih_gen_rd_packet(instance, vc, 0x06, 0x0, command, bytes_to_read, read_buffer); + default: + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid DCS command"); + } + return 0; + } + return 0; +} +uint16_t mipi_dsih_gen_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length, uint8_t bytes_to_read, uint8_t* read_buffer) +{ + uint8_t data_type = 0; + if (instance == 0) + { + return 0; + } + if (instance->status != INITIALIZED) + { + return 0; + } + switch(param_length) + { + case 0: + data_type = 0x04; + return mipi_dsih_gen_rd_packet(instance, vc, data_type, 0x00, 0x00, bytes_to_read, read_buffer); + case 1: + data_type = 0x14; + return mipi_dsih_gen_rd_packet(instance, vc, data_type, 0x00, params[0], bytes_to_read, read_buffer); + case 2: + data_type = 0x24; + return mipi_dsih_gen_rd_packet(instance, vc, data_type, params[1], params[0], bytes_to_read, read_buffer); + default: + return 0; + } +} +uint16_t mipi_dsih_gen_rd_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t msb_byte, uint8_t lsb_byte, uint8_t bytes_to_read, uint8_t* read_buffer) +{ + dsih_error_t err_code = OK; + int timeout = 0; + int counter = 0; + int i = 0; + int last_count = 0; + uint32_t temp[1] = {0}; + if (instance == 0) + { + return 0; + } + if (instance->status != INITIALIZED) + { + return 0; + } + if (bytes_to_read < 1) + { + return 0; + } + if (read_buffer == 0) + { + return 0; + } +#ifndef FB_CHECK_ESD_IN_VFP + /* make sure command mode is on */ + mipi_dsih_cmd_mode(instance, 1); +#endif + /* make sure receiving is enabled */ + mipi_dsih_hal_bta_en(instance, 1); + /* listen to the same virtual channel as the one sent to */ + mipi_dsih_hal_gen_rd_vc(instance, vc); + for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) + { /* check if payload Tx fifo is not full */ + if (!mipi_dsih_hal_gen_cmd_fifo_full(instance)) + { + mipi_dsih_hal_gen_packet_header(instance, vc, data_type, msb_byte, lsb_byte); + break; + } + } + if (!(timeout < DSIH_FIFO_ACTIVE_WAIT)) + { + if (instance->log_error != 0) + { + instance->log_error("sprdfb: tx rd command timed out\n"); + } + return 0; + } + /* loop for the number of words to be read */ + for (timeout = 0; timeout < DSIH_FIFO_ACTIVE_WAIT; timeout++) + { /* check if command transaction is done */ + if (!mipi_dsih_hal_gen_rd_cmd_busy(instance)) + { + if (!mipi_dsih_hal_gen_read_fifo_empty(instance)) + { + for (counter = 0; (!mipi_dsih_hal_gen_read_fifo_empty(instance)); counter += 4) + { + err_code = mipi_dsih_hal_gen_read_payload(instance, temp); + if (err_code) + { + return 0; + } + if (counter < bytes_to_read) + { + for (i = 0; i < 4; i++) + { + if ((counter + i) < bytes_to_read) + { + /* put 32 bit temp in 4 bytes of buffer passed by user*/ + read_buffer[counter + i] = (uint8_t)(temp[0] >> (i * 8)); + last_count = i + counter; + } + else + { + if ((uint8_t)(temp[0] >> (i * 8)) != 0x00) + { + last_count = i + counter; + } + } + } + } + else + { + last_count = counter; + for (i = 0; i < 4; i++) + { + if ((uint8_t)(temp[0] >> (i * 8)) != 0x00) + { + last_count = i + counter; + } + } + } + } + return last_count + 1; + } +#ifdef FB_CHECK_ESD_IN_VFP + else if(timeout == (DSIH_FIFO_ACTIVE_WAIT - 1))//else +#else + else +#endif + { + if (instance->log_error != 0) + { + instance->log_error("sprdfb: rx buffer empty\n"); + } + return 0; + } + } +//#ifdef FB_CHECK_ESD_IN_VFP + udelay(5); +//#endif + } + if (instance->log_error != 0) + { + instance->log_error("sprdfb: rx command timed out\n"); + } + return 0; +} +uint32_t mipi_dsih_dump_register_configuration(dsih_ctrl_t * instance, int all, register_config_t *config, uint16_t config_length) +{ + uint32_t current0 = 0; + uint16_t count = 0; + if (instance == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (instance->status != INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (all) + { /* dump all registers */ + for (current0 = R_DSI_HOST_VERSION; current0 <= R_DSI_HOST_ERROR_MSK1; count++, current0 += (R_DSI_HOST_PWR_UP - R_DSI_HOST_VERSION)) + { + if ((config_length == 0) || (config == 0) || count >= config_length) + { /* no place to write - write to STD IO */ + if (instance->log_info != 0) + { + instance->log_info("sprdfb: DSI 0x%lX:0x%lX", current0, mipi_dsih_read_word(instance, current0)); + } + } + else + { + config[count].addr = current0; + config[count].data = mipi_dsih_read_word(instance, current0); + } + } + } + else + { + if(config == 0) + { + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid buffer"); + } + } + else + { + for (count = 0; count < config_length; count++) + { + config[count].data = mipi_dsih_read_word(instance, config[count].addr); + } + } + } + return count; +} +uint32_t mipi_dsih_write_register_configuration(dsih_ctrl_t * instance, register_config_t *config, uint16_t config_length) +{ + uint16_t count = 0; + if (instance == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (instance->status != INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + for (count = 0; count < config_length; count++) + { + mipi_dsih_write_word(instance, config[count].addr, config[count].data); + } + return count; +} +dsih_error_t mipi_dsih_register_event(dsih_ctrl_t * instance, dsih_event_t event, void (*handler)(dsih_ctrl_t *, void *)) +{ + uint32_t mask = 1; + uint32_t temp = 0; + if (event >= DSI_MAX_EVENT) + { + return ERR_DSI_INVALID_EVENT; + } + if (handler == 0) + { + return ERR_DSI_INVALID_HANDLE; + } + if (instance == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (instance->status != INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + instance->event_registry[event] = handler; + if (event < HS_CONTENTION) + { + temp = mipi_dsih_hal_get_error_mask_0(instance, 0xffffffff); + temp &= ~(mask << event); + temp |= (0 & mask) << event; + mipi_dsih_hal_error_mask_0(instance, temp); + } + else + { + temp = mipi_dsih_hal_get_error_mask_1(instance, 0xffffffff); + temp &= ~(mask << (event - HS_CONTENTION)); + temp |= (0 & mask) << (event - HS_CONTENTION); + mipi_dsih_hal_error_mask_1(instance, temp); + if (event == RX_CRC_ERR) + { /* automatically enable CRC reporting */ + mipi_dsih_hal_gen_crc_rx_en(instance, 1); + } + } + return OK; +} +dsih_error_t mipi_dsih_unregister_event(dsih_ctrl_t * instance, dsih_event_t event) +{ + uint32_t mask = 1; + uint32_t temp = 0; + if (event >= DSI_MAX_EVENT) + { + return ERR_DSI_INVALID_EVENT; + } + if (instance == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (instance->status != INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + instance->event_registry[event] = 0; + if (event < HS_CONTENTION) + { + temp = mipi_dsih_hal_get_error_mask_0(instance, 0xffffffff); + temp &= ~(mask << event); + temp |= (1 & mask) << event; + mipi_dsih_hal_error_mask_0(instance, temp); + } + else + { + temp = mipi_dsih_hal_get_error_mask_1(instance, 0xffffffff); + temp &= ~(mask << (event - HS_CONTENTION)); + temp |= (1 & mask) << (event - HS_CONTENTION); + mipi_dsih_hal_error_mask_1(instance, temp); + if (event == RX_CRC_ERR) + { /* automatically disable CRC reporting */ + mipi_dsih_hal_gen_crc_rx_en(instance, 0); + } + } + return OK; +} +dsih_error_t mipi_dsih_unregister_all_events(dsih_ctrl_t * instance) +{ + int i = 0; + if (instance == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (instance->status != INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + for (i = 0; i < DSI_MAX_EVENT; i++) + { + instance->event_registry[i] = 0; + } + mipi_dsih_hal_error_mask_0(instance, 0xffffff); + mipi_dsih_hal_error_mask_1(instance, 0xffffff); + /* automatically disable CRC reporting */ + mipi_dsih_hal_gen_crc_rx_en(instance, 0); + return OK; +} +void mipi_dsih_event_handler(void * param) +{ + dsih_ctrl_t * instance = (dsih_ctrl_t *)(param); + uint8_t i = 0; + uint32_t status_0; + uint32_t status_1; + + if (instance == 0) + { + return; + } + + status_0 = mipi_dsih_hal_error_status_0(instance, 0xffffffff); + status_1 = mipi_dsih_hal_error_status_1(instance, 0xffffffff); + + for (i = 0; i < DSI_MAX_EVENT; i++) + { + if (instance->event_registry[i] != 0) + { + if (i < HS_CONTENTION) + { + if ((status_0 & (1 << i)) != 0) + { + instance->event_registry[i](instance, &i); + } + } + else + { + if ((status_1 & (1 << (i - HS_CONTENTION))) != 0) + { + instance->event_registry[i](instance, &i); + } + } + } + } +} +void mipi_dsih_reset_controller(dsih_ctrl_t * instance) +{ + mipi_dsih_hal_power(instance, 0); + mipi_dsih_hal_power(instance, 1); +} +void mipi_dsih_shutdown_controller(dsih_ctrl_t * instance, int shutdown) +{ + mipi_dsih_hal_power(instance, !shutdown); +} +void mipi_dsih_reset_phy(dsih_ctrl_t * instance) +{ + mipi_dsih_dphy_reset(&(instance->phy_instance), 0); + mipi_dsih_dphy_reset(&(instance->phy_instance), 1); +} +void mipi_dsih_shutdown_phy(dsih_ctrl_t * instance, int shutdown) +{ + mipi_dsih_dphy_shutdown(&(instance->phy_instance), !shutdown); +} + +void mipi_dsih_ulps_mode(dsih_ctrl_t * instance, int en) +{ + mipi_dsih_dphy_ulps_data_lanes(&(instance->phy_instance),en); + mipi_dsih_dphy_ulps_clk_lane(&(instance->phy_instance),en); +} + + diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h new file mode 100644 index 00000000..5004c55c --- /dev/null +++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_api.h @@ -0,0 +1,113 @@ + +/* + The Synopsys Software Driver and documentation (hereinafter "Software") + is an unsupported work of Synopsys, Inc. unless otherwise + expressly agreed to in writing between Synopsys and you. + + The Software IS NOT an item of Licensed Software or Licensed Product under + any End User Software License Agreement or Agreement for Licensed Product + with Synopsys or any supplement thereto. Permission is hereby granted, + free of charge, to any person obtaining a copy of this software annotated + with this license and the Software, to deal in the Software without + restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, subject + to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + */ +#ifndef MIPI_DSIH_API_H_ +#define MIPI_DSIH_API_H_ + +#include "mipi_dsih_local.h" + +/* general configuration functions */ + +dsih_error_t mipi_dsih_open(dsih_ctrl_t * instance); + +dsih_error_t mipi_dsih_close(dsih_ctrl_t * instance); + +void mipi_dsih_reset_controller(dsih_ctrl_t * instance); + +void mipi_dsih_shutdown_controller(dsih_ctrl_t * instance, int shutdown); + +void mipi_dsih_reset_phy(dsih_ctrl_t * instance); + +void mipi_dsih_shutdown_phy(dsih_ctrl_t * instance, int shutdown); + +void mipi_dsih_ulps_mode(dsih_ctrl_t * instance, int en); + +/* packet handling */ + +dsih_error_t mipi_dsih_enable_rx(dsih_ctrl_t * instance, int enable); + +dsih_error_t mipi_dsih_peripheral_ack(dsih_ctrl_t * instance, int enable); + +dsih_error_t mipi_dsih_tear_effect_ack(dsih_ctrl_t * instance, int enable); + +dsih_error_t mipi_dsih_eotp_rx(dsih_ctrl_t * instance, int enable); + +dsih_error_t mipi_dsih_ecc_rx(dsih_ctrl_t * instance, int enable); + + +dsih_error_t mipi_dsih_eotp_tx(dsih_ctrl_t * instance, int enable); + +/* video mode functions */ + +dsih_error_t mipi_dsih_dpi_video(dsih_ctrl_t * instance, dsih_dpi_video_t * video_params); + +void mipi_dsih_allow_return_to_lp(dsih_ctrl_t * instance, int hfp, int hbp, int vactive, int vfp, int vbp, int vsync); + +/* command mode functions */ + +dsih_error_t mipi_dsih_dcs_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length); + +dsih_error_t mipi_dsih_gen_wr_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length); + +dsih_error_t mipi_dsih_gen_wr_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t* params, uint16_t param_length); + +uint16_t mipi_dsih_dcs_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t command, uint8_t bytes_to_read, uint8_t* read_buffer); + +uint16_t mipi_dsih_gen_rd_cmd(dsih_ctrl_t * instance, uint8_t vc, uint8_t* params, uint16_t param_length, uint8_t bytes_to_read, uint8_t* read_buffer); + +uint16_t mipi_dsih_gen_rd_packet(dsih_ctrl_t * instance, uint8_t vc, uint8_t data_type, uint8_t msb_byte, uint8_t lsb_byte, uint8_t bytes_to_read, uint8_t* read_buffer); + +void mipi_dsih_cmd_mode(dsih_ctrl_t * instance, int en); + +void mipi_dsih_video_mode(dsih_ctrl_t * instance, int en); + +int mipi_dsih_active_mode(dsih_ctrl_t * instance); + +void mipi_dsih_dcs_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read); + +void mipi_dsih_gen_cmd_lp_transmission(dsih_ctrl_t * instance, int long_write, int short_write, int short_read); + +/* event handling functions */ + +dsih_error_t mipi_dsih_register_event(dsih_ctrl_t * instance, dsih_event_t event, void (*handler)(dsih_ctrl_t *, void *)); + +dsih_error_t mipi_dsih_unregister_event(dsih_ctrl_t * instance, dsih_event_t event); + +dsih_error_t mipi_dsih_unregister_all_events(dsih_ctrl_t * instance); + +void mipi_dsih_event_handler(void * param); + +uint32_t mipi_dsih_dump_register_configuration(dsih_ctrl_t * instance, int all, register_config_t *config, uint16_t config_length); + +uint32_t mipi_dsih_write_register_configuration(dsih_ctrl_t * instance, register_config_t *config, uint16_t config_length); + + +#endif /* MIPI_DSIH_API_H_ */ diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c new file mode 100644 index 00000000..ab68b9e2 --- /dev/null +++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.c @@ -0,0 +1,1031 @@ + +#include "mipi_dsih_dphy.h" + +#define PRECISION_FACTOR (1000) +/* Reference clock frequency divided by Input Frequency Division Ratio LIMITS */ +#define DPHY_DIV_UPPER_LIMIT (40000) +#ifdef GEN_2 +#define DPHY_DIV_LOWER_LIMIT (5000) +#else +#define DPHY_DIV_LOWER_LIMIT (1000) +#endif +#if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined GEN_2)) +#define MIN_OUTPUT_FREQ (80) +#elif defined DPHY2Btql +#define MIN_OUTPUT_FREQ (200) +#undef GEN_2 +#endif +/** + * Initialise D-PHY module and power up + * @param phy pointer to structure which holds information about the d-phy + * module + * @return error code + */ +dsih_error_t mipi_dsih_dphy_open(dphy_t * phy) +{ + if (phy == 0) + { + return ERR_DSI_PHY_INVALID; + } + else if ((phy->core_read_function == 0) || (phy->core_write_function == 0)) + { + return ERR_DSI_INVALID_IO; + } + else if (phy->status == INITIALIZED) + { + return ERR_DSI_PHY_INVALID; + } + phy->status = NOT_INITIALIZED; +#if 0 + mipi_dsih_dphy_reset(phy, 0); + mipi_dsih_dphy_stop_wait_time(phy, 0x1C); + mipi_dsih_dphy_no_of_lanes(phy, 1); + mipi_dsih_dphy_clock_en(phy, 1); + mipi_dsih_dphy_shutdown(phy, 1); + mipi_dsih_dphy_reset(phy, 1); +#endif + phy->status = INITIALIZED; + return OK; +} +uint8_t mipi_dsih_dphy_test_data_read(dphy_t * instance, uint8_t address) +{ + uint32_t i = 0; + mipi_dsih_dphy_test_clock(instance, 1); + /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */ + mipi_dsih_dphy_test_data_in(instance, address); + /* set TESTEN input high */ + mipi_dsih_dphy_test_en(instance, 1); + /* drive the TESTCLK input low; the falling edge captures the chosen test code into the transceiver */ + mipi_dsih_dphy_test_clock(instance, 0); + /* set TESTEN input low to disable further test mode code latching */ + mipi_dsih_dphy_test_en(instance, 0); + +// udelay(1); + for(i=0;i<1000;i++) + ; + return mipi_dsih_dphy_test_data_out(instance); +} + +/** + * Configure D-PHY and PLL module to desired operation mode + * @param phy pointer to structure which holds information about the d-phy + * module + * @param no_of_lanes active + * @param output_freq desired high speed frequency + * @return error code + */ + + #ifdef GEN_2 +dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq) +{ + uint32_t loop_divider = 0; /* (M) */ + uint32_t input_divider = 1; /* (N) */ + uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/ + uint8_t no_of_bytes = 0; + uint8_t i = 0; + uint8_t n=0;/* iterator */ + uint8_t range = 0; /* ranges iterator */ + int flag = 0; + struct + { + uint32_t loop_div; /* upper limit of loop divider range */ + uint8_t cp_current; /* icpctrl */ + uint8_t lpf_resistor; /* lpfctrl */ + } + loop_bandwidth[] = + + { /* gen 2 associates the charge pump current and LPF resistor with the + output frequency ranges (and thus we simplify here to use the + counter/pointer of the following structure) */ + { 90, 0x02, 0x02}, { 100, 0x02, 0x02}, { 110, 0x02, 0x02}, + { 130, 0x02, 0x01}, { 140, 0x02, 0x01}, { 150, 0x02, 0x01}, + { 170, 0x09, 0x00}, { 180, 0x09, 0x01}, { 200, 0x09, 0x01}, + { 220, 0x09, 0x04}, { 240, 0x09, 0x04}, { 250, 0x09, 0x04}, + { 270, 0x06, 0x04}, { 300, 0x06, 0x04}, { 330, 0x09, 0x04}, + { 360, 0x09, 0x04}, { 400, 0x09, 0x04}, { 450, 0x06, 0x04}, + { 500, 0x06, 0x04}, { 550, 0x06, 0x04}, { 600, 0x06, 0x04}, + { 650, 0x0A, 0x04}, { 700, 0x0A, 0x04}, { 750, 0x0A, 0x04}, + { 800, 0x0A, 0x04}, { 850, 0x0A, 0x04}, { 900, 0x0A, 0x04}, + { 950, 0x0B, 0x08}, {1000, 0x0B, 0x08}, {1050, 0x0B, 0x08}, + {1100, 0x0B, 0x08}, {1150, 0x0B, 0x08}, {1200, 0x0B, 0x08}, + {1250, 0x0B, 0x08}, {1300, 0x0B, 0x08}, {1350, 0x0B, 0x08}, + {1400, 0x0B, 0x08}, {1450, 0x0B, 0x08}, {1500, 0x0B, 0x08} + }; + uint32_t delta = 0; + uint32_t tmp_loop_divider = 0; + unsigned step = 0; + + struct + { + uint32_t freq; /* upper margin of frequency range */ + uint8_t hs_freq; /* hsfreqrange */ + uint8_t vco_range; /* vcorange */ + } + ranges[] = + { + { 90, 0x00, 0x00}, { 100, 0x10, 0x00}, { 110, 0x20, 0x00}, + { 130, 0x01, 0x00}, { 140, 0x11, 0x00}, { 150, 0x21, 0x00}, + { 170, 0x02, 0x00}, { 180, 0x12, 0x00}, { 200, 0x22, 0x00}, + { 220, 0x03, 0x01}, { 240, 0x13, 0x01}, { 250, 0x23, 0x01}, + { 270, 0x04, 0x01}, { 300, 0x14, 0x01}, { 330, 0x05, 0x02}, + { 360, 0x15, 0x02}, { 400, 0x25, 0x02}, { 450, 0x06, 0x02}, + { 500, 0x16, 0x02}, { 550, 0x07, 0x03}, { 600, 0x17, 0x03}, + { 650, 0x08, 0x03}, { 700, 0x18, 0x03}, { 750, 0x09, 0x04}, + { 800, 0x19, 0x04}, { 850, 0x29, 0x04}, { 900, 0x39, 0x04}, + { 950, 0x0A, 0x05}, {1000, 0x1A, 0x05}, {1050, 0x2A, 0x05}, + {1100, 0x3A, 0x05}, {1150, 0x0B, 0x06}, {1200, 0x1B, 0x06}, + {1250, 0x2B, 0x06}, {1300, 0x3B, 0x06}, {1350, 0x0C, 0x07}, + {1400, 0x1C, 0x07}, {1450, 0x2C, 0x07}, {1500, 0x3C, 0x07} + }; + + if (phy == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (phy->status < INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (output_freq < MIN_OUTPUT_FREQ) + { + return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; + } + + loop_divider = ((output_freq * (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) / phy->reference_freq); + /* here delta will account for the rounding */ + delta = ((loop_divider * phy->reference_freq) / (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) - output_freq; + for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++) + { + tmp_loop_divider = ((output_freq * input_divider) / (phy->reference_freq)); + if ((tmp_loop_divider % 2) == 0) + { /* if even */ + if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider))) + { /* exact values found */ + flag = 1; + loop_divider = tmp_loop_divider; + delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider)); + /* variable was incremented before exiting the loop */ + input_divider--; + } + if ((output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider))) < delta) + { /* values found with smaller delta */ + loop_divider = tmp_loop_divider; + delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider)); + step = 1; + } + } + else + { + tmp_loop_divider += 1; + if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider))) + { /* exact values found */ + flag = 1; + loop_divider = tmp_loop_divider; + delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq; + /* variable was incremented before exiting the loop */ + input_divider--; + } + if (((tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq) < delta) + { /* values found with smaller delta */ + loop_divider = tmp_loop_divider; + delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq; + step = 0; + } + } + } + if (!flag) + { + input_divider = step + (loop_divider * phy->reference_freq) / output_freq; +// phy->log_info("D-PHY: Approximated Frequency: %d KHz", (loop_divider * (phy->reference_freq / input_divider))); + } +#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING + if (phy->phy_keep_work != true) +#endif + { + /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to + avoid transient periods in PHY operation during re-configuration procedures. */ + mipi_dsih_dphy_reset(phy, 0); + mipi_dsih_dphy_clock_en(phy, 0); + mipi_dsih_dphy_shutdown(phy, 0); + /* provide an initial active-high test clear pulse in TESTCLR */ + mipi_dsih_dphy_test_clear(phy, 1); + mipi_dsih_dphy_test_clear(phy, 0); + for(n=0;n<100;n++){ + ; + } + } + /* find ranges */ + for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++) + { + ; + } + if (range >= (sizeof(ranges)/sizeof(ranges[0]))) + { + return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; + } + /* set up board depending on environment if any */ + if (phy->bsp_pre_config != 0) + { + phy->bsp_pre_config(phy, 0); + } + + /* Jessica add - begin*/ + data[0] = 0x83;//0x44;//0x44;//0x40; //0x40: ok for 200 clock lane lpx /*about 52ns*/ + mipi_dsih_dphy_write(phy, 0x60, data, 1); +// data[0] = 0x0; //0xA6;//0xC6;//0xC6;//0x86; //0x48: ok for 200 prepare time +// mipi_dsih_dphy_write(phy, 0x61, data, 1); + +// data[0] = 0x0;//0x6a;//0x6a;//0x4a; //0x4a: ok for 200 zero time +// mipi_dsih_dphy_write(phy, 0x62, data, 1); + + data[0] = 0x83;//0x44;//0x40;//0x40; // 0x40: ok for 200 data lane lpx /*about 52ns*/ + mipi_dsih_dphy_write(phy, 0x70, data, 1); + +// data[0] = 0x0;// 0x84;//0x96;//0x96;//0x86; //0x48: ok for 200 prepare time +// mipi_dsih_dphy_write(phy, 0x71, data, 1); + +// data[0] = 0x0;//0x44;//0x44;//0x40; //0x4a: ok for 200 zero time +// mipi_dsih_dphy_write(phy, 0x72, data, 1); + + //data[0] = 0x44; + //mipi_dsih_dphy_write(phy, 0x73, data, 1); + + //data[0] = 0x7F; + //mipi_dsih_dphy_write(phy, 0x74, data, 1); + + /* Jessica add - end*/ + + data[0] = 0x70; + mipi_dsih_dphy_write(phy, 0x16, data, 1); + + /* setup digital part */ + /* hs frequency range [7]|[6:1]|[0]*/ + data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0; + //data[0] = (0 << 7) | (0x23 << 1) | 0; + /*From ASIC, we need unmask this code to make the frequency correct*/ + mipi_dsih_dphy_write(phy, 0x44, data, 1); //Jessica remove for more accurate frequency + /* setup PLL */ + /* vco range [7]|[6:3]|[2:1]|[0] */ + data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0; + mipi_dsih_dphy_write(phy, 0x10, data, 1); //Jessica +#ifdef TESTCHIP + /* for all Gen2 testchips, bypass LP TX enable idle low power */ + data[0] = 0x80; + mipi_dsih_dphy_write(phy, 0x32, data, 1); + mipi_dsih_dphy_write(phy, 0x42, data, 1); + mipi_dsih_dphy_write(phy, 0x52, data, 1); + mipi_dsih_dphy_write(phy, 0x82, data, 1); + mipi_dsih_dphy_write(phy, 0x92, data, 1); +#endif + if ((loop_divider % 2) != 0) + { /* only odd integers are allowed (1 will be subtracted upon writing, + see below) */ + loop_divider -= 1; + + } + /* gen 2 associates the charge pump current and LPF resistor with the + output frequency ranges (and thus we simplify here to use the + counter/pointer of the following structure) */ + i = range; + data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4); + + mipi_dsih_dphy_write(phy, 0x19, data, 1); //Jessica + + /* PLL Lock bypass|charge pump current [7:4]|[3:0] */ + data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0); + mipi_dsih_dphy_write(phy, 0x11, data, 1); //Jessica + /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */ + data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0); + mipi_dsih_dphy_write(phy, 0x12, data, 1); + /* PLL input divider ratio [7:0] */ + data[0] = input_divider - 1; + mipi_dsih_dphy_write(phy, 0x17, data, 1); //Jessica + +// data[0] = 1; +// mipi_dsih_dphy_write(phy, 0xB0, data, 1); + + data[0] = 0x04; //short the delay time before BTA + mipi_dsih_dphy_write(phy, 0x07, data, 1); + + data[0] = 0x8B; + mipi_dsih_dphy_write(phy, 0x22, data, 1); +// data[1] = mipi_dsih_dphy_test_data_out(phy); +// printk("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]); + + no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */ + for (i = 0; i < no_of_bytes; i++) + { + data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) )); + /* 7 is dependent on no_of_bytes + make sure 5 bits only of value are written at a time */ + } + /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */ + mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes); + mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes); +#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING + if (phy->phy_keep_work != true) +#endif + { + mipi_dsih_dphy_stop_wait_time(phy, 0x1C); + mipi_dsih_dphy_clock_en(phy, 1); + for(n=0;n<100;n++){ + ; + } + mipi_dsih_dphy_shutdown(phy, 1); + for(n=0;n<100;n++){ + ; + } + mipi_dsih_dphy_reset(phy, 1); + } + return OK; +} +#else +dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq) +{ + uint32_t loop_divider = 0; /* (M) */ + uint32_t input_divider = 1; /* (N) */ + uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/ + uint8_t no_of_bytes = 0; + uint8_t i = 0; /* iterator */ + uint8_t n=0;/* iterator */ + uint8_t range = 0; /* ranges iterator */ + int flag = 0; +#ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP + struct + { + uint32_t freq; /* upper margin of frequency range */ + uint8_t hs_freq; /* hsfreqrange */ + uint8_t vco_range; /* vcorange */ + } + ranges[] = + { + {90, 0x00, 0x01}, {100, 0x10, 0x01}, {110, 0x20, 0x01}, + {125, 0x01, 0x01}, {140, 0x11, 0x01}, {150, 0x21, 0x01}, + {160, 0x02, 0x01}, {180, 0x12, 0x03}, {200, 0x22, 0x03}, + {210, 0x03, 0x03}, {240, 0x13, 0x03}, {250, 0x23, 0x03}, + {270, 0x04, 0x07}, {300, 0x14, 0x07}, {330, 0x24, 0x07}, + {360, 0x15, 0x07}, {400, 0x25, 0x07}, {450, 0x06, 0x07}, + {500, 0x16, 0x07}, {550, 0x07, 0x0f}, {600, 0x17, 0x0f}, + {650, 0x08, 0x0f}, {700, 0x18, 0x0f}, {750, 0x09, 0x0f}, + {800, 0x19, 0x0f}, {850, 0x0A, 0x0f}, {900, 0x1A, 0x0f}, + {950, 0x2A, 0x0f}, {1000, 0x3A, 0x0f} + }; + struct + { + uint32_t loop_div; /* upper limit of loop divider range */ + uint8_t cp_current; /* icpctrl */ + uint8_t lpf_resistor; /* lpfctrl */ + } + loop_bandwidth[] = + { + {32, 0x06, 0x10}, {64, 0x06, 0x10}, {128, 0x0C, 0x08}, + {256, 0x04, 0x04}, {512, 0x00, 0x01}, {768, 0x01, 0x01}, + {1000, 0x02, 0x01} + }; +#elif defined DPHY2Btql + struct + { + uint32_t loop_div; /* upper limit of loop divider range */ + uint8_t cp_current; /* icpctrl */ + uint8_t lpf_resistor; /* lpfctrl */ + } + loop_bandwidth[] = + { + {32, 0x0B, 0x00}, {64, 0x0A, 0x00}, {128, 0x09, 0x01}, + {256, 0x08, 0x03}, {512, 0x08, 0x07}, {768, 0x08, 0x0F}, + {1000, 0x08, 0x1F} + }; +#endif + if (phy == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (phy->status < INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + if (output_freq < MIN_OUTPUT_FREQ) + { + return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; + } + /* find M and N dividers */ + for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++) + { /* here the >= DPHY_DIV_LOWER_LIMIT is a phy constraint, formula should be above 1 MHz */ + if (((output_freq * input_divider) % (phy->reference_freq )) == 0) + { /* values found */ + loop_divider = ((output_freq * input_divider) / (phy->reference_freq )); + if (loop_divider >= 12) + { + flag = 1; + } + } + } + if ((!flag) || ((phy->reference_freq / input_divider) < DPHY_DIV_LOWER_LIMIT)) + { /* no exact value found in previous for loop */ + /* this solution is not favourable as jitter would be maximum */ + loop_divider = output_freq / DPHY_DIV_LOWER_LIMIT; + input_divider = phy->reference_freq / DPHY_DIV_LOWER_LIMIT; + } + else + { /* variable was incremented before exiting the loop */ + input_divider--; + } + for (i = 0; (i < (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0]))) && (loop_divider > loop_bandwidth[i].loop_div); i++) + { + ; + } + if (i >= (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0]))) + { + return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; + } + printk("sprdfb: Gen1 D-PHY: Approximated Frequency: %d KHz\n", (loop_divider * (phy->reference_freq / input_divider))); +#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING + if (phy->phy_keep_work != true) +#endif + { + /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to + avoid transient periods in PHY operation during re-configuration procedures. */ + mipi_dsih_dphy_reset(phy, 0); + mipi_dsih_dphy_clock_en(phy, 0); + mipi_dsih_dphy_shutdown(phy, 0); + /* provide an initial active-high test clear pulse in TESTCLR */ + mipi_dsih_dphy_test_clear(phy, 1); + mipi_dsih_dphy_test_clear(phy, 0); + } +#ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP + /* find ranges */ + for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++) + { + ; + } + if (range >= (sizeof(ranges)/sizeof(ranges[0]))) + { + return ERR_DSI_PHY_FREQ_OUT_OF_BOUND; + } + /* set up board depending on environment if any */ + if (phy->bsp_pre_config != 0) + { + phy->bsp_pre_config(phy, 0); + } + + /* Jessica add - begin*/ + data[0] = 0x42;//0x44;//0x44;//0x40; //0x40: ok for 200 clock lane lpx /*about 52ns*/ + mipi_dsih_dphy_write(phy, 0x60, data, 1); + data[0] = 0x0; //0xA6;//0xC6;//0xC6;//0x86; //0x48: ok for 200 prepare time + mipi_dsih_dphy_write(phy, 0x61, data, 1); + + data[0] = 0x0;//0x6a;//0x6a;//0x4a; //0x4a: ok for 200 zero time + mipi_dsih_dphy_write(phy, 0x62, data, 1); + + data[0] = 0x42;//0x44;//0x40;//0x40; // 0x40: ok for 200 data lane lpx /*about 52ns*/ + mipi_dsih_dphy_write(phy, 0x70, data, 1); + + data[0] = 0x0;// 0x84;//0x96;//0x96;//0x86; //0x48: ok for 200 prepare time + mipi_dsih_dphy_write(phy, 0x71, data, 1); + + data[0] = 0x0;//0x44;//0x44;//0x40; //0x4a: ok for 200 zero time + mipi_dsih_dphy_write(phy, 0x72, data, 1); + + //data[0] = 0x44; + //mipi_dsih_dphy_write(phy, 0x73, data, 1); + + //data[0] = 0x7F; + //mipi_dsih_dphy_write(phy, 0x74, data, 1); + + /* Jessica add - end*/ + + /* setup digital part */ + /* hs frequency range [7]|[6:1]|[0]*/ + data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0; + //data[0] = (0 << 7) | (0x23 << 1) | 0; + /*From ASIC, we need unmask this code to make the frequency correct*/ + mipi_dsih_dphy_write(phy, 0x44, data, 1); //Jessica remove for more accurate frequency + /* setup PLL */ + /* vco range [7]|[6:3]|[2:1]|[0] */ + data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0; + mipi_dsih_dphy_write(phy, 0x10, data, 1); //Jessica + /* PLL reserved|Input divider control|Loop Divider Control|Post Divider Ratio [7:6]|[5]|[4]|[3:0] */ + data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4) | (0x03 << 0); /* post divider default = 0x03 - it is only used for clock out 2*/ + mipi_dsih_dphy_write(phy, 0x19, data, 1); //Jessica +#elif defined DPHY2Btql + /* vco range [7:5]|[4]|[3]|[2:1]|[0] */ + data[0] = ((((output_freq / 1000) > 500 )? 1: 0) << 4) | (1 << 3) | (0 << 1) | 0; + mipi_dsih_dphy_write(phy, 0x10, data, 1); +#endif + /* PLL Lock bypass|charge pump current [7:4]|[3:0] */ + data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0); + mipi_dsih_dphy_write(phy, 0x11, data, 1); //Jessica + /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */ + data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0); + mipi_dsih_dphy_write(phy, 0x12, data, 1); + /* PLL input divider ratio [7:0] */ + data[0] = input_divider - 1; + mipi_dsih_dphy_write(phy, 0x17, data, 1); //Jessica + + data[0] = 0x04; //short the delay time before BTA + mipi_dsih_dphy_write(phy, 0x07, data, 1); + +// data[0] = 1; +// mipi_dsih_dphy_write(phy, 0xB0, data, 1); + + data[0] = 0x8B; + mipi_dsih_dphy_write(phy, 0x22, data, 1); + // data[1] = mipi_dsih_dphy_test_data_out(phy); +// printk("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]); + + no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */ + for (i = 0; i < no_of_bytes; i++) + { + data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) )); + /* 7 is dependent on no_of_bytes + make sure 5 bits only of value are written at a time */ + } + /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */ + mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes); + mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes); +#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING + if (phy->phy_keep_work != true) +#endif + { + mipi_dsih_dphy_stop_wait_time(phy, 0x1C); + mipi_dsih_dphy_clock_en(phy, 1); + for(n=0;n<100;n++){ + ; + } + mipi_dsih_dphy_shutdown(phy, 1); + for(n=0;n<100;n++){ + ; + } + mipi_dsih_dphy_reset(phy, 1); + } + return OK; +} +#endif +/** + * Close and power down D-PHY module + * @param phy pointer to structure which holds information about the d-phy + * module + * @return error code + */ + +dsih_error_t mipi_dsih_dphy_close(dphy_t * phy) +{ + if (phy == 0) + { + return ERR_DSI_INVALID_INSTANCE; + } + else if ((phy->core_read_function == 0) || (phy->core_write_function == 0)) + { + return ERR_DSI_INVALID_IO; + } + if (phy->status < NOT_INITIALIZED) + { + return ERR_DSI_INVALID_INSTANCE; + } + mipi_dsih_dphy_reset(phy, 0); + mipi_dsih_dphy_reset(phy, 1); + mipi_dsih_dphy_shutdown(phy, 0); + phy->status = NOT_INITIALIZED; + return OK; +} +/** + * Enable clock lane module + * @param instance pointer to structure which holds information about the d-phy + * module + * @param en + */ +void mipi_dsih_dphy_clock_en(dphy_t * instance, int en) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_RSTZ, en, 2, 1); +} +/** + * Reset D-PHY module + * @param instance pointer to structure which holds information about the d-phy + * module + * @param reset + */ +void mipi_dsih_dphy_reset(dphy_t * instance, int reset) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_RSTZ, reset, 1, 1); +} +/** + * Power up/down D-PHY module + * @param instance pointer to structure which holds information about the d-phy + * module + * @param powerup (1) shutdown (0) + */ +void mipi_dsih_dphy_shutdown(dphy_t * instance, int powerup) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_RSTZ, powerup, 0, 1); +} +/** + * Configure minimum wait period for HS transmission request after a stop state + * @param instance pointer to structure which holds information about the d-phy + * module + * @param no_of_byte_cycles [in byte (lane) clock cycles] + */ +void mipi_dsih_dphy_stop_wait_time(dphy_t * instance, uint8_t no_of_byte_cycles) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CFG, no_of_byte_cycles, 2, 8); +} +/** + * Set number of active lanes + * @param instance pointer to structure which holds information about the d-phy + * module + * @param no_of_lanes + */ +void mipi_dsih_dphy_no_of_lanes(dphy_t * instance, uint8_t no_of_lanes) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CFG, no_of_lanes - 1, 0, 2); +} +/** + * Get number of currently active lanes + * @param instance pointer to structure which holds information about the d-phy + * module + * @return number of active lanes + */ +uint8_t mipi_dsih_dphy_get_no_of_lanes(dphy_t * instance) +{ + return mipi_dsih_dphy_read_part(instance, R_DSI_HOST_PHY_IF_CFG, 0, 2); +} +/** + * Request the PHY module to start transmission of high speed clock. + * This causes the clock lane to start transmitting DDR clock on the + * lane interconnect. + * @param instance pointer to structure which holds information about the d-phy + * module + * @param enable + * @note this function should be called explicitly by user always except for + * transmitting + */ +void mipi_dsih_dphy_enable_hs_clk(dphy_t * instance, int enable) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, enable, 0, 1); +} +/** + * One bit is asserted in the trigger_request (4bits) to cause the lane module + * to cause the associated trigger to be sent across the lane interconnect. + * The trigger request is synchronous with the rising edge of the clock. + * @note: Only one bit of the trigger_request is asserted at any given time, the + * remaining must be left set to 0, and only when not in LPDT or ULPS modes + * @param instance pointer to structure which holds information about the d-phy + * module + * @param trigger_request 4 bit request + */ +dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t * instance, uint8_t trigger_request) +{ + uint8_t sum = 0; + int i = 0; + for (i = 0; i < 4; i++) + { + sum += ((trigger_request >> i) & 1); + } + if (sum == 1) + { /* clear old trigger */ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0x00, 5, 4); + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, trigger_request, 5, 4); + for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++) + { + if(mipi_dsih_dphy_status(instance, 0x0010)) + { + break; + } + } + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0x00, 5, 4); + if (i >= DSIH_PHY_ACTIVE_WAIT) + { + return ERR_DSI_TIMEOUT; + } + return OK; + } + return ERR_DSI_INVALID_COMMAND; +} +/** + * ULPS mode request/exit on all active data lanes. + * @param instance pointer to structure which holds information about the d-phy + * module + * @param enable (request 1/ exit 0) + * @return error code + * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms + */ +#ifdef GEN_2 +dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable) +{ + int timeout; + /* mask 1 0101 0010 0000 */ + uint16_t data_lanes_mask = 0; + if (enable) + { + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 3, 1); + return OK; + } + else + { + if (mipi_dsih_dphy_status(instance, 0x1) == 0) + { + return ERR_DSI_PHY_PLL_NOT_LOCKED; + } + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 4, 1); + switch (mipi_dsih_dphy_get_no_of_lanes(instance)) + { + case 3: + data_lanes_mask |= (1 << 12); + case 2: + data_lanes_mask |= (1 << 10); + case 1: + data_lanes_mask |= (1 << 8); + case 0: + data_lanes_mask |= (1 << 5); + break; + default: + data_lanes_mask = 0; + break; + } + for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++) + { /* verify that the DPHY has left ULPM */ + /* mask 1010100100000 */ + if (mipi_dsih_dphy_status(instance, data_lanes_mask) == data_lanes_mask) + { + break; + } + /* wait at least 1ms */ + for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++) + { + ; + } + } + if (mipi_dsih_dphy_status(instance, data_lanes_mask) != data_lanes_mask) + { + instance->log_info("sprdfb: stat %x, mask %x", mipi_dsih_dphy_status(instance, data_lanes_mask), data_lanes_mask); + return ERR_DSI_TIMEOUT; + } + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 3, 1); + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 4, 1); + } + return OK; +} +#else +void mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable) +{ + int timeout; + if (enable) + { + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 3, 1); + } + else + { + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 4, 1); + for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++) + { /* verify that the DPHY has left ULPM */ + /* mask 1010100100000 */ + if (mipi_dsih_dphy_status(instance, 0x1520) == 0) + { /* wait at least 1ms */ + for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++) + { + ; + } + break; + } + } + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 3, 1); + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 4, 1); + } +} +#endif +/** + * ULPS mode request/exit on Clock Lane. + * @param instance pointer to structure which holds information about the + * d-phy module + * @param enable 1 or disable 0 of the Ultra Low Power State of the clock lane + * @return error code + * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms + */ +#ifdef GEN_2 +dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable) +{ + int timeout; + /* mask 1000 */ + uint16_t clk_lane_mask = 0x0008; + if (enable) + { +// mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 0, 1); + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 1, 1); + } + else + { + if (mipi_dsih_dphy_status(instance, 0x1) == 0) + { + return ERR_DSI_PHY_PLL_NOT_LOCKED; + } + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 2, 1); + for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++) + { /* verify that the DPHY has left ULPM */ + /* mask 1010100100000 */ + if (mipi_dsih_dphy_status(instance, clk_lane_mask) == clk_lane_mask) + { /* wait at least 1ms */ + instance->log_info("sprdfb: stat %x, mask %x", mipi_dsih_dphy_status(instance, clk_lane_mask), clk_lane_mask); + break; + } + /* wait at least 1ms */ + for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++) + { + enable = mipi_dsih_dphy_status(instance, clk_lane_mask); + } + } + if (mipi_dsih_dphy_status(instance, clk_lane_mask) != clk_lane_mask) + { + return ERR_DSI_TIMEOUT; + } + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 1, 1); + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 2, 1); + } + return OK; +} +#else +void mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable) +{ + int timeout; + if (enable) + { + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 0, 1); + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 1, 1); + } + else + { + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 2, 1); + for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++) + { /* verify that the DPHY has left ULPM */ + /* mask 1010100100000 */ + if (mipi_dsih_dphy_status(instance, 0x0004) == 0) + { /* wait at least 1ms */ + for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++) + { + ; + } + break; + } + } + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 1, 1); + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 2, 1); + } +} +#endif +/** + * Get D-PHY PPI status + * @param instance pointer to structure which holds information about the d-phy + * module + * @param mask + * @return status + */ +uint32_t mipi_dsih_dphy_status(dphy_t * instance, uint16_t mask) +{ + return mipi_dsih_dphy_read_word(instance, R_DSI_HOST_PHY_STATUS) & mask; +} +/** + * @param instance pointer to structure which holds information about the d-phy + * module + * @param value + */ +void mipi_dsih_dphy_test_clock(dphy_t * instance, int value) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_TST_CRTL0, value, 1, 1); +} +/** + * @param instance pointer to structure which holds information about the d-phy + * module + * @param value + */ +void mipi_dsih_dphy_test_clear(dphy_t * instance, int value) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_TST_CRTL0, value, 0, 1); +} +/** + * @param instance pointer to structure which holds information about the d-phy + * module + * @param on_falling_edge + */ +void mipi_dsih_dphy_test_en(dphy_t * instance, uint8_t on_falling_edge) +{ + mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_TST_CRTL1, on_falling_edge, 16, 1); +} +/** + * @param instance pointer to structure which holds information about the d-phy + * module + */ +uint8_t mipi_dsih_dphy_test_data_out(dphy_t * instance) +{ + return mipi_dsih_dphy_read_part(instance, R_DSI_HOST_PHY_TST_CRTL1, 8, 8); +} +/** + * @param instance pointer to structure which holds information about the d-phy + * module + * @param test_data + */ +void mipi_dsih_dphy_test_data_in(dphy_t * instance, uint8_t test_data) +{ + mipi_dsih_dphy_write_word(instance, R_DSI_HOST_PHY_TST_CRTL1, test_data); +} +/** + * Write to D-PHY module (encapsulating the digital interface) + * @param instance pointer to structure which holds information about the d-phy + * module + * @param address offset inside the D-PHY digital interface + * @param data array of bytes to be written to D-PHY + * @param data_length of the data array + */ +void mipi_dsih_dphy_write(dphy_t * instance, uint8_t address, uint8_t * data, uint8_t data_length) +{ + unsigned i = 0; + if (data != 0) + { +#if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined DPHY2Btql) || (defined GEN_2)) + /* set the TESTCLK input high in preparation to latch in the desired test mode */ + mipi_dsih_dphy_test_clock(instance, 1); + /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */ + mipi_dsih_dphy_test_data_in(instance, address); + /* set TESTEN input high */ + mipi_dsih_dphy_test_en(instance, 1); + /* drive the TESTCLK input low; the falling edge captures the chosen test code into the transceiver */ + mipi_dsih_dphy_test_clock(instance, 0); + /* set TESTEN input low to disable further test mode code latching */ + mipi_dsih_dphy_test_en(instance, 0); + /* start writing MSB first */ + for (i = data_length; i > 0; i--) + { /* set TESTDIN[7:0] to the desired test data appropriate to the chosen test mode */ + mipi_dsih_dphy_test_data_in(instance, data[i - 1]); + /* pulse TESTCLK high to capture this test data into the macrocell; repeat these two steps as necessary */ + mipi_dsih_dphy_test_clock(instance, 1); + mipi_dsih_dphy_test_clock(instance, 0); + } +#endif + } +} + + + +/* abstracting BSP */ +/** + * Write to whole register to D-PHY module (encapsulating the bus interface) + * @param instance pointer to structure which holds information about the d-phy + * module + * @param reg_address offset + * @param data 32-bit word + */ +void mipi_dsih_dphy_write_word(dphy_t * instance, uint32_t reg_address, uint32_t data) +{ + if (instance->core_write_function != 0) + { + instance->core_write_function(instance->address, reg_address, data); + } +} +/** + * Write bit field to D-PHY module (encapsulating the bus interface) + * @param instance pointer to structure which holds information about the d-phy + * module + * @param reg_address offset + * @param data bits to be written to D-PHY + * @param shift from the right hand side of the register (big endian) + * @param width of the bit field + */ +void mipi_dsih_dphy_write_part(dphy_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width) +{ + uint32_t mask = 0; + uint32_t temp = 0; + if (instance->core_read_function != 0) + { + mask = (1 << width) - 1; + temp = mipi_dsih_dphy_read_word(instance, reg_address); + temp &= ~(mask << shift); + temp |= (data & mask) << shift; + mipi_dsih_dphy_write_word(instance, reg_address, temp); + } +} +/** + * Read whole register from D-PHY module (encapsulating the bus interface) + * @param instance pointer to structure which holds information about the d-phy + * module + * @param reg_address offset + * @return data 32-bit word + */ +uint32_t mipi_dsih_dphy_read_word(dphy_t * instance, uint32_t reg_address) +{ + if (instance->core_read_function == 0) + { + return ERR_DSI_INVALID_IO; + } + return instance->core_read_function(instance->address, reg_address); +} +/** + * Read bit field from D-PHY module (encapsulating the bus interface) + * @param instance pointer to structure which holds information about the d-phy + * module + * @param reg_address offset + * @param shift from the right hand side of the register (big endian) + * @param width of the bit field + * @return data bits to be written to D-PHY + */ +uint32_t mipi_dsih_dphy_read_part(dphy_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width) +{ + return (mipi_dsih_dphy_read_word(instance, reg_address) >> shift) & ((1 << width) - 1); +} + diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h new file mode 100644 index 00000000..4d457db2 --- /dev/null +++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_dphy.h @@ -0,0 +1,55 @@ +/* + * @file mipi_dsih_dphy.h + * + * Synopsys Inc. + * SG DWC PT02 + */ + +#ifndef MIPI_DSIH_DPHY_H_ +#define MIPI_DSIH_DPHY_H_ + +#include "mipi_dsih_local.h" + +#define R_DSI_HOST_PHY_RSTZ 0x54UL +#define R_DSI_HOST_PHY_IF_CFG 0x58UL +#define R_DSI_HOST_PHY_IF_CTRL 0x5CUL +#define R_DSI_HOST_PHY_STATUS 0x60UL +#define R_DSI_HOST_PHY_TST_CRTL0 0x64UL +#define R_DSI_HOST_PHY_TST_CRTL1 0x68UL + +/* obligatory functions - code can be changed for different phys*/ +dsih_error_t mipi_dsih_dphy_open(dphy_t * phy); +dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq); +dsih_error_t mipi_dsih_dphy_close(dphy_t * phy); + +void mipi_dsih_dphy_clock_en(dphy_t * instance, int en); +void mipi_dsih_dphy_reset(dphy_t * instance, int reset); +void mipi_dsih_dphy_shutdown(dphy_t * instance, int powerup); + +void mipi_dsih_dphy_stop_wait_time(dphy_t * instance, uint8_t no_of_byte_cycles); +void mipi_dsih_dphy_no_of_lanes(dphy_t * instance, uint8_t no_of_lanes); +uint8_t mipi_dsih_dphy_get_no_of_lanes(dphy_t * instance); +void mipi_dsih_dphy_enable_hs_clk(dphy_t * instance, int enable); +dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t * instance, uint8_t trigger_request); +#ifdef GEN_2 +dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable); +dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable); +#else +void mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable); +void mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable); +#endif +uint32_t mipi_dsih_dphy_status(dphy_t * instance, uint16_t mask); +/* end of obligatory functions*/ +void mipi_dsih_dphy_test_clock(dphy_t * instance, int value); +void mipi_dsih_dphy_test_clear(dphy_t * instance, int value); +void mipi_dsih_dphy_test_en(dphy_t * instance, uint8_t on_falling_edge); +uint8_t mipi_dsih_dphy_test_data_out(dphy_t * instance); +void mipi_dsih_dphy_test_data_in(dphy_t * instance, uint8_t test_data); + +void mipi_dsih_dphy_write(dphy_t * instance, uint8_t address, uint8_t * data, uint8_t data_length); + +void mipi_dsih_dphy_write_word(dphy_t * instance, uint32_t reg_address, uint32_t data); +void mipi_dsih_dphy_write_part(dphy_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width); +uint32_t mipi_dsih_dphy_read_word(dphy_t * instance, uint32_t reg_address); +uint32_t mipi_dsih_dphy_read_part(dphy_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width); +#endif /* MIPI_DSIH_DPHY_H_ */ diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c new file mode 100644 index 00000000..cf87836d --- /dev/null +++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.c @@ -0,0 +1,529 @@ + +#include "mipi_dsih_hal.h" + +void mipi_dsih_write_word(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data) +{ + + instance->core_write_function(instance->address, reg_address, data); +} +void mipi_dsih_write_part(dsih_ctrl_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width) +{ + uint32_t mask = (1 << width) - 1; + uint32_t temp = mipi_dsih_read_word(instance, reg_address); + + temp &= ~(mask << shift); + temp |= (data & mask) << shift; + mipi_dsih_write_word(instance, reg_address, temp); +} +uint32_t mipi_dsih_read_word(dsih_ctrl_t * instance, uint32_t reg_address) +{ + return instance->core_read_function(instance->address, reg_address); +} +uint32_t mipi_dsih_read_part(dsih_ctrl_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width) +{ + return (mipi_dsih_read_word(instance, reg_address) >> shift) & ((1 << width) - 1); +} +uint32_t mipi_dsih_hal_get_version(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_word(instance, R_DSI_HOST_VERSION); +} +void mipi_dsih_hal_power(dsih_ctrl_t * instance, int on) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_PWR_UP, on, 0, 1); +} +int mipi_dsih_hal_get_power(dsih_ctrl_t * instance) +{ + return (int)(mipi_dsih_read_word(instance, R_DSI_HOST_PWR_UP)); +} +void mipi_dsih_hal_tx_escape_division(dsih_ctrl_t * instance, uint8_t tx_escape_division) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_CLK_MGR, tx_escape_division, 0, 8); +} +void mipi_dsih_hal_dpi_video_vc(dsih_ctrl_t * instance, uint8_t vc) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, (uint32_t)(vc), 0, 2); +} +uint8_t mipi_dsih_hal_dpi_get_video_vc(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_DPI_CFG, 0, 2); +} +dsih_error_t mipi_dsih_hal_dpi_color_coding(dsih_ctrl_t * instance, dsih_color_coding_t color_coding) +{ + dsih_error_t err = OK; + if (color_coding > 7) + { + if (instance->log_error != 0) + { + instance->log_error("sprdfb: invalid colour configuration"); + } + err = ERR_DSI_COLOR_CODING; + } + else + { + mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, color_coding, 2, 3); + } + return err; +} +dsih_color_coding_t mipi_dsih_hal_dpi_get_color_coding(dsih_ctrl_t * instance) +{ + return (dsih_color_coding_t)(mipi_dsih_read_part(instance, R_DSI_HOST_DPI_CFG, 2, 3)); +} +uint8_t mipi_dsih_hal_dpi_get_color_depth(dsih_ctrl_t * instance) +{ + uint8_t color_depth = 0; + switch (mipi_dsih_read_part(instance, R_DSI_HOST_DPI_CFG, 2, 3)) + { + case 0: + case 1: + case 2: + color_depth = 16; + break; + case 3: + case 4: + color_depth = 18; + break; + default: + color_depth = 24; + break; + } + return color_depth; +} +uint8_t mipi_dsih_hal_dpi_get_color_config(dsih_ctrl_t * instance) +{ + uint8_t color_config = 0; + switch (mipi_dsih_read_part(instance, R_DSI_HOST_DPI_CFG, 2, 3)) + { + case 0: + color_config = 1; + break; + case 1: + color_config = 2; + break; + case 2: + color_config = 3; + break; + case 3: + color_config = 1; + break; + case 4: + color_config = 2; + break; + default: + color_config = 0; + break; + } + return color_config; +} +void mipi_dsih_hal_dpi_18_loosely_packet_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, enable, 10, 1); +} +void mipi_dsih_hal_dpi_color_mode_pol(dsih_ctrl_t * instance, int active_low) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 9, 1); +} +void mipi_dsih_hal_dpi_shut_down_pol(dsih_ctrl_t * instance, int active_low) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 8, 1); +} +void mipi_dsih_hal_dpi_hsync_pol(dsih_ctrl_t * instance, int active_low) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 7, 1); +} +void mipi_dsih_hal_dpi_vsync_pol(dsih_ctrl_t * instance, int active_low) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 6, 1); +} +void mipi_dsih_hal_dpi_dataen_pol(dsih_ctrl_t * instance, int active_low) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_DPI_CFG, active_low, 5, 1); +} +void mipi_dsih_hal_dpi_frame_ack_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 11, 1); +} +void mipi_dsih_hal_dpi_null_packet_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 10, 1); +} +void mipi_dsih_hal_dpi_multi_packet_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 9, 1); +} +void mipi_dsih_hal_dpi_lp_during_hfp(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 8, 1); +} +void mipi_dsih_hal_dpi_lp_during_hbp(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 7, 1); +} +void mipi_dsih_hal_dpi_lp_during_vactive(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 6, 1); +} +void mipi_dsih_hal_dpi_lp_during_vfp(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 5, 1); +} +void mipi_dsih_hal_dpi_lp_during_vbp(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 4, 1); +} +void mipi_dsih_hal_dpi_lp_during_vsync(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 3, 1); +} +dsih_error_t mipi_dsih_hal_dpi_video_mode_type(dsih_ctrl_t * instance, dsih_video_mode_t type) +{ + if (type < 3) + { + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, type, 1, 2); + return OK; + } + else + { + if (instance->log_error != 0) + { + instance->log_error("sprdfb: undefined type"); + } + return ERR_DSI_OUT_OF_BOUND; + } +} +void mipi_dsih_hal_dpi_video_mode_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VID_MODE_CFG, enable, 0, 1); +} +int mipi_dsih_hal_dpi_is_video_mode(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_VID_MODE_CFG, 0, 1); +} +dsih_error_t mipi_dsih_hal_dpi_null_packet_size(dsih_ctrl_t * instance, uint16_t size) +{ + if (size < 0x3ff) /* 10-bit field */ + { + mipi_dsih_write_part(instance, R_DSI_HOST_VID_PKT_CFG, size, 21, 10); + return OK; + } + else + { + return ERR_DSI_OUT_OF_BOUND; + } +} +dsih_error_t mipi_dsih_hal_dpi_chunks_no(dsih_ctrl_t * instance, uint16_t no) +{ + if (no < 0x3ff) + { + mipi_dsih_write_part(instance, R_DSI_HOST_VID_PKT_CFG, no, 11, 10); + return OK; + } + else + { + return ERR_DSI_OUT_OF_BOUND; + } +} +dsih_error_t mipi_dsih_hal_dpi_video_packet_size(dsih_ctrl_t * instance, uint16_t size) +{ + if (size < 0x7ff) /* 11-bit field */ + { + mipi_dsih_write_part(instance, R_DSI_HOST_VID_PKT_CFG, size, 0, 11); + return OK; + } + else + { + return ERR_DSI_OUT_OF_BOUND; + } +} +void mipi_dsih_hal_tear_effect_ack_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, enable, 14, 1); +} +void mipi_dsih_hal_cmd_ack_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, enable, 13, 1); +} +dsih_error_t mipi_dsih_hal_dcs_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp) +{ + switch (no_of_param) + { + case 0: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 7, 1); + break; + case 1: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 8, 1); + break; + default: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 12, 1); + break; + } + return OK; +} +dsih_error_t mipi_dsih_hal_dcs_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp) +{ + dsih_error_t err = OK; + switch (no_of_param) + { + case 0: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 9, 1); + break; + default: + if (instance->log_error != 0) + { + instance->log_error("sprdfb: undefined DCS Read packet type"); + } + err = ERR_DSI_OUT_OF_BOUND; + break; + } + return err; +} + +/*Jessica add begin: to support max read packet size command */ +dsih_error_t mipi_dsih_hal_max_rd_packet_size_type(dsih_ctrl_t * instance, int lp) +{ + dsih_error_t err = OK; + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 10, 1); + return err; +} +/*Jessica add end*/ + +dsih_error_t mipi_dsih_hal_gen_wr_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp) +{ + switch (no_of_param) + { + case 0: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 1, 1); + break; + case 1: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 2, 1); + break; + case 2: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 3, 1); + break; + default: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 11, 1); + break; + } + return OK; +} +dsih_error_t mipi_dsih_hal_gen_rd_tx_type(dsih_ctrl_t * instance, unsigned no_of_param, int lp) +{ + dsih_error_t err = OK; + switch (no_of_param) + { + case 0: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 4, 1); + break; + case 1: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 5, 1); + break; + case 2: + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 6, 1); + break; + default: + if (instance->log_error != 0) + { + instance->log_error("sprdfb: undefined Generic Read packet type"); + } + err = ERR_DSI_OUT_OF_BOUND; + break; + } + return err; +} +void mipi_dsih_hal_max_rd_size_tx_type(dsih_ctrl_t * instance, int lp) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, lp, 10, 1); +} +void mipi_dsih_hal_gen_cmd_mode_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_CMD_MODE_CFG, enable, 0, 1); +} +int mipi_dsih_hal_gen_is_cmd_mode(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_MODE_CFG, 0, 1); +} +void mipi_dsih_hal_dpi_hline(dsih_ctrl_t * instance, uint16_t time) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_TMR_LINE_CFG, time, 18, 14); +} +void mipi_dsih_hal_dpi_hbp(dsih_ctrl_t * instance, uint16_t time) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_TMR_LINE_CFG, time, 9, 9); +} +void mipi_dsih_hal_dpi_hsa(dsih_ctrl_t * instance, uint16_t time) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_TMR_LINE_CFG, time, 0, 9); +} +void mipi_dsih_hal_dpi_vactive(dsih_ctrl_t * instance, uint16_t lines) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VTIMING_CFG, lines, 16, 11); +} +void mipi_dsih_hal_dpi_vfp(dsih_ctrl_t * instance, uint16_t lines) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VTIMING_CFG, lines, 10, 6); +} +void mipi_dsih_hal_dpi_vbp(dsih_ctrl_t * instance, uint16_t lines) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VTIMING_CFG, lines, 4, 6); +} +void mipi_dsih_hal_dpi_vsync(dsih_ctrl_t * instance, uint16_t lines) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_VTIMING_CFG, lines, 0, 4); +} +void mipi_dsih_hal_timeout_clock_division(dsih_ctrl_t * instance, uint8_t byte_clk_division_factor) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_CLK_MGR, byte_clk_division_factor, 8, 8); +} +void mipi_dsih_hal_lp_rx_timeout(dsih_ctrl_t * instance, uint16_t count) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_TO_CNT_CFG, count, 16, 16); +} +void mipi_dsih_hal_hs_tx_timeout(dsih_ctrl_t * instance, uint16_t count) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_TO_CNT_CFG, count, 0, 16); +} +uint32_t mipi_dsih_hal_error_status_0(dsih_ctrl_t * instance, uint32_t mask) +{ + return (mipi_dsih_read_word(instance, R_DSI_HOST_ERROR_ST0) & mask); +} +uint32_t mipi_dsih_hal_error_status_1(dsih_ctrl_t * instance, uint32_t mask) +{ + return (mipi_dsih_read_word(instance, R_DSI_HOST_ERROR_ST1) & mask); +} +void mipi_dsih_hal_error_mask_0(dsih_ctrl_t * instance, uint32_t mask) +{ + mipi_dsih_write_word(instance, R_DSI_HOST_ERROR_MSK0, mask); +} +uint32_t mipi_dsih_hal_get_error_mask_0(dsih_ctrl_t * instance, uint32_t mask) +{ + return (mipi_dsih_read_word(instance, R_DSI_HOST_ERROR_MSK0) & mask); +} +void mipi_dsih_hal_error_mask_1(dsih_ctrl_t * instance, uint32_t mask) +{ + mipi_dsih_write_word(instance, R_DSI_HOST_ERROR_MSK1, mask); +} +uint32_t mipi_dsih_hal_get_error_mask_1(dsih_ctrl_t * instance, uint32_t mask) +{ + return (mipi_dsih_read_word(instance, R_DSI_HOST_ERROR_MSK1) & mask); +} +/* DBI NOT IMPLEMENTED */ +void mipi_dsih_hal_dbi_out_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option); +void mipi_dsih_hal_dbi_in_color_coding(dsih_ctrl_t * instance, uint8_t color_depth, uint8_t option); +void mipi_dsih_hal_dbi_lut_size(dsih_ctrl_t * instance, uint8_t size); +void mipi_dsih_hal_dbi_partitioning_en(dsih_ctrl_t * instance, int enable); +void mipi_dsih_hal_dbi_dcs_vc(dsih_ctrl_t * instance, uint8_t vc); +void mipi_dsih_hal_dbi_max_cmd_size(dsih_ctrl_t * instance, uint16_t size); +void mipi_dsih_hal_dbi_cmd_size(dsih_ctrl_t * instance, uint16_t size); +void mipi_dsih_hal_dbi_max_cmd_size(dsih_ctrl_t * instance, uint16_t size); +int mipi_dsih_hal_dbi_rd_cmd_busy(dsih_ctrl_t * instance); +int mipi_dsih_hal_dbi_read_fifo_full(dsih_ctrl_t * instance); +int mipi_dsih_hal_dbi_read_fifo_empty(dsih_ctrl_t * instance); +int mipi_dsih_hal_dbi_write_fifo_full(dsih_ctrl_t * instance); +int mipi_dsih_hal_dbi_write_fifo_empty(dsih_ctrl_t * instance); +int mipi_dsih_hal_dbi_cmd_fifo_full(dsih_ctrl_t * instance); +int mipi_dsih_hal_dbi_cmd_fifo_empty(dsih_ctrl_t * instance); + +dsih_error_t mipi_dsih_hal_gen_packet_header(dsih_ctrl_t * instance, uint8_t vc, uint8_t packet_type, uint8_t ms_byte, uint8_t ls_byte) +{ + if (vc < 4) + { + mipi_dsih_write_part(instance, R_DSI_HOST_GEN_HDR, (ms_byte << 16) | (ls_byte << 8 ) | ((vc << 6) | packet_type), 0, 24); + return OK; + } + return ERR_DSI_OVERFLOW; +} +dsih_error_t mipi_dsih_hal_gen_packet_payload(dsih_ctrl_t * instance, uint32_t payload) +{ + if (mipi_dsih_hal_gen_write_fifo_full(instance)) + { + return ERR_DSI_OVERFLOW; + } + mipi_dsih_write_word(instance, R_DSI_HOST_GEN_PLD_DATA, payload); + return OK; + +} +dsih_error_t mipi_dsih_hal_gen_read_payload(dsih_ctrl_t * instance, uint32_t* payload) +{ + *payload = mipi_dsih_read_word(instance, R_DSI_HOST_GEN_PLD_DATA); + return OK; +} + +void mipi_dsih_hal_gen_rd_vc(dsih_ctrl_t * instance, uint8_t vc) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, vc, 5, 2); +} +void mipi_dsih_hal_gen_eotp_rx_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 1, 1); +} +void mipi_dsih_hal_gen_eotp_tx_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 0, 1); +} +void mipi_dsih_hal_bta_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 2, 1); +} +void mipi_dsih_hal_gen_ecc_rx_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 3, 1); +} +void mipi_dsih_hal_gen_crc_rx_en(dsih_ctrl_t * instance, int enable) +{ + mipi_dsih_write_part(instance, R_DSI_HOST_PCKHDL_CFG, enable, 4, 1); +} +int mipi_dsih_hal_gen_rd_cmd_busy(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 6, 1); +} +int mipi_dsih_hal_gen_read_fifo_full(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 5, 1); +} +int mipi_dsih_hal_gen_read_fifo_empty(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 4, 1); +} +int mipi_dsih_hal_gen_write_fifo_full(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 3, 1); +} +int mipi_dsih_hal_gen_write_fifo_empty(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 2, 1); +} +int mipi_dsih_hal_gen_cmd_fifo_full(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 1, 1); +} +int mipi_dsih_hal_gen_cmd_fifo_empty(dsih_ctrl_t * instance) +{ + return mipi_dsih_read_part(instance, R_DSI_HOST_CMD_PKT_STATUS, 0, 1); +} +/* only if DPI */ +dsih_error_t mipi_dsih_phy_hs2lp_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles) +{ + //mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 20, 8); + mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 24, 8); + return OK; +} +dsih_error_t mipi_dsih_phy_lp2hs_config(dsih_ctrl_t * instance, uint8_t no_of_byte_cycles) +{ + //mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 12, 8); + mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 16, 8); + return OK; +} +dsih_error_t mipi_dsih_phy_bta_time(dsih_ctrl_t * instance, uint16_t no_of_byte_cycles) +{ + /*Jessica modified: From ASIC, the second table in spec is correct, this 15 bits are max rd time*/ + if (no_of_byte_cycles < 0x8000) /* 15-bit field */ + { + //mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 0, 12); + mipi_dsih_write_part(instance, R_DSI_HOST_PHY_TMR_CFG, no_of_byte_cycles, 0, 15); + } + else + { + return ERR_DSI_OVERFLOW; + } + return OK; +} +/* */ \ No newline at end of file diff --git a/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h new file mode 100644 index 00000000..4524f9f7 --- /dev/null +++ b/drivers/video/sprdfb/dsi_1_10a/mipi_dsih_hal.h @@ -0,0 +1,242 @@ +/* + * @file mipi_dsih_hal.h + * + * Synopsys Inc. + * SG DWC PT02 + */ +/* + The Synopsys Software Driver and documentation (hereinafter "Software") + is an unsupported work of Synopsys, Inc. unless otherwise + expressly agreed to in writing between Synopsys and you. + + The Software IS NOT an item of Licensed Software or Licensed Product under + any End User Software License Agreement or Agreement for Licensed Product + with Synopsys or any supplement thereto. Permission is hereby granted, + free of charge, to any person obtaining a copy of this software annotated + with this license and the Software, to deal in the Software without + restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, subject + to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + */ + +#ifndef MIPI_DSIH_HAL_H_ +#define MIPI_DSIH_HAL_H_ + +#include "mipi_dsih_local.h" + +#define R_DSI_HOST_VERSION 0x00UL +#define R_DSI_HOST_PWR_UP 0x04UL +#define R_DSI_HOST_CLK_MGR 0x08UL +#define R_DSI_HOST_DPI_CFG 0x0CUL +#define R_DSI_HOST_DBI_CFG 0x10UL +#define R_DSI_HOST_DBI_CMDSIZE 0x14UL +#define R_DSI_HOST_PCKHDL_CFG 0x18UL +#define R_DSI_HOST_VID_MODE_CFG 0x1CUL +#define R_DSI_HOST_VID_PKT_CFG 0x20UL +#define R_DSI_HOST_CMD_MODE_CFG 0x24UL +#define R_DSI_HOST_TMR_LINE_CFG 0x28UL +#define R_DSI_HOST_VTIMING_CFG 0x2CUL +#define R_DSI_HOST_PHY_TMR_CFG 0x30UL +#define R_DSI_HOST_GEN_HDR 0x34UL +#define R_DSI_HOST_GEN_PLD_DATA 0x38UL +#define R_DSI_HOST_CMD_PKT_STATUS 0x3CUL +#define R_DSI_HOST_TO_CNT_CFG 0x40UL +#define R_DSI_HOST_ERROR_ST0 0x44UL +#define R_DSI_HOST_ERROR_ST1 0x48UL +#define R_DSI_HOST_ERROR_MSK0 0x4CUL +#define R_DSI_HOST_ERROR_MSK1 0x50UL + +#ifdef CONFIG_OF +extern uint32_t g_dsi_base_addr; +#endif + +typedef enum _Dsi_Int0_Type_ { + ack_with_err_0, + ack_with_err_1, + ack_with_err_2, + ack_with_err_3, + ack_with_err_4, + ack_with_err_5, + ack_with_err_6, + ack_with_err_7, + ack_with_err_8, + ack_with_err_9, + ack_with_err_10, + ack_with_err_11, + ack_with_err_12, + ack_with_err_13, + ack_with_err_14, + ack_with_err_15, + dphy_errors_0, + dphy_errors_1, + dphy_errors_2, + dphy_errors_3, + dphy_errors_4, + DSI_INT0_MAX, +}Dsi_Int0_Type; + +typedef enum _Dsi_Int1_Type_ { + to_hs_tx, + to_lp_rx, + ecc_single_err, + ecc_multi_err, + crc_err, + pkt_size_err, + eopt_err, + dpi_pld_wr_err, + gen_cmd_wr_err, + gen_pld_wr_err, + gen_pld_send_err, + gen_pld_rd_err, + gen_pld_recv_err, + dbi_cmd_wr_err, + dbi_pld_wr_err, + dbi_pld_rd_err, + dbi_pld_recv_err, + dbi_illegal_comm_err, + DSI_INT1_MAX, +}Dsi_Int1_Type; +#define DSI_INT_MASK0_SET(bit,val)\ +{\ + uint32_t reg_val = dsi_core_read_function(SPRD_MIPI_DSIC_BASE, R_DSI_HOST_ERROR_MSK0);\ + reg_val = (val == 1)?(reg_val | (1UL< +#include +#include "../sprdfb_chip_common.h" + + +//typedef unsigned char uint8_t; +//typedef unsigned short uint16_t; +//typedef unsigned int uint32_t; + +#define DSIH_PIXEL_TOLERANCE 2 +#define DSIH_FIFO_ACTIVE_WAIT 5000 /* no of tries to access the fifo*/ +#define DSIH_PHY_ACTIVE_WAIT 200 +#define ONE_MS_ACTIVE_WAIT 50000 /* 50MHz processor */ +#define DEFAULT_BYTE_CLOCK 864000 /* a value to start PHY PLL - random */ + +/** Define D-PHY type */ + +#ifdef SPRD_MIPI_DPHY_GEN1 +/** DWC_MIPI_DPHY_BIDIR_TSMC40LP 4 Lanes Gen 1 1GHz */ +#define DWC_MIPI_DPHY_BIDIR_TSMC40LP +#endif +#ifdef SPRD_MIPI_DPHY_GEN2 +/** DWC_MIPI_DPHY_BIDIR_TSMC40LP / GF28LP 4 Lanes Gen 2 1.5GHz */ +#define GEN_2 +#endif +/** 4 Lanes Gen 2 1.5GHz testchips */ +//#define TESTCHIP +/** TQL 2 Lane test chip */ +/* #define DPHY2Btql */ +typedef enum +{ + OK = 0, + ERR_DSI_COLOR_CODING, + ERR_DSI_OUT_OF_BOUND, + ERR_DSI_OVERFLOW, + ERR_DSI_INVALID_INSTANCE, + ERR_DSI_INVALID_IO, + ERR_DSI_CORE_INCOMPATIBLE, + ERR_DSI_VIDEO_MODE, + ERR_DSI_INVALID_COMMAND, + ERR_DSI_INVALID_EVENT, + ERR_DSI_INVALID_HANDLE, + ERR_DSI_PHY_POWERUP, + ERR_DSI_PHY_INVALID, + ERR_DSI_PHY_FREQ_OUT_OF_BOUND, +#ifdef GEN_2 + ERR_DSI_PHY_PLL_NOT_LOCKED, +#endif + ERR_DSI_TIMEOUT +} +dsih_error_t; +typedef enum +{ + VIDEO_NON_BURST_WITH_SYNC_PULSES = 0, + VIDEO_NON_BURST_WITH_SYNC_EVENTS, + VIDEO_BURST_WITH_SYNC_PULSES +} +dsih_video_mode_t; +typedef enum +{ + COLOR_CODE_16BIT_CONFIG1, + COLOR_CODE_16BIT_CONFIG2, + COLOR_CODE_16BIT_CONFIG3, + COLOR_CODE_18BIT_CONFIG1, + COLOR_CODE_18BIT_CONFIG2, + COLOR_CODE_24BIT +} +dsih_color_coding_t; +typedef enum +{ + ACK_SOT_ERR = 0, + ACK_SOT_SYNC, + ACK_EOT_SYNC, + ACK_ESCAPE_CMD_ERR, + ACK_LP_TX_SYNC_ERR, + ACK_HS_RX_TIMEOUT_ERR, + ACK_FALSE_CONTROL_ERR, + ACK_RSVD_DEVICE_ERR_7, + ACK_ECC_SINGLE_BIT_ERR, + ACK_ECC_MULTI_BIT_ERR, + ACK_CHECKSUM_ERR, + ACK_DSI_TYPE_NOT_RECOGNIZED_ERR, + ACK_VC_ID_INVALID_ERR, + ACK_INVALID_TX_LENGTH_ERR, + ACK_RSVD_DEVICE_ERR_14, + ACK_DSI_PROTOCOL_ERR, + + DPHY_ESC_ENTRY_ERR, + DPHY_SYNC_ESC_LP_ERR, + DPHY_CONTROL_LANE0_ERR, + DPHY_CONTENTION_LP0_ERR, + DPHY_CONTENTION_LP1_ERR, + /* start of st1*/ + HS_CONTENTION, + LP_CONTENTION, + RX_ECC_SINGLE_ERR, + RX_ECC_MULTI_ERR, + RX_CRC_ERR, + RX_PKT_SIZE_ERR, + RX_EOTP_ERR, + DPI_PLD_FIFO_FULL_ERR, + GEN_TX_CMD_FIFO_FULL_ERR, + GEN_TX_PLD_FIFO_FULL_ERR, + GEN_TX_PLD_FIFO_EMPTY_ERR, + GEN_RX_PLD_FIFO_EMPTY_ERR, + GEN_RX_PLD_FIFO_FULL_ERR, + + DBI_TX_CMD_FIFO_FULL_ERR, + DBI_TX_PLD_FIFO_FULL_ERR, + DBI_RX_PLD_FIFO_EMPTY_ERR, + DBI_RX_PLD_FIFO_FULL_ERR, + DBI_ILLEGAL_CMD_ERR, + DSI_MAX_EVENT +} +dsih_event_t; +typedef enum +{ + NOT_INITIALIZED = 0, + INITIALIZED, + ON, + OFF +} +dsih_state_t; + +typedef struct dphy_t +{ + uint32_t address; + uint32_t reference_freq; +#ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING + /** mark if D-PHY should keep work or not */ + uint32_t phy_keep_work; +#endif + dsih_state_t status; + void (*bsp_pre_config)(struct dphy_t *instance, void* param); + uint32_t (*core_read_function)(uint32_t addr, uint32_t offset); + void (*core_write_function)(uint32_t addr, uint32_t offset, uint32_t data); + void (*log_error)(const char * string); + void (*log_info)(const char *fmt, ...); +} +dphy_t; + +typedef struct dsih_ctrl_t +{ + uint32_t address; + dphy_t phy_instance; + uint32_t phy_feq; + uint8_t max_lanes; + uint8_t max_hs_to_lp_cycles; + uint8_t max_lp_to_hs_cycles; + uint16_t max_bta_cycles; + int color_mode_polarity; + int shut_down_polarity; + dsih_state_t status; + uint32_t (*core_read_function)(uint32_t addr, uint32_t offset); + void (*core_write_function)(uint32_t addr, uint32_t offset, uint32_t data); + void (*log_error)(const char * string); + void (*log_info)(const char *fmt, ...); + void (*event_registry[DSI_MAX_EVENT])(struct dsih_ctrl_t *instance, void *handler); +} +dsih_ctrl_t; +typedef struct +{ + uint8_t no_of_lanes; + uint8_t virtual_channel; + dsih_video_mode_t video_mode; + int receive_ack_packets; + uint32_t byte_clock; + uint32_t pixel_clock; + dsih_color_coding_t color_coding; + int is_18_loosely; + int data_en_polarity; + int h_polarity; + uint16_t h_active_pixels; /* hadr*/ + uint16_t h_sync_pixels; + uint16_t h_back_porch_pixels; /* hbp */ + uint16_t h_total_pixels; /* h_total */ + int v_polarity; + uint16_t v_active_lines; /* vadr*/ + uint16_t v_sync_lines; + uint16_t v_back_porch_lines; /* vbp */ + uint16_t v_total_lines; /* v_total */ +} +dsih_dpi_video_t; +typedef struct +{ + uint32_t addr; + uint32_t data; +} +register_config_t; + +#endif /* MIPI_DSIH_LOCAL_H_ */ + -- cgit v1.3.1