1 /*
2  * Copyright (C) 2012, Stefano Babic <sbabic@denx.de>
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 
23 #include <asm/io.h>
24 #include <asm/errno.h>
25 #include <asm/arch/imx-regs.h>
26 #include <linux/types.h>
27 #include <asm/arch/sys_proto.h>
28 
29 #define ESDCTL_DDR2_EMR2	0x04000000
30 #define ESDCTL_DDR2_EMR3	0x06000000
31 #define ESDCTL_PRECHARGE	0x00000400
32 #define ESDCTL_DDR2_EN_DLL	0x02000400
33 #define ESDCTL_DDR2_RESET_DLL	0x00000333
34 #define ESDCTL_DDR2_MR		0x00000233
35 #define ESDCTL_DDR2_OCD_DEFAULT 0x02000780
36 
37 enum {
38 	SMODE_NORMAL =	0,
39 	SMODE_PRECHARGE,
40 	SMODE_AUTO_REFRESH,
41 	SMODE_LOAD_REG,
42 	SMODE_MANUAL_REFRESH
43 };
44 
45 #define set_mode(x, en, m)	(x | (en << 31) | (m << 28))
46 
47 static inline void dram_wait(unsigned int count)
48 {
49 	volatile unsigned int wait = count;
50 
51 	while (wait--)
52 		;
53 
54 }
55 
56 void mx3_setup_sdram_bank(u32 start_address, u32 ddr2_config,
57 	u32 row, u32 col, u32 dsize, u32 refresh)
58 {
59 	struct esdc_regs *esdc = (struct esdc_regs *)ESDCTL_BASE_ADDR;
60 	u32 *cfg_reg, *ctl_reg;
61 	u32 val;
62 	u32 ctlval;
63 
64 	switch (start_address) {
65 	case CSD0_BASE_ADDR:
66 		cfg_reg = &esdc->esdcfg0;
67 		ctl_reg = &esdc->esdctl0;
68 		break;
69 	case CSD1_BASE_ADDR:
70 		cfg_reg = &esdc->esdcfg1;
71 		ctl_reg = &esdc->esdctl1;
72 		break;
73 	default:
74 		return;
75 	}
76 
77 	/* The MX35 supports 11 up to 14 rows */
78 	if (row < 11 || row > 14 || col < 8 || col > 10)
79 		return;
80 	ctlval = (row - 11) << 24 | (col - 8) << 20 | (dsize << 16);
81 
82 	/* Initialize MISC register for DDR2 */
83 	val = ESDC_MISC_RST | ESDC_MISC_MDDR_EN | ESDC_MISC_MDDR_DL_RST |
84 		ESDC_MISC_DDR_EN | ESDC_MISC_DDR2_EN;
85 	writel(val, &esdc->esdmisc);
86 	val &= ~(ESDC_MISC_RST | ESDC_MISC_MDDR_DL_RST);
87 	writel(val, &esdc->esdmisc);
88 
89 	/*
90 	 * according to DDR2 specs, wait a while before
91 	 * the PRECHARGE_ALL command
92 	 */
93 	dram_wait(0x20000);
94 
95 	/* Load DDR2 config and timing */
96 	writel(ddr2_config, cfg_reg);
97 
98 	/* Precharge ALL */
99 	writel(set_mode(ctlval, 1, SMODE_PRECHARGE),
100 		ctl_reg);
101 	writel(0xda, start_address + ESDCTL_PRECHARGE);
102 
103 	/* Load mode */
104 	writel(set_mode(ctlval, 1, SMODE_LOAD_REG),
105 		ctl_reg);
106 	writeb(0xda, start_address + ESDCTL_DDR2_EMR2); /* EMRS2 */
107 	writeb(0xda, start_address + ESDCTL_DDR2_EMR3); /* EMRS3 */
108 	writeb(0xda, start_address + ESDCTL_DDR2_EN_DLL); /* Enable DLL */
109 	writeb(0xda, start_address + ESDCTL_DDR2_RESET_DLL); /* Reset DLL */
110 
111 	/* Precharge ALL */
112 	writel(set_mode(ctlval, 1, SMODE_PRECHARGE),
113 		ctl_reg);
114 	writel(0xda, start_address + ESDCTL_PRECHARGE);
115 
116 	/* Set mode auto refresh : at least two refresh are required */
117 	writel(set_mode(ctlval, 1, SMODE_AUTO_REFRESH),
118 		ctl_reg);
119 	writel(0xda, start_address);
120 	writel(0xda, start_address);
121 
122 	writel(set_mode(ctlval, 1, SMODE_LOAD_REG),
123 		ctl_reg);
124 	writeb(0xda, start_address + ESDCTL_DDR2_MR);
125 	writeb(0xda, start_address + ESDCTL_DDR2_OCD_DEFAULT);
126 
127 	/* OCD mode exit */
128 	writeb(0xda, start_address + ESDCTL_DDR2_EN_DLL); /* Enable DLL */
129 
130 	/* Set normal mode */
131 	writel(set_mode(ctlval, 1, SMODE_NORMAL) | refresh,
132 		ctl_reg);
133 
134 	dram_wait(0x20000);
135 
136 	/* Do not set delay lines, only for MDDR */
137 }
138