/** * @file sdrv_lvds_drv.c * @brief sdrv lvds driver source. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include enum LVDS_CHANNEL { LVDS_CH0 = 0, LVDS_CH_MAX_NUM }; enum { LVDS_SEPARATE_MODE = 0, LVDS_MODE_MAX_NUM }; enum { LVDS_PIXEL_BPP_NC = -1, LVDS_PIXEL_BPP_16, LVDS_PIXEL_BPP_24, LVDS_PIXEL_BPP_30, }; enum { SOFT_RESET_CH0 = 0, SOFT_RESET_CH_MAX_NUM }; typedef enum { PIXEL_FORMAT_18_BIT = 0x0, PIXEL_FORMAT_24_BIT = 0x1, PIXEL_FORMAT_30_BIT = 0x2 } LVDS_PIXEL_FORMAT; enum { DUALLODD_ODD = 0x0, DUALLODD_EVEN = 0x1 }; struct lvds_chx_info { uint32_t ch_idx; uint32_t ch_mode; uint32_t pixel_fmt; uint32_t map_format; uint32_t vsync_pol; }; static unsigned int lvds_get_reg_base(void) { static unsigned int base = 0; if (base == 0) base = LVDS_BASE; return base; } static int get_lvds_pixel_bpp(int pixel_bpp) { switch (pixel_bpp) { case 16: return LVDS_PIXEL_BPP_16; case 24: return LVDS_PIXEL_BPP_24; case 30: return LVDS_PIXEL_BPP_30; default: return LVDS_PIXEL_BPP_NC; } } status_t lvds_soft_reset(void) { unsigned int val = 0; addr_t base = lvds_get_reg_base(); /*set to high*/ val = disp_read(base, LVDS_SOFT_RESET); val = reg_value(1, val, CH0_SOFT_RESET_SHIFT, CH0_SOFT_RESET_MASK); disp_write(base, LVDS_SOFT_RESET, val); udelay(10); /*set to low*/ val = reg_value(0, val, CH0_SOFT_RESET_SHIFT, CH0_SOFT_RESET_MASK); disp_write(base, LVDS_SOFT_RESET, val); return SDRV_DISPSS_STATUS_OK; } static void lvds_channel_config(addr_t base, struct lvds_chx_info *info) { unsigned int val = 0; int i = 0; val = disp_read(base, DC1_MUX_CTRL); val = reg_value(1, val, PARAL_TO_LVDS_EN_SHIFT, PARAL_TO_LVDS_EN_MASK); disp_write(base, DC1_MUX_CTRL, val); val = disp_read(base, LVDS_CH0_CTRL); val = reg_value(0, val, CH0_DUALMODE_SHIFT, CH0_DUALMODE_MASK); val = reg_value(info->pixel_fmt, val, CH0_BPP_SHIFT, CH0_BPP_MASK); val = reg_value(info->map_format, val, CH0_FORMAT_SHIFT, CH0_FORMAT_MASK); val = reg_value(info->vsync_pol, val, CH0_VSYNC_POL_SHIFT, CH0_VSYNC_POL_MASK); val = reg_value(0, val, CH0_MUX_SHIFT, CH0_MUX_MASK); val = reg_value(1, val, CH0_EN_SHIFT, CH0_EN_MASK); disp_write(base, LVDS_CH0_CTRL, val); val = disp_read(base, LVDS_CH0_PAD_COM_SET); val = reg_value(1, val, CH0_TEST_RXEN_SHIFT, CH0_TEST_RXEN_MASK); val = reg_value(1, val, CH0_TEST_PULLDN_SHIFT, CH0_TEST_PULLDN_MASK); disp_write(base, LVDS_CH0_PAD_COM_SET, val); for (i = 0; i < 5; i++) { val = disp_read(base, LVDS_CH0_PAD_SET_(i)); val = reg_value(1, val, CH0_TXEN_SHIFT, CH0_TXEN_MASK); val = reg_value(1, val, CH0_RTERM_EN_SHIFT, CH0_RTERM_EN_MASK); disp_write(base, LVDS_CH0_PAD_SET_(i), val); } } /** * @brief lvds channel enable. * * This function control the lvds channel output. * * @param [in] enable false->disable; true->enable. */ void sdrv_lvds_channel_enable(bool enable) { int val = 0; int i = 0; addr_t base = lvds_get_reg_base(); DISPSS_LOG_FUNC(); val = disp_read(base, LVDS_CH0_PAD_COM_SET); if (enable) { val = reg_value(1, val, CH0_TEST_RXEN_SHIFT, CH0_TEST_RXEN_MASK); val = reg_value(1, val, CH0_TEST_PULLDN_SHIFT, CH0_TEST_PULLDN_MASK); } else { val = reg_value(0, val, CH0_TEST_RXEN_SHIFT, CH0_TEST_RXEN_MASK); val = reg_value(0, val, CH0_TEST_PULLDN_SHIFT, CH0_TEST_PULLDN_MASK); } disp_write(base, LVDS_CH0_PAD_COM_SET, val); for (i = 0; i < 5; i++) { val = disp_read(base, LVDS_CH0_PAD_SET_(i)); if (enable) { val = reg_value(1, val, CH0_TXEN_SHIFT, CH0_TXEN_MASK); val = reg_value(1, val, CH0_RTERM_EN_SHIFT, CH0_RTERM_EN_MASK); } else { val = reg_value(0, val, CH0_TXEN_SHIFT, CH0_TXEN_MASK); val = reg_value(0, val, CH0_RTERM_EN_SHIFT, CH0_RTERM_EN_MASK); } disp_write(base, LVDS_CH0_PAD_SET_(i), val); } } status_t sdrv_lvds_init(struct sdrv_panel *panel) { status_t ret = SDRV_DISPSS_STATUS_OK; if (panel != NULL) { int lvds_pixel_bpp; addr_t base = lvds_get_reg_base(); struct lvds_chx_info chx_info; DISPSS_LOG_FUNC(); memset(&chx_info, 0, sizeof(struct lvds_chx_info)); lvds_pixel_bpp = get_lvds_pixel_bpp(panel->pixel_bpp); chx_info.map_format = panel->timing->map_format; chx_info.vsync_pol = panel->timing->vsync_pol; chx_info.pixel_fmt = lvds_pixel_bpp; chx_info.ch_mode = LVDS_SEPARATE_MODE; chx_info.ch_idx = LVDS_CH0; lvds_channel_config(base, &chx_info); } else { DISPSS_LOG_INFO("sdrv_panel arg err"); ret = SDRV_DISPSS_STATUS_INVALID_PARAM; } return ret; }