| #include "asrfb.h" |
| #include "mcu_drv.h" |
| |
| static struct s_mcu_ctx g_mcu_ctx; |
| static void set_mcu_path(struct s_mcu_ctx *mcu_ctx, uint32_t path) |
| { |
| if(path == MCU_PATH_IMAGE) |
| lcd_clear_bits(LCD_SMPN_CTRL, BIT_4); |
| else |
| lcd_set_bits(LCD_SMPN_CTRL, BIT_4); |
| mcu_ctx->cur_path = path; |
| } |
| |
| static void trigger_mcu(uint32_t val) |
| { |
| /* polling mode */ |
| int cnt = 0; |
| lcd_write(LCD_SLV_PORT, val); |
| val = lcd_read(SPU_IRQ_ISR_RAW); |
| while (!(val & IRQ_MCU_DONE)) { |
| cnt++; |
| if(cnt >= 100){ |
| printf("Warn: lcd spi xfer timeout.\n"); |
| break; |
| } |
| udelay(10); |
| val = lcd_read(SPU_IRQ_ISR_RAW); |
| } |
| |
| lcd_write(SPU_IRQ_ISR_RAW, ~IRQ_MCU_DONE); |
| } |
| |
| struct s_mcu_ctx* mcu_init(uint32_t sclk, struct mcu_info *info) |
| { |
| struct s_mcu_ctx *mcu_ctx = &g_mcu_ctx; |
| uint32_t reg = 0, scycle, rl, rh, wl, wh; |
| |
| scycle = 1000000 / sclk; /*ns*/ |
| rl = (info->timing->rlpw + scycle - 1) / scycle - 1; |
| rh = (info->timing->rhpw + scycle - 1) / scycle - 1; |
| wl = (info->timing->wlpw + scycle - 1) / scycle - 1; |
| wh = (info->timing->whpw + scycle - 1) / scycle - 1; |
| if((rl > 15) || (rh > 15) || (wl > 15) || (wh > 15)){ |
| printf("%s: can't get mcu's clk!\r\n", __func__); |
| return NULL; |
| } |
| |
| memset(mcu_ctx, 0, sizeof(struct s_mcu_ctx)); |
| mcu_ctx->base_addr = CONFIG_FB_ASR_REG_BASE; |
| mcu_ctx->sclk = sclk; |
| memcpy(&mcu_ctx->info, info, sizeof(struct mcu_info)); |
| |
| reg = rl << 28 | rh << 24 | wl << 20 | wh << 16; |
| |
| if(info->format >= MCU_FORMAT_RGB888_3 && info->format <= MCU_FORMAT_RGB565_1) |
| reg |= (info->format << 8); |
| else |
| reg |= (1 << 8); |
| |
| if(info->endian == MCU_ENDIAN_MSB) |
| reg |= BIT_6; |
| |
| if(info->device_id == 0) |
| reg &= ~BIT_5; |
| |
| if(info->bus_mode == MCU_BUS_8080) |
| reg &= ~BIT_2; |
| |
| reg |= BIT_0; /* enable mcu interface */ |
| lcd_write(LCD_SMPN_CTRL, reg); |
| /* should be set, otherwith color will error */ |
| lcd_set_bits(LCD_MISC_CNTL, BIT_1); |
| /* delay cs rising edge one cycle */ |
| lcd_set_bits(LCD_PN_CTRL0, BIT_25); |
| |
| /* use register path as default */ |
| set_mcu_path(mcu_ctx, MCU_PATH_REGISTER); |
| mcu_ctx->status = MCU_STATUS_INIT; |
| return mcu_ctx; |
| } |
| |
| int mcu_set_cs(struct s_mcu_ctx *mcu_ctx, uint32_t enable) |
| { |
| if(mcu_ctx->info.force_cs == 0){ |
| printf("%s: Not force CS mode, can't set CS!\r\n", __func__); |
| return -1; |
| } |
| |
| if(enable) |
| lcd_set_bits(LCD_SMPN_CTRL, BIT_1); |
| else |
| lcd_clear_bits(LCD_SMPN_CTRL, BIT_1); |
| mcu_ctx->cur_cs = enable; |
| return 0; |
| } |
| |
| int mcu_write_cmd(struct s_mcu_ctx *mcu_ctx, uint32_t cmd, uint32_t bits) |
| { |
| int reg; |
| |
| if((mcu_ctx->info.force_cs == 1) && (mcu_ctx->cur_cs == 0)){ |
| printf("%s: Invalid CS status\r\n", __func__); |
| return -1; |
| } |
| |
| if(mcu_ctx->cur_path == MCU_PATH_IMAGE) |
| set_mcu_path(mcu_ctx, MCU_PATH_REGISTER); |
| |
| switch(bits){ |
| case 8: |
| reg = (cmd & 0xFF) | BIT_8; |
| trigger_mcu(reg); |
| break; |
| case 16: |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| break; |
| case 24: |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| reg = (cmd & 0xFF0000) | BIT_8; |
| trigger_mcu(reg); |
| break; |
| case 32: |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| reg = (cmd & 0xFF0000) | BIT_8 | ((cmd & 0xFF000000)<<8) | BIT_24; |
| trigger_mcu(reg); |
| break; |
| default: |
| printf("%s: Invalid bits!\r\n", __func__); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int mcu_write_data(struct s_mcu_ctx *mcu_ctx, uint32_t data, uint32_t bits) |
| { |
| int reg; |
| |
| if((mcu_ctx->info.force_cs == 1) && (mcu_ctx->cur_cs == 0)){ |
| printf("%s: Invalid CS status\r\n", __func__); |
| return -1; |
| } |
| |
| if(mcu_ctx->cur_path == MCU_PATH_IMAGE) |
| set_mcu_path(mcu_ctx, MCU_PATH_REGISTER); |
| |
| switch(bits){ |
| case 8: |
| reg = (data & 0xFF) | BIT_8 | BIT_15; |
| trigger_mcu(reg); |
| break; |
| case 16: |
| reg = (data & 0xFF) | BIT_8 | BIT_15 | ((data & 0xFF00)<<8) | BIT_24 |
| | BIT_31; |
| trigger_mcu(reg); |
| break; |
| case 24: |
| reg = (data & 0xFF) | BIT_8 | BIT_15 | ((data & 0xFF00)<<8) | BIT_24 |
| | BIT_31; |
| trigger_mcu(reg); |
| reg = (data & 0xFF0000) | BIT_8; |
| trigger_mcu(reg); |
| break; |
| case 32: |
| reg = (data & 0xFF) | BIT_8 | BIT_15 | ((data & 0xFF00)<<8) | BIT_24 |
| | BIT_31; |
| trigger_mcu(reg); |
| reg = (data & 0xFF0000) | BIT_8 | BIT_15 | ((data & 0xFF000000)<<8) |
| | BIT_24 | BIT_31; |
| trigger_mcu(reg); |
| break; |
| default: |
| printf("%s: Invalid bits!\r\n", __func__); |
| return -1; |
| } |
| return 0; |
| } |
| |
| |
| int mcu_read_data(struct s_mcu_ctx *mcu_ctx, uint32_t cmd, uint32_t cmd_bits, |
| uint32_t *data, uint32_t data_bits) |
| { |
| int reg; |
| int readdata; |
| |
| if((mcu_ctx->info.force_cs == 1) && (mcu_ctx->cur_cs == 0)){ |
| printf("%s: Invalid CS status\r\n", __func__); |
| return -1; |
| } |
| |
| if(mcu_ctx->cur_path == MCU_PATH_IMAGE) |
| set_mcu_path(mcu_ctx, MCU_PATH_REGISTER); |
| |
| switch(cmd_bits){ |
| case 8: |
| case 24: |
| if(cmd_bits == 8){ |
| reg = (cmd & 0xFF) | BIT_8; |
| } else { |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| reg = (cmd & 0xFF0000) | BIT_8; |
| } |
| switch(data_bits){ |
| case 8: |
| reg |= BIT_25 | BIT_31; |
| trigger_mcu(reg);//The first read is dummy |
| reg = BIT_9 | BIT_15; |
| trigger_mcu(reg); |
| *data = lcd_read(LCD_ISA_RXDATA) & MASK8; |
| break; |
| case 16: |
| reg |= BIT_25 | BIT_31; |
| trigger_mcu(reg);//The first read is dummy |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg); |
| *data = lcd_read(LCD_ISA_RXDATA) & MASK16; |
| break; |
| case 24: |
| reg |= BIT_25 | BIT_31; |
| trigger_mcu(reg);//The first read is dummy |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg); |
| readdata = lcd_read(LCD_ISA_RXDATA) & MASK16; |
| reg = BIT_9 | BIT_15; |
| trigger_mcu(reg); |
| *data = (readdata << 8) | (lcd_read(LCD_ISA_RXDATA) & MASK8); |
| break; |
| case 32: |
| reg |= BIT_25 | BIT_31; |
| trigger_mcu(reg);//The first read is dummy |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg); |
| readdata = lcd_read(LCD_ISA_RXDATA) & MASK16; |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg); |
| *data = (readdata << 16) | (lcd_read(LCD_ISA_RXDATA) & MASK16); |
| break; |
| default: |
| printf("%s: Invalid bits!\r\n", __func__); |
| return -1; |
| } |
| break; |
| case 16: |
| case 32: |
| if(cmd_bits == 16){ |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| } else { |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| reg = (cmd & 0xFF0000) | BIT_8 | ((cmd & 0xFF000000)<<8) | BIT_24; |
| trigger_mcu(reg); |
| } |
| switch(data_bits){ |
| case 8: |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg);//The first read is dummy |
| *data = (lcd_read(LCD_ISA_RXDATA) & MASK16) >> 8; |
| break; |
| case 16: |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg);//The first read is dummy |
| readdata = (lcd_read(LCD_ISA_RXDATA) & MASK16) >> 8; |
| reg = BIT_9 | BIT_15; |
| trigger_mcu(reg); |
| *data = (readdata << 8)|(lcd_read(LCD_ISA_RXDATA) & MASK8); |
| break; |
| case 24: |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg);//The first read is dummy |
| readdata = (lcd_read(LCD_ISA_RXDATA) & MASK16) >> 8; |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg); |
| *data = (readdata << 16)|(lcd_read(LCD_ISA_RXDATA) & MASK16); |
| break; |
| case 32: |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg);//The first read is dummy |
| readdata = (lcd_read(LCD_ISA_RXDATA) & MASK16) >> 8; |
| reg = BIT_9 | BIT_15 | BIT_25 | BIT_31; |
| trigger_mcu(reg); |
| readdata = (readdata << 16)|(lcd_read(LCD_ISA_RXDATA) & MASK16); |
| reg = BIT_9 | BIT_15; |
| trigger_mcu(reg); |
| *data = (readdata << 8)|(lcd_read(LCD_ISA_RXDATA) & MASK8); |
| break; |
| default: |
| printf("%s: Invalid bits!\r\n", __func__); |
| return -1; |
| } |
| break; |
| default: |
| printf("%s: Invalid bits!\r\n", __func__); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int mcu_write_cmd_data(struct s_mcu_ctx *mcu_ctx, uint32_t cmd, |
| uint32_t cmd_bits, uint32_t data, uint32_t data_bits) |
| { |
| int reg; |
| |
| if ((mcu_ctx->info.force_cs == 1) && (mcu_ctx->cur_cs == 0)) { |
| printf("%s: Invalid CS status\r\n", __func__); |
| return -1; |
| } |
| |
| if(mcu_ctx->cur_path == MCU_PATH_IMAGE) |
| set_mcu_path(mcu_ctx, MCU_PATH_REGISTER); |
| |
| switch(cmd_bits){ |
| case 8: |
| case 24: |
| if(cmd_bits == 8){ |
| reg = (cmd & 0xFF) | BIT_8; |
| } else { |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| reg = (cmd & 0xFF0000) | BIT_8; |
| } |
| switch(data_bits){ |
| case 8: |
| reg |= ((data & 0xFF)<<16) | BIT_24 | BIT_31; |
| trigger_mcu(reg); |
| break; |
| case 16: |
| reg |= ((data & 0xFF)<<16) | BIT_24 | BIT_31; |
| trigger_mcu(reg); |
| reg = ((data & 0xFF00) >> 8) | BIT_8 | BIT_15; |
| trigger_mcu(reg); |
| break; |
| case 24: |
| reg |= ((data & 0xFF)<<16) | BIT_24 | BIT_31; |
| trigger_mcu(reg); |
| reg = ((data & 0xFF00) >> 8) | BIT_8 | BIT_15 | |
| ((data & 0xFF0000)) | BIT_24 | BIT_31; |
| trigger_mcu(reg); |
| break; |
| case 32: |
| reg |= ((data & 0xFF)<<16) | BIT_24 | BIT_31; |
| trigger_mcu(reg); |
| reg = ((data & 0xFF00) >> 8) | BIT_8 | BIT_15 | |
| ((data & 0xFF0000)) | BIT_24 | BIT_31; |
| trigger_mcu(reg); |
| reg = (data & 0xFF000000) | BIT_8 | BIT_15; |
| trigger_mcu(reg); |
| break; |
| default: |
| printf("%s: Invalid bits!\r\n", __func__); |
| return -1; |
| } |
| break; |
| case 16: |
| case 32: |
| if(cmd_bits == 16){ |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| } else { |
| reg = (cmd & 0xFF) | BIT_8 | ((cmd & 0xFF00)<<8) | BIT_24; |
| trigger_mcu(reg); |
| reg = (cmd & 0xFF0000) | BIT_8 | ((cmd & 0xFF000000)<<8) | BIT_24; |
| trigger_mcu(reg); |
| } |
| switch(data_bits){ |
| case 8: |
| reg = (data & 0xFF) | BIT_8 | BIT_15; |
| trigger_mcu(reg); |
| break; |
| case 16: |
| reg = (data & 0xFF) | BIT_8 | BIT_15 | ((data & 0xFF00)<<8) | BIT_24 |
| | BIT_31; |
| trigger_mcu(reg); |
| break; |
| case 24: |
| reg = (data & 0xFF) | BIT_8 | BIT_15 | ((data & 0xFF00)<<8) | BIT_24 |
| | BIT_31; |
| trigger_mcu(reg); |
| reg = (data & 0xFF0000) | BIT_8; |
| trigger_mcu(reg); |
| break; |
| case 32: |
| reg = (data & 0xFF) | BIT_8 | BIT_15 | ((data & 0xFF00)<<8) | BIT_24 |
| | BIT_31; |
| trigger_mcu(reg); |
| reg = (data & 0xFF0000) | BIT_8 | BIT_15 | ((data & 0xFF000000)<<8) |
| | BIT_24 | BIT_31; |
| trigger_mcu(reg); |
| break; |
| default: |
| printf("%s: Invalid bits!\r\n", __func__); |
| return -1; |
| } |
| break; |
| default: |
| printf("%s: Invalid bits!\r\n", __func__); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int mcu_before_refresh(struct s_mcu_ctx *mcu_ctx) |
| { |
| if(mcu_ctx->cur_path != MCU_PATH_IMAGE) |
| set_mcu_path(mcu_ctx, MCU_PATH_IMAGE); |
| return 0; |
| } |
| |
| int mcu_after_refresh(struct s_mcu_ctx *mcu_ctx) |
| { |
| if(mcu_ctx->cur_path != MCU_PATH_REGISTER) |
| set_mcu_path(mcu_ctx, MCU_PATH_REGISTER); |
| |
| return 0; |
| } |
| |
| void mcu_uninit(struct s_mcu_ctx *mcu_ctx) |
| { |
| lcd_write(LCD_SMPN_CTRL, 0); |
| mcu_ctx->status = MCU_STATUS_UNINIT; |
| } |
| |