LIST "KZM9G low-level initialization routine."
LIST "Adapted from u-boot KZM9G support code."

LIST "Copyright (C) 2013 Ulrich Hecht"

LIST "This program is free software; you can redistribute it and/or modify"
LIST "it under the terms of the GNU General Public License version 2 as"
LIST "published by the Free Software Foundation."

LIST "This program is distributed in the hope that it will be useful,"
LIST "but WITHOUT ANY WARRANTY; without even the implied warranty of"
LIST "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"
LIST "GNU General Public License for more details."


LIST "Register definitions:"

LIST "Secure control register"
#define LIFEC_SEC_SRC (0xE6110008)

LIST "RWDT"
#define RWDT_BASE   (0xE6020000)
#define RWTCSRA0 (RWDT_BASE + 0x04)

LIST "HPB Semaphore Control Registers"
#define HPBSCR_BASE (0xE6000000)
#define HPBCTRL6 (HPBSCR_BASE + 0x1030)

#define SBSC1_BASE  (0xFE400000)
#define SDCR0A		(SBSC1_BASE + 0x0008)
#define SDCR1A		(SBSC1_BASE + 0x000C)
#define SDPCRA		(SBSC1_BASE + 0x0010)
#define SDCR0SA		(SBSC1_BASE + 0x0018)
#define SDCR1SA		(SBSC1_BASE + 0x001C)
#define RTCSRA		(SBSC1_BASE + 0x0020)
#define RTCORA		(SBSC1_BASE + 0x0028)
#define RTCORHA		(SBSC1_BASE + 0x002C)
#define SDWCRC0A	(SBSC1_BASE + 0x0040)
#define SDWCRC1A	(SBSC1_BASE + 0x0044)
#define SDWCR00A	(SBSC1_BASE + 0x0048)
#define SDWCR01A	(SBSC1_BASE + 0x004C)
#define SDWCR10A	(SBSC1_BASE + 0x0050)
#define SDWCR11A	(SBSC1_BASE + 0x0054)
#define SDWCR2A		(SBSC1_BASE + 0x0060)
#define SDWCRC2A	(SBSC1_BASE + 0x0064)
#define ZQCCRA		(SBSC1_BASE + 0x0068)
#define SDMRACR0A	(SBSC1_BASE + 0x0084)
#define SDMRTMPCRA	(SBSC1_BASE + 0x008C)
#define SDMRTMPMSKA	(SBSC1_BASE + 0x0094)
#define SDGENCNTA	(SBSC1_BASE + 0x009C)
#define SDDRVCR0A	(SBSC1_BASE + 0x00B4)
#define DLLCNT0A	(SBSC1_BASE + 0x0354)

#define SDMRA1  (0xFE500000)
#define SDMRA2  (0xFE5C0000)
#define SDMRA3  (0xFE504000)

#define SBSC2_BASE  (0xFB400000)
#define SDCR0B		(SBSC2_BASE + 0x0008)
#define SDCR1B		(SBSC2_BASE + 0x000C)
#define SDPCRB		(SBSC2_BASE + 0x0010)
#define SDCR0SB		(SBSC2_BASE + 0x0018)
#define SDCR1SB		(SBSC2_BASE + 0x001C)
#define RTCSRB		(SBSC2_BASE + 0x0020)
#define RTCORB		(SBSC2_BASE + 0x0028)
#define RTCORHB		(SBSC2_BASE + 0x002C)
#define SDWCRC0B	(SBSC2_BASE + 0x0040)
#define SDWCRC1B	(SBSC2_BASE + 0x0044)
#define SDWCR00B	(SBSC2_BASE + 0x0048)
#define SDWCR01B	(SBSC2_BASE + 0x004C)
#define SDWCR10B	(SBSC2_BASE + 0x0050)
#define SDWCR11B	(SBSC2_BASE + 0x0054)
#define SDPDCR0B	(SBSC2_BASE + 0x0058)
#define SDWCR2B		(SBSC2_BASE + 0x0060)
#define SDWCRC2B	(SBSC2_BASE + 0x0064)
#define ZQCCRB		(SBSC2_BASE + 0x0068)
#define SDMRACR0B	(SBSC2_BASE + 0x0084)
#define SDMRTMPCRB	(SBSC2_BASE + 0x008C)
#define SDMRTMPMSKB	(SBSC2_BASE + 0x0094)
#define SDGENCNTB	(SBSC2_BASE + 0x009C)
#define DPHYCNT0B	(SBSC2_BASE + 0x00A0)
#define DPHYCNT1B	(SBSC2_BASE + 0x00A4)
#define DPHYCNT2B	(SBSC2_BASE + 0x00A8)
#define SDDRVCR0B	(SBSC2_BASE + 0x00B4)
#define DLLCNT0B	(SBSC2_BASE + 0x0354)

