一、主要还是解决这个问题,最后没办法,只能进行串口通信,来识别屏幕的类型了。
基本步骤如下:
1. uboot阶段发送串口指令,等待串口回复数据,根据数据识别屏幕类型
2.在bootargs增加一个自定义的参数,告诉内核屏幕的类型,驱动中更加屏幕类型使用不同的时序
本文只讲uboot中串口的设置,本次项目中使用的是串口4.
参考文件:drivers/serial/ns16550.c (uboot2017.09源码)
二、遇到的问题:
1.要不要使用dts?,由于能力有限,没有使用dts设置
2.如何初始化?
3.如何进行io复用?
4.调试的时候遇到的问题,就是无法通信,使用ttl的串口连着,看到又0xff,00,00三个字节输出,但是这三个字节都不是我自己发送的。开始时怀疑波特率的问题,因为我实际发送了8个字节,而只收到了3个字节,那就时钟配置不对,又把时钟的配置找了一圈,后面确认是24MHz。
5.时钟确认之后,后来发现是引脚复用不对,由于不熟悉3399的结构,弄混了GRF和PMUGRF,以为是同一个东西。直接就用错了,后来改了过来。
6.还是要适当使用uboot的md和mm工具,这样能方便直接读取寄存器的内容,根据实际的值去判断设置是否正确。
7.serial_din和serial_in也是一定要慎重,这个地方用错了,直接导致uboot崩了,无法进入loader模式,差点成砖了,还好最后发现还能用短路(emmc_clk和GND)的办法进入到maskrom模式。
三、代码
直接在ns16550.c中参考,并写在了该文件中。
特别说明以下:
1.接收函数我使用了一个超时返回的方法,因为接收不到值得时候(比如没有连接屏,或者连接的屏型号不对呢等等各种因素吧),我不能一直卡着,就直接启动了。
2.发送函数我写死了,因为我只有一条查询指令,干脆就直接写了,要灵活使用的朋友注意一下。
#define PMUCRU_BASE 0xff750000
void board_com4_init(void)
{
//gpio的初始化
#define PMUGRF_BASE 0xff320000
struct rk3399_pmugrf_regs * const pmugrf = (void *)PMUGRF_BASE;
/* Enable early UART4 channel on the RK3399/RK3399PRO */
rk_clrsetreg(&pmugrf->gpio1a_iomux,
PMUGRF_GPIO1A7_SEL_MASK,
PMUGRF_UART4_RXD << PMUGRF_GPIO1A7_SEL_SHIFT);
rk_clrsetreg(&pmugrf->gpio1b_iomux,
PMUGRF_GPIO1B0_SEL_MASK,
PMUGRF_UART4_TXD << PMUGRF_GPIO1B0_SEL_SHIFT);
printf("board_com4_init done..\n");
}
void com4_init(void)
{
struct NS16550 *com_port = (struct NS16550 *)0xff370000; //com4
int baud_divisor;
// unsigned int val_temp;
// volatile unsigned long* pmucru_clksel_con5 = (volatile unsigned long*)(PMUCRU_BASE + 0x0094);
// val_temp = *pmucru_clksel_con5;
// printf("1. val_temp = %u\n",val_temp);
// val_temp &= ~(3 << 8);
// val_temp |= (2<<8) | (2<<14); //默认值是2, 时钟源选择24M输入
// * pmucru_clksel_con5 = val_temp;
/*
* We copy the code from above because it is already horribly messy.
* Trying to refactor to nicely remove the duplication doesn't seem
* feasible. The better fix is to move all users of this driver to
* driver model.
*/
baud_divisor = ns16550_calc_divisor(com_port, 24000000,
115200);
serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
serial_dout(&com_port->mdr1, 0x7);
serial_dout(&com_port->mcr, 0);
serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
// serial_dout(&com_port->fcr, UART_FCR_RXSR | UART_FCR_TXSR); //不使能FIFO
serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL); //设置波特率
serial_dout(&com_port->dll, baud_divisor & 0xff);
serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
serial_dout(&com_port->lcr, UART_LCRVAL);
serial_dout(&com_port->mdr1, 0x0);
//1. gpio 初始化
board_com4_init();
printf("12-07-1,end com4_init\n");
}
void com4_send_cmd(void)
{
struct NS16550 *com_port = (struct NS16550 *)0xff370000; //com4
char cmd_buf[] = {0xa5,0x5a,0x88,0,0,0,0,0x87};
int i;
for(i=0;i<8;i++)
{
while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
;
serial_dout(&com_port->thr, cmd_buf[i]);
// printf("cmd_buf[i] = %d\n",cmd_buf[i]);
}
// NS16550_putc(com_port, cmd_buf[i]);
}
//int is_com4_recv_data(void)
//{
// struct NS16550 *com_port = (struct NS16550 *)0xff370000; //com4
//
// return(serial_in(&com_port->lsr) & UART_LSR_DR);
//
//}
//-1 表示出错
int com4_recv_a_byte_data(void)
{
struct NS16550 *com_port = (struct NS16550 *)0xff370000; //com4
int i = 0;
while(!(serial_din(&com_port->lsr) & UART_LSR_DR)) //返回0表示没有数据
{
mdelay(1); //延时1ms
i++;
if(i>=200) //最多等待200ms
return -1;
}
return serial_din(&com_port->rbr); //收到数据了
}
宏定义自己加一下,grf_rk3399.h
实际使用的代码如下:
接收8个字节的代码,不是阻塞等待,是超时处理!!!!
//返回-1 就是超时,-3表示校验和错误。
int com4_recv_lcd_type_data(void)
{
char cmd_buf[12];
int count = 0;
int ret_val = 0;
// int val;
while(1)
{
ret_val = com4_recv_a_byte_data();
if(ret_val == -1) //出错了
return -1;
cmd_buf[count] = ret_val;
if(count == 0){
if(cmd_buf[count] != 0xa5)
{
count = 0;
continue;
}
}
else if(count == 1){
if(cmd_buf[count] != 0x5a)
{
count = 0;
continue;
}
}
else if(count >= 7) //接收结束
{
printf("com4 lcd_type data :%x %x %x %x-- %x %x %x - %x\n",cmd_buf[0],cmd_buf[1],cmd_buf[2],cmd_buf[3],
cmd_buf[4],cmd_buf[5],cmd_buf[6],
cmd_buf[7]);
//val = cmd_buf[0]+cmd_buf[1]+cmd_buf[2]+cmd_buf[3]+cmd_buf[4]+cmd_buf[5]+cmd_buf[6];
if(((cmd_buf[2]+cmd_buf[3])&0xff) == cmd_buf[7])
return cmd_buf[3];
// printf("%x %x %x %x-- %x %x %x - %x\n",cmd_buf[0],cmd_buf[1],cmd_buf[2],cmd_buf[3],
// cmd_buf[4],cmd_buf[5],cmd_buf[6],
// cmd_buf[7]);
break;
}
count ++;
}
return -3;
}