]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/arm926ejs/mx28/spl_mem_init.c
Unified codebase for TX28, TX48, TX51, TX53
[karo-tx-uboot.git] / arch / arm / cpu / arm926ejs / mx28 / spl_mem_init.c
1 /*
2  * Freescale i.MX28 RAM init
3  *
4  * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5  * on behalf of DENX Software Engineering GmbH
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25
26 #include <common.h>
27 #include <config.h>
28 #include <asm/io.h>
29 #include <asm/arch/iomux-mx28.h>
30 #include <asm/arch/imx-regs.h>
31
32 #include "mx28_init.h"
33
34 extern void mx28_ddr2_setup(void) __attribute__((weak,
35                 alias("mx28_ddr2_setup_missing")));
36
37 static void mx28_ddr2_setup_missing(void)
38 {
39         serial_puts("platform specific mx28_ddr_setup() is missing\n");
40 }
41
42 static void mx28_mem_init_clock(void)
43 {
44         struct mx28_clkctrl_regs *clkctrl_regs =
45                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
46
47         /* Gate EMI clock */
48         writeb(CLKCTRL_FRAC_CLKGATE,
49                 &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_EMI]);
50
51         /* Set fractional divider for ref_emi to 480 * 18 / 21 = 411MHz */
52         writeb(CLKCTRL_FRAC_CLKGATE | (21 & CLKCTRL_FRAC_FRAC_MASK),
53                 &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
54
55         /* Ungate EMI clock */
56         writeb(CLKCTRL_FRAC_CLKGATE,
57                 &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_EMI]);
58
59
60         /* Set EMI clock divider for EMI clock to 411 / 2 = 205MHz */
61         writel((2 << CLKCTRL_EMI_DIV_EMI_OFFSET) |
62                 (1 << CLKCTRL_EMI_DIV_XTAL_OFFSET),
63                 &clkctrl_regs->hw_clkctrl_emi);
64         while (readl(&clkctrl_regs->hw_clkctrl_emi) & CLKCTRL_EMI_BUSY_REF_EMI)
65                 ;
66
67         /* Unbypass EMI */
68         writel(CLKCTRL_CLKSEQ_BYPASS_EMI,
69                 &clkctrl_regs->hw_clkctrl_clkseq_clr);
70 }
71
72 static void mx28_mem_setup_cpu_and_hbus(void)
73 {
74         struct mx28_clkctrl_regs *clkctrl_regs =
75                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
76
77         /* Set fractional divider for ref_cpu to 480 * 18 / 19 = 454MHz
78          * and ungate CPU clock */
79         writeb(19 & CLKCTRL_FRAC_FRAC_MASK,
80                 (uint8_t *)&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
81
82         /* Set CPU bypass */
83         writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
84                 &clkctrl_regs->hw_clkctrl_clkseq_set);
85
86         /* HBUS = 151MHz */
87         clrsetbits_le32(&clkctrl_regs->hw_clkctrl_hbus,
88                         CLKCTRL_HBUS_DIV_MASK,
89                         3 << CLKCTRL_HBUS_DIV_OFFSET);
90         while (readl(&clkctrl_regs->hw_clkctrl_hbus) & CLKCTRL_HBUS_ASM_BUSY)
91                 ;
92
93         /* CPU clock divider = 1 */
94         clrsetbits_le32(&clkctrl_regs->hw_clkctrl_cpu,
95                         CLKCTRL_CPU_DIV_CPU_MASK,
96                         1 << CLKCTRL_CPU_DIV_CPU_OFFSET);
97         while (readl(&clkctrl_regs->hw_clkctrl_cpu) & CLKCTRL_CPU_BUSY_REF_CPU)
98                 ;
99
100         /* Disable CPU bypass */
101         writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
102                 &clkctrl_regs->hw_clkctrl_clkseq_clr);
103
104         early_delay(15000);
105 }
106
107 #define HW_DIGCTRL_SCRATCH0     0x8001c280
108 #define HW_DIGCTRL_SCRATCH1     0x8001c290
109 static void data_abort_memdetect_handler(void) __attribute__((naked));
110 static void data_abort_memdetect_handler(void)
111 {
112         asm volatile("subs pc, r14, #4");
113 }
114
115 uint32_t mx28_mem_get_size(void)
116 {
117         uint32_t sz, da;
118         uint32_t *vt = (uint32_t *)0x20;
119
120         /* Replace the DABT handler. */
121         da = vt[4];
122         vt[4] = (uint32_t)data_abort_memdetect_handler;
123
124         sz = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE);
125
126         /* Restore the old DABT handler. */
127         vt[4] = da;
128
129         return sz;
130 }
131
132 void mx28_mem_init(void)
133 {
134         struct mx28_clkctrl_regs *clkctrl_regs =
135                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
136         struct mx28_pinctrl_regs *pinctrl_regs =
137                 (struct mx28_pinctrl_regs *)MXS_PINCTRL_BASE;
138
139         /* Set DDR2 mode */
140         writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2,
141                 &pinctrl_regs->hw_pinctrl_emi_ds_ctrl_set);
142
143         /* Power up PLL0 */
144         writel(CLKCTRL_PLL0CTRL0_POWER,
145                 &clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
146
147         /* enabling the PLL requires a 10µs delay before use as clk source */
148         early_delay(11);
149
150         mx28_mem_init_clock();
151
152         /*
153          * Configure the DRAM registers
154          */
155
156         /* Clear START bit from DRAM_CTL16 */
157         clrbits_le32(MXS_DRAM_BASE + 0x40, 1);
158
159         mx28_ddr2_setup();
160
161         /* Clear SREFRESH bit from DRAM_CTL17 */
162         clrbits_le32(MXS_DRAM_BASE + 0x44, 1);
163
164         /* Set START bit in DRAM_CTL16 */
165         setbits_le32(MXS_DRAM_BASE + 0x40, 1);
166
167         /* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */
168         while (!(readl(MXS_DRAM_BASE + 0xe8) & (1 << 20)))
169                 ;
170
171         mx28_mem_setup_cpu_and_hbus();
172 }