#define SDMRB1  (0xFB500000)
#define SDMRB2  (0xFB5C0000)
#define SDMRB3  (0xFB504000)

#define CPG_BASE   (0xE6150000)
#define FRQCRA		(CPG_BASE + 0x0000)
#define FRQCRB		(CPG_BASE + 0x0004)
#define FRQCRD		(CPG_BASE + 0x00E4)
#define VCLKCR1		(CPG_BASE + 0x0008)
#define VCLKCR2		(CPG_BASE + 0x000C)
#define VCLKCR3		(CPG_BASE + 0x001C)
#define ZBCKCR		(CPG_BASE + 0x0010)
#define FLCKCR		(CPG_BASE + 0x0014)
#define SD0CKCR		(CPG_BASE + 0x0074)
#define SD1CKCR		(CPG_BASE + 0x0078)
#define SD2CKCR		(CPG_BASE + 0x007C)
#define FSIACKCR	(CPG_BASE + 0x0018)
#define SUBCKCR		(CPG_BASE + 0x0080)
#define SPUACKCR	(CPG_BASE + 0x0084)
#define SPUVCKCR	(CPG_BASE + 0x0094)
#define MSUCKCR		(CPG_BASE + 0x0088)
#define HSICKCR		(CPG_BASE + 0x008C)
#define FSIBCKCR	(CPG_BASE + 0x0090)
#define MFCK1CR		(CPG_BASE + 0x0098)
#define MFCK2CR		(CPG_BASE + 0x009C)
#define DSITCKCR	(CPG_BASE + 0x0060)
#define DSI0PCKCR	(CPG_BASE + 0x0064)
#define DSI1PCKCR	(CPG_BASE + 0x0068)
#define DSI0PHYCR	(CPG_BASE + 0x006C)
#define DVFSCR3		(CPG_BASE + 0x0174)
#define DVFSCR4		(CPG_BASE + 0x0178)
#define DVFSCR5		(CPG_BASE + 0x017C)
#define MPMODE		(CPG_BASE + 0x00CC)

#define PLLECR		(CPG_BASE + 0x00D0)
#define PLL0CR		(CPG_BASE + 0x00D8)
#define PLL1CR		(CPG_BASE + 0x0028)
#define PLL2CR		(CPG_BASE + 0x002C)
#define PLL3CR		(CPG_BASE + 0x00DC)
#define PLL0STPCR	(CPG_BASE + 0x00F0)
#define PLL1STPCR	(CPG_BASE + 0x00C8)
#define PLL2STPCR	(CPG_BASE + 0x00F8)
#define PLL3STPCR	(CPG_BASE + 0x00FC)
#define RMSTPCR0	(CPG_BASE + 0x0110)
#define RMSTPCR1	(CPG_BASE + 0x0114)
#define RMSTPCR2	(CPG_BASE + 0x0118)
#define RMSTPCR3	(CPG_BASE + 0x011C)
#define RMSTPCR4	(CPG_BASE + 0x0120)
#define RMSTPCR5	(CPG_BASE + 0x0124)
#define SMSTPCR0	(CPG_BASE + 0x0130)
#define SMSTPCR2	(CPG_BASE + 0x0138)
#define SMSTPCR3	(CPG_BASE + 0x013C)
#define CPGXXCR4	(CPG_BASE + 0x0150)
#define SRCR0		(CPG_BASE + 0x80A0)
#define SRCR2		(CPG_BASE + 0x80B0)
#define SRCR3		(CPG_BASE + 0x80A8)
#define VREFCR		(CPG_BASE + 0x00EC)
#define PCLKCR		(CPG_BASE + 0x1020)

