| /* |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * * |
| This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * * |
| This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * * |
| You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| * * |
| Description: |
| */ |
| |
| #include <common.h> |
| //#include <asm/io.h> |
| #include <asm/arch/secure_apb.h> |
| #include <asm/arch/cpu.h> |
| |
| /* for gxbaby(s905) use only */ |
| |
| //#define wr_reg(addr, data) writel(data, addr) |
| //#define rd_reg(addr) readl(addr) |
| #define readl(addr) (unsigned int )(*((volatile unsigned int *)((unsigned long)(unsigned int )addr))) //rd_reg(addr) |
| #define writel(data ,addr) (*((volatile unsigned int *)((unsigned long)(unsigned int )addr)))=(data) //wr_reg(addr, data) |
| |
| #define wr_reg(addr, data) (*((volatile unsigned int *)((unsigned long)(unsigned int )addr)))=(data) //wr_reg(addr, data) |
| #define rd_reg(addr) (unsigned int )(*((volatile unsigned int *)((unsigned long)(unsigned int )addr))) //rd_reg(addr) |
| |
| /* ddr regs */ |
| #define DDR0_PUB_REG_BASE (0xc8836000) |
| #define DDR0_PUB_PIR (DDR0_PUB_REG_BASE+(0x01<<2)) |
| #define DDR0_PUB_PGCR1 (DDR0_PUB_REG_BASE+(0x03<<2)) |
| #define DDR0_PUB_ACLCDLR (DDR0_PUB_REG_BASE+(0x0F<<2)) |
| #define DDR0_PUB_DX0LCDLR1 (DDR0_PUB_REG_BASE+(0xAF<<2)) |
| #define DDR0_PUB_DX1LCDLR1 (DDR0_PUB_REG_BASE+(0xCF<<2)) |
| |
| #define ACBDLR_MAX 0X1F |
| #define ACLCDLR_MAX 0XFF |
| #define DQBDLR_MAX 0X1F |
| #define DQLCDLR_MAX 0XFF |
| #define DXNGTR_MAX 0X7 |
| |
| #define WR_RD_ADJ_USE_ENV 1 |
| #define WR_RD_ADJ_USE_UART_INPUT 2 |
| |
| #define OPEN_CHANNEL_A_PHY_CLK() (writel((0), 0xc8836c00)) |
| #define OPEN_CHANNEL_B_PHY_CLK() (writel((0), 0xc8836c00)) |
| #define CLOSE_CHANNEL_A_PHY_CLK() (writel((5), 0xc8836c00)) |
| #define CLOSE_CHANNEL_B_PHY_CLK() (writel((5), 0xc8836c00)) |
| |
| int wr_adj_per[12]={ |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| }; |
| int rd_adj_per[12]={ |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| 100 , |
| }; |
| |
| #define CMD_ARGV_MAX 13 |
| #define CMD_DQS_ADJ_MAX 6 |
| //just tune for lcdlr |
| int do_ddr_dqs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| if (argc < CMD_ARGV_MAX) { |
| //cmd_usage(cmdtp); |
| return -1; |
| } |
| |
| int i=0; |
| char *endp; |
| unsigned int wr_rd_adj_input_src=2; |
| |
| printf("\nEnter ddr_fine_tune_lcdlr_env function\n"); |
| #if 0 |
| printf("\nargc== 0x%08x, argv", argc); |
| for (i = 0;i<argc;i++) |
| printf("[%d]=%s, ",i,argv[i]); |
| #endif |
| OPEN_CHANNEL_A_PHY_CLK(); |
| |
| //wr_rd_adj_input_src = simple_strtoul(argv[1], &endp, 10); |
| if (wr_rd_adj_input_src == WR_RD_ADJ_USE_UART_INPUT) { |
| printf("\nTune ddr lcdlr use uart input\n"); |
| if (argc > CMD_ARGV_MAX) |
| argc = CMD_ARGV_MAX; |
| for (i = 1; i<argc; i++) { |
| if (i<(1+CMD_DQS_ADJ_MAX)) |
| wr_adj_per[i-1]=simple_strtoul(argv[i], &endp, 10); |
| else |
| rd_adj_per[i-1-CMD_DQS_ADJ_MAX]=simple_strtoul(argv[i], &endp, 10); |
| } |
| } |
| |
| #if 0 |
| if (wr_rd_adj_input_src == WR_RD_ADJ_USE_ENV) { |
| printf("\nTune ddr lcdlr use uboot env\n"); |
| const char *s; |
| int value=0; |
| s = getenv("env_wr_lcdlr_pr"); |
| if (s) { |
| printf("%s",s); |
| value = simple_strtoul(s, &endp, 16); |
| printf("%d",value); |
| } |
| s = getenv("env_rd_lcdlr_pr"); |
| |
| if (s) { |
| printf("%s",s); |
| } |
| |
| if (argc>24+2) |
| argc=24+2; |
| for (i = 2;i<argc;i++) { |
| if (i<(2+6)) |
| wr_adj_per[i-2]=simple_strtoul(argv[i], &endp, 16); |
| else |
| rd_adj_per[i-8]=simple_strtoul(argv[i], &endp, 16); |
| } |
| } |
| #endif |
| |
| printf(" wr_adj_per[]={"); |
| for (i = 0; i < CMD_DQS_ADJ_MAX; i++) |
| printf("%04d, ", wr_adj_per[i]); |
| printf("};\n"); |
| printf(" rd_adj_per[]={"); |
| for (i = 0; i < CMD_DQS_ADJ_MAX; i++) |
| printf("%04d, ", rd_adj_per[i]); |
| printf("};\n"); |
| |
| wr_reg(DDR0_PUB_PIR, (rd_reg(DDR0_PUB_PIR))|(1<<29)); |
| wr_reg(DDR0_PUB_PGCR1, (rd_reg(DDR0_PUB_PGCR1))|(1<<26)); |
| |
| int lcdlr_w=0,lcdlr_r=0; |
| unsigned temp_reg=0; |
| int temp_count=0; |
| for (temp_count=0;temp_count<2;temp_count++) { |
| temp_reg=(unsigned)(DDR0_PUB_ACLCDLR+(temp_count<<2)); |
| lcdlr_w=(int)((rd_reg((uint64_t)(temp_reg)))&ACLCDLR_MAX); |
| lcdlr_w=lcdlr_w?lcdlr_w:1; |
| lcdlr_w=(lcdlr_w*(wr_adj_per[temp_count]))/100; |
| if (temp_count == 1) |
| lcdlr_w=lcdlr_w&ACBDLR_MAX; |
| wr_reg(((uint64_t)(temp_reg)),((lcdlr_w)&ACLCDLR_MAX)); |
| } |
| |
| for (temp_count=2;temp_count<CMD_DQS_ADJ_MAX;temp_count++) { |
| temp_reg=(unsigned)(DDR0_PUB_DX0LCDLR1+(DDR0_PUB_DX1LCDLR1-DDR0_PUB_DX0LCDLR1)*(temp_count-2)); |
| lcdlr_w=(int)((rd_reg((uint64_t)(temp_reg)))&DQLCDLR_MAX); |
| lcdlr_w=lcdlr_w?lcdlr_w:1; |
| lcdlr_r=(int)(((rd_reg((uint64_t)(temp_reg)))>>8)&DQLCDLR_MAX); |
| lcdlr_r=lcdlr_r?lcdlr_r:1; |
| lcdlr_w=(lcdlr_w*(wr_adj_per[temp_count]))/100; |
| lcdlr_r=(lcdlr_r*(rd_adj_per[temp_count]))/100; |
| wr_reg(((uint64_t)(temp_reg)),(((lcdlr_r<<16)|(lcdlr_r<<8)|(lcdlr_w)))); |
| } |
| |
| /* S905X */ |
| #if 0 |
| for ( temp_count=6;temp_count<8;temp_count++) { |
| temp_reg=(unsigned)(DDR1_PUB_ACLCDLR+((temp_count-6)<<2)); |
| |
| lcdlr_w=(int)((rd_reg((uint64_t)(temp_reg)))&ACLCDLR_MAX); |
| lcdlr_w=lcdlr_w?lcdlr_w:1; |
| lcdlr_w=(lcdlr_w*(wr_adj_per[temp_count]))/100; |
| if (temp_count == 7) |
| lcdlr_w=lcdlr_w&ACBDLR_MAX; |
| wr_reg(((uint64_t)(temp_reg)),((lcdlr_w)&ACLCDLR_MAX)); |
| } |
| |
| for (temp_count=8;temp_count<12;temp_count++) { |
| temp_reg=(unsigned)(DDR1_PUB_DX0LCDLR1+(DDR1_PUB_DX1LCDLR1-DDR1_PUB_DX0LCDLR1)*(temp_count-8)); |
| lcdlr_w=(int)((rd_reg((uint64_t)(temp_reg)))&0xff); |
| lcdlr_w=lcdlr_w?lcdlr_w:1; |
| lcdlr_r=(int)(((rd_reg((uint64_t)(temp_reg)))>>8)&0xff); |
| lcdlr_r=lcdlr_r?lcdlr_r:1; |
| lcdlr_w=(lcdlr_w*(wr_adj_per[temp_count]))/100; |
| lcdlr_r=(lcdlr_r*(rd_adj_per[temp_count]))/100; |
| wr_reg(((uint64_t)(temp_reg)),(((lcdlr_r<<16)|(lcdlr_r<<8)|(lcdlr_w)))); |
| } |
| #endif |
| |
| wr_reg(DDR0_PUB_PGCR1, (rd_reg(DDR0_PUB_PGCR1))&(~(1<<26))); |
| wr_reg(DDR0_PUB_PIR, (rd_reg(DDR0_PUB_PIR))&(~(1<<29))); |
| |
| #if 0 |
| wr_reg(DDR1_PUB_PGCR1, (rd_reg(DDR1_PUB_PGCR1))&(~(1<<26))); |
| wr_reg(DDR1_PUB_PIR, (rd_reg(DDR1_PUB_PIR))&(~(1<<29))); |
| #endif |
| |
| printf("\nEnd of adjust lcdlr\n"); |
| |
| CLOSE_CHANNEL_A_PHY_CLK(); |
| return 0; |
| } |
| |
| U_BOOT_CMD( |
| ddr_dqs, CMD_ARGV_MAX, 1, do_ddr_dqs, |
| "tune ddr dqs in uboot...", |
| "[wr0] [wr1] [wr2] [wr3] [wr4] [wr5] [rd0] [rd1] [rd2] [rd3] [rd4] [rd5]\n" |
| ); |