blob: 64cc937dd4da53157c4e78dc36abfe5d46f571bd [file] [log] [blame]
#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;
}