#define PORT32CR (0xE6051020)
#define PORT33CR (0xE6051021)
#define PORT34CR (0xE6051022)
#define PORT35CR (0xE6051023)

LIST "DRAM initialization code:"

EW RWTCSRA0, 0xA507

ED_AND LIFEC_SEC_SRC, 0xFFFF7FFF

ED_AND SMSTPCR3,0xFFFF7FFF
ED_AND SRCR3, 0xFFFF7FFF
ED_AND SMSTPCR2,0xFFFBFFFF
ED_AND SRCR2, 0xFFFBFFFF
ED PLLECR, 0x00000000

WAIT_MASK PLLECR, 0x00000F00, 0x00000000
WAIT_MASK FRQCRB, 0x80000000, 0x00000000

ED PLL0CR, 0x2D000000
ED PLL1CR, 0x17100000
ED FRQCRB, 0x96235880
WAIT_MASK FRQCRB, 0x80000000, 0x00000000

ED FLCKCR, 0x0000000B
ED_AND SMSTPCR0, 0xFFFFFFFD

ED_AND SRCR0, 0xFFFFFFFD
ED 0xE6001628, 0x514
ED 0xE6001648, 0x514
ED 0xE6001658, 0x514
ED 0xE6001678, 0x514

ED DVFSCR4, 0x00092000
ED DVFSCR5, 0x000000DC
ED PLLECR, 0x00000000
WAIT_MASK PLLECR, 0x00000F00, 0x00000000

ED FRQCRA, 0x0012453C
ED FRQCRB, 0x80431350
WAIT_MASK FRQCRB, 0x80000000, 0x00000000
ED FRQCRD, 0x00000B0B
WAIT_MASK FRQCRD, 0x80000000, 0x00000000

ED PCLKCR, 0x00000003
ED VCLKCR1, 0x0000012F
ED VCLKCR2, 0x00000119
ED VCLKCR3, 0x00000119
ED ZBCKCR, 0x00000002
ED FLCKCR, 0x00000005
ED SD0CKCR, 0x00000080
ED SD1CKCR, 0x00000080
ED SD2CKCR, 0x00000080
ED FSIACKCR, 0x0000003F
ED FSIBCKCR, 0x0000003F
ED SUBCKCR, 0x00000080
ED SPUACKCR, 0x0000000B
ED SPUVCKCR, 0x0000000B
ED MSUCKCR, 0x0000013F
ED HSICKCR, 0x00000080
ED MFCK1CR, 0x0000003F
ED MFCK2CR, 0x0000003F
ED DSITCKCR, 0x00000107
ED DSI0PCKCR, 0x00000313
ED DSI1PCKCR, 0x0000130D
ED DSI0PHYCR, 0x2A800E0E
ED PLL0CR, 0x1E000000
ED PLL0CR, 0x2D000000
ED PLL1CR, 0x17100000
ED PLL2CR, 0x27000080
ED PLL3CR, 0x1D000000
ED PLL0STPCR, 0x00080000
ED PLL1STPCR, 0x000120C0
ED PLL2STPCR, 0x00012000
ED PLL3STPCR, 0x00000030
ED PLLECR, 0x0000000B
WAIT_MASK PLLECR, 0x00000B00, 0x00000B00

ED DVFSCR3, 0x000120F0
ED MPMODE, 0x00000020
ED VREFCR, 0x0000028A
ED RMSTPCR0, 0xE4628087
ED RMSTPCR1, 0xFFFFFFFF
ED RMSTPCR2, 0x53FFFFFF
ED RMSTPCR3, 0xFFFFFFFF
ED RMSTPCR4, 0x00800D3D
ED RMSTPCR5, 0xFFFFF3FF
ED SMSTPCR2, 0x00000000
ED SRCR2,  0x00040000
ED_AND PLLECR, 0xFFFFFFF7
WAIT_MASK PLLECR, 0x00000800, 0x00000000

LIST "set SBSC operational"
ED HPBCTRL6, 0x00000001
WAIT_MASK HPBCTRL6, 0x00000001, 0x00000001

LIST "set SBSC operating frequency"
ED FRQCRD, 0x00001414
WAIT_MASK FRQCRD, 0x80000000, 0x00000000
ED PLL3CR, 0x1D000000
ED_OR PLLECR, 0x00000008
WAIT_MASK PLLECR, 0x00000800, 0x00000800

LIST "enable DLL oscillation in DDRPHY"
ED_OR DLLCNT0A, 0x00000002

LIST "wait >= 100 ns"
ED SDGENCNTA, 0x00000005
WAIT_MASK SDGENCNTA, 0xFFFFFFFF, 0x00000000

LIST "target LPDDR2 device settings"
ED SDCR0A, 0xACC90159
ED SDCR1A, 0x00010059
ED SDWCRC0A, 0x50874114
ED SDWCRC1A, 0x33199B37
ED SDWCRC2A, 0x008F2313
ED SDWCR00A, 0x31020707
ED SDWCR01A, 0x0017040A
ED SDWCR10A, 0x31020707
ED SDWCR11A, 0x0017040A

ED SDDRVCR0A, 0x055557ff

ED SDWCR2A, 0x30000000

LIST "drive CKE high"
ED_OR SDPCRA, 0x00000080
WAIT_MASK SDPCRA, 0x00000080, 0x00000080

LIST "wait >= 200 us"
ED SDGENCNTA, 0x00002710
WAIT_MASK SDGENCNTA, 0xFFFFFFFF, 0x00000000

LIST "issue reset command to LPDDR2 device"
ED SDMRACR0A, 0x0000003F
ED SDMRA1, 0x00000000

LIST "wait >= 10 (or 1) us (docs inconsistent)"
ED SDGENCNTA, 0x000001F4
WAIT_MASK SDGENCNTA, 0xFFFFFFFF, 0x00000000

LIST "MRW ZS initialization calibration command"
ED SDMRACR0A, 0x0000FF0A
ED SDMRA3, 0x00000000

LIST "wait >= 1 us"
ED SDGENCNTA, 0x00000032
WAIT_MASK SDGENCNTA, 0xFFFFFFFF, 0x00000000

LIST "specify operating mode in LPDDR2"
ED SDMRACR0A, 0x00002201
ED SDMRA1, 0x00000000
ED SDMRACR0A, 0x00000402
ED SDMRA1, 0x00000000
ED SDMRACR0A, 0x00000203
ED SDMRA1, 0x00000000

LIST "initialize DDR interface"
ED SDMRA2, 0x00000000

LIST "temperature sensor control"
ED SDMRTMPCRA, 0x88800004
ED SDMRTMPMSKA,0x00000004

LIST "auto-refreshing control"
ED RTCORA, 0xA55A0032
ED RTCORHA, 0xA55A000C
ED RTCSRA, 0xA55A2048

ED_OR SDCR0A, 0x00000800
ED_OR SDCR1A, 0x00000400

LIST "auto ZQ calibration control"
ED ZQCCRA, 0xFFF20000

ED_OR DLLCNT0B, 0x00000002
ED SDGENCNTB, 0x00000005
WAIT_MASK SDGENCNTB, 0xFFFFFFFF, 0x00000000

ED SDCR0B, 0xACC90159
ED SDCR1B, 0x00010059
ED SDWCRC0B, 0x50874114
ED SDWCRC1B, 0x33199B37
ED SDWCRC2B, 0x008F2313
ED SDWCR00B, 0x31020707
ED SDWCR01B, 0x0017040A
ED SDWCR10B, 0x31020707
ED SDWCR11B, 0x0017040A
ED SDDRVCR0B, 0x055557ff
ED SDWCR2B, 0x30000000
ED_OR SDPCRB, 0x00000080
WAIT_MASK SDPCRB, 0x00000080, 0x00000080

ED SDGENCNTB, 0x00002710
WAIT_MASK SDGENCNTB, 0xFFFFFFFF, 0x00000000
ED SDMRACR0B, 0x0000003F

LIST "upstream u-boot writes to SDMRA1A for both SBSC 1 and 2, which does"
LIST "not seem to make a lot of sense..."
ED SDMRB1, 0x00000000

ED SDGENCNTB, 0x000001F4
WAIT_MASK SDGENCNTB, 0xFFFFFFFF, 0x00000000

ED SDMRACR0B, 0x0000FF0A
ED SDMRB3, 0x00000000
ED SDGENCNTB, 0x00000032
WAIT_MASK SDGENCNTB, 0xFFFFFFFF, 0x00000000

ED SDMRACR0B, 0x00002201
ED SDMRB1, 0x00000000
ED SDMRACR0B, 0x00000402
ED SDMRB1, 0x00000000
ED SDMRACR0B, 0x00000203
ED SDMRB1, 0x00000000
ED SDMRB2, 0x00000000
ED SDMRTMPCRB, 0x88800004
ED SDMRTMPMSKB, 0x00000004
ED RTCORB,  0xA55A0032
ED RTCORHB, 0xA55A000C
ED RTCSRB,  0xA55A2048
ED_OR SDCR0B, 0x00000800
ED_OR SDCR1B, 0x00000400
ED ZQCCRB, 0xFFF20000
ED_OR SDPDCR0B, 0x00030000
ED DPHYCNT1B, 0xA5390000
ED DPHYCNT0B, 0x00001200
ED DPHYCNT1B, 0x07CE0000
ED DPHYCNT0B, 0x00001247
WAIT_MASK DPHYCNT2B, 0xFFFFFFFF, 0x07CE0000

ED_AND SDPDCR0B, 0xFFFCFFFF

ED FRQCRD, 0x00000B0B
WAIT_MASK FRQCRD, 0x80000000, 0x00000000

ED CPGXXCR4, 0xfffffffc

LIST "Setup SCIF4 / workaround"
EB PORT32CR, 0x12
EB PORT33CR, 0x22
EB PORT34CR, 0x12
EB PORT35CR, 0x22

EW 0xE6C80000, 0
EB 0xE6C80004, 0x19
EW 0xE6C80008, 0x0030
EW 0xE6C80018, 0
EW 0xE6C80030, 0x0014

LIST "Magic to avoid hangs and corruption on DRAM writes."

LIST "It has been observed that the system would most often hang while"
LIST "decompressing the kernel, and if it didn't it would always write"
LIST "a corrupt image to DRAM."
LIST "This problem does not occur in u-boot, and the reason is that"
LIST "u-boot performs an additional cache invalidation after setting up"
LIST "the DRAM controller. Such an invalidation should not be necessary at"
LIST "this point, and attempts at removing parts of the routine to arrive"
LIST "at the minimal snippet of code necessary to avoid the DRAM stability"
LIST "problem yielded the following:"

MRC p15, 0, r0, c1, c0, 0
MCR p15, 0, r0, c1, c0, 0
