# SPDX-License-Identifier: GPL-2.0-or-later

##################################################################################
# Author: Wjatscheslaw Stoljarski (Slawa) <wjatscheslaw.stoljarski@kiwigrid.com> #
# Kiwigrid GmbH                                                                  #
##################################################################################

# The IMX53LOCO (QSB) board has a single IMX53 chip
source [find target/imx53.cfg]
# Helper for common memory read/modify/write procedures
source [find mem_helper.tcl]

echo "iMX53 Loco board lodaded."

# Set reset type
#reset_config srst_only

adapter speed 3000

# Slow speed to be sure it will work
jtag_rclk 1000
$_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 }

#adapter srst delay 200
#jtag_ntrst_delay 200

$_TARGETNAME configure -event "reset-assert" {
	echo "Resetting ...."
	#cortex_a dbginit
}

$_TARGETNAME configure -event reset-init { loco_init }

global AIPS1_BASE_ADDR
set AIPS1_BASE_ADDR     0x53F00000
global AIPS2_BASE_ADDR
set AIPS2_BASE_ADDR     0x63F00000

proc loco_init { } {
	echo "Reset-init..."
	; # halt the CPU
	halt

	echo "HW version [format %x [mrw 0x48]]"

	dap apsel 1
	DCD

	; # ARM errata ID #468414
	set tR [arm mrc 15 0 1 0 1]
	arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}]	; # enable L1NEON bit

	init_l2cc
	init_aips
	init_clock

	dap apsel 0

	; # Force ARM state
	; #reg cpsr 0x000001D3
	arm core_state arm

	jtag_rclk 3000
#	adapter speed 3000
}


# L2CC Cache setup/invalidation/disable
proc init_l2cc { } {
	; #/* explicitly disable L2 cache */
	; #mrc 15, 0, r0, c1, c0, 1
	set tR [arm mrc 15 0 1 0 1]
	; #bic r0, r0, #0x2
	; #mcr 15, 0, r0, c1, c0, 1
	arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}]

	; #/* reconfigure L2 cache aux control reg */
	; #mov r0, #0xC0                   /* tag RAM */
	; #add r0, r0, #0x4                /* data RAM */
	; #orr r0, r0, #(1 << 24)          /* disable write allocate delay */
	; #orr r0, r0, #(1 << 23)          /* disable write allocate combine */
	; #orr r0, r0, #(1 << 22)          /* disable write allocate */

	; #mcr 15, 1, r0, c9, c0, 2
	arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}]
}


# AIPS setup - Only setup MPROTx registers.
# The PACR default values are good.
proc init_aips { } {
	; # Set all MPROTx to be non-bufferable, trusted for R/W,
	; # not forced to user-mode.
	global AIPS1_BASE_ADDR
	global AIPS2_BASE_ADDR
	set VAL			0x77777777

#	dap apsel 1
	mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL
	mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL
	mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL
	mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL
#	dap apsel 0
}


proc init_clock { } {
	global AIPS1_BASE_ADDR
	global AIPS2_BASE_ADDR
	set CCM_BASE_ADDR	[expr {$AIPS1_BASE_ADDR + 0x000D4000}]
	set CLKCTL_CCSR         0x0C
	set CLKCTL_CBCDR	0x14
	set CLKCTL_CBCMR        0x18
	set PLL1_BASE_ADDR	[expr {$AIPS2_BASE_ADDR + 0x00080000}]
	set PLL2_BASE_ADDR	[expr {$AIPS2_BASE_ADDR + 0x00084000}]
	set PLL3_BASE_ADDR	[expr {$AIPS2_BASE_ADDR + 0x00088000}]
	set PLL4_BASE_ADDR	[expr {$AIPS2_BASE_ADDR + 0x0008C000}]
	set CLKCTL_CSCMR1	0x1C
	set CLKCTL_CDHIPR	0x48
	set PLATFORM_BASE_ADDR	[expr {$AIPS2_BASE_ADDR + 0x000A0000}]
	set CLKCTL_CSCDR1	0x24
	set CLKCTL_CCDR		0x04

	; # Switch ARM to step clock
	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4

	return
	echo "not returned"
	setup_pll $PLL1_BASE_ADDR 800
	setup_pll $PLL3_BASE_ADDR 400

	; # Switch peripheral to PLL3
	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154
	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}]
	while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 }

	setup_pll $PLL2_BASE_ADDR 400

	; # Switch peripheral to PLL2
	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}]

	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154

	; # change uart clk parent to pll2
	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}]

	; # make sure change is effective
	while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 }

	setup_pll $PLL3_BASE_ADDR 216

	setup_pll $PLL4_BASE_ADDR 455

	; # Set the platform clock dividers
	mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124

	mww [expr {$CCM_BASE_ADDR + 0x10}] 0

	; # Switch ARM back to PLL 1.
	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0

	; # make uart div=6
	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}]

	; # Restore the default values in the Gate registers
	mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF
	mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF
	mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF
	mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF
	mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF
	mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF
	mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF
	mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF

	mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000

	; # for cko - for ARM div by 8
	mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}]
}


proc setup_pll { PLL_ADDR CLK } {
	set PLL_DP_CTL		0x00
	set PLL_DP_CONFIG   	0x04
	set PLL_DP_OP		0x08
	set PLL_DP_HFS_OP	0x1C
	set PLL_DP_MFD		0x0C
	set PLL_DP_HFS_MFD	0x20
	set PLL_DP_MFN		0x10
	set PLL_DP_HFS_MFN	0x24

	if {$CLK == 1000} {
		set DP_OP	[expr {(10 << 4) + ((1 - 1) << 0)}]
		set DP_MFD	[expr {12 - 1}]
		set DP_MFN	5
	} elseif {$CLK == 850} {
		set DP_OP	[expr {(8 << 4) + ((1 - 1)  << 0)}]
		set DP_MFD	[expr {48 - 1}]
		set DP_MFN	41
	} elseif {$CLK == 800} {
		set DP_OP	[expr {(8 << 4) + ((1 - 1)  << 0)}]
		set DP_MFD	[expr {3 - 1}]
		set DP_MFN	1
	} elseif {$CLK == 700} {
		set DP_OP	[expr {(7 << 4) + ((1 - 1)  << 0)}]
		set DP_MFD	[expr {24 - 1}]
		set DP_MFN	7
	} elseif {$CLK == 600} {
		set DP_OP	[expr {(6 << 4) + ((1 - 1)  << 0)}]
		set DP_MFD	[expr {4 - 1}]
		set DP_MFN	1
	} elseif {$CLK == 665} {
		set DP_OP	[expr {(6 << 4) + ((1 - 1)  << 0)}]
		set DP_MFD	[expr {96 - 1}]
		set DP_MFN	89
	} elseif {$CLK == 532} {
		set DP_OP	[expr {(5 << 4) + ((1 - 1)  << 0)}]
		set DP_MFD	[expr {24 - 1}]
		set DP_MFN	13
	} elseif {$CLK == 455} {
		set DP_OP	[expr {(8 << 4) + ((2 - 1)  << 0)}]
		set DP_MFD	[expr {48 - 1}]
		set DP_MFN	71
	} elseif {$CLK == 400} {
		set DP_OP	[expr {(8 << 4) + ((2 - 1)  << 0)}]
		set DP_MFD	[expr {3 - 1}]
		set DP_MFN	1
	} elseif {$CLK == 216} {
		set DP_OP	[expr {(6 << 4) + ((3 - 1)  << 0)}]
		set DP_MFD	[expr {4 - 1}]
		set DP_MFN	3
	} else {
		error "Error (setup_dll): clock not found!"
	}

	mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232
	mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2

	mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP
	mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP

	mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD
	mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD

	mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN
	mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN

	mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232
	while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 }
}


proc CPU_2_BE_32 { L } {
	return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8)  | (($L & 0xFF000000) >> 24)}]
}


# Device Configuration Data
proc DCD { } {
#	dap apsel 1
	mww 0x53FA8554 0x00300000	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM3
	mww 0x53FA8558 0x00300040	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3
	mww 0x53FA8560 0x00300000	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM2
	mww 0x53FA8564 0x00300040	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT
	mww 0x53FA8568 0x00300040	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2
	mww 0x53FA8570 0x00300000	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_1
	mww 0x53FA8574 0x00300000	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS
	mww 0x53FA8578 0x00300000	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0
	mww 0x53FA857c 0x00300040	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0
	mww 0x53FA8580 0x00300040	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0
	mww 0x53FA8584 0x00300000	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0
	mww 0x53FA8588 0x00300000	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS
	mww 0x53FA8590 0x00300040	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1
	mww 0x53FA8594 0x00300000	;# IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1
	mww 0x53FA86f0 0x00300000	;# IOMUXC_SW_PAD_CTL_GRP_ADDDS
	mww 0x53FA86f4 0x00000000	;# IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL
	mww 0x53FA86fc 0x00000000	;# IOMUXC_SW_PAD_CTL_GRP_DDRPKE
	mww 0x53FA8714 0x00000000	;# IOMUXC_SW_PAD_CTL_GRP_DDRMODE - CMOS mode
	mww 0x53FA8718 0x00300000	;# IOMUXC_SW_PAD_CTL_GRP_B0DS
	mww 0x53FA871c 0x00300000	;# IOMUXC_SW_PAD_CTL_GRP_B1DS
	mww 0x53FA8720 0x00300000	;# IOMUXC_SW_PAD_CTL_GRP_CTLDS
	mww 0x53FA8724 0x04000000	;# IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE - DDR_SEL0=
	mww 0x53FA8728 0x00300000	;# IOMUXC_SW_PAD_CTL_GRP_B2DS
	mww 0x53FA872c 0x00300000	;# IOMUXC_SW_PAD_CTL_GRP_B3DS

	# Initialize DDR2 memory
	mww 0x63FD9088 0x35343535	;# ESDCTL_RDDLCTL
	mww 0x63FD9090 0x4d444c44	;# ESDCTL_WRDLCTL
	mww 0x63FD907c 0x01370138	;# ESDCTL_DGCTRL0
	mww 0x63FD9080 0x013b013c	;# ESDCTL_DGCTRL1
	mww 0x63FD9018 0x00011740	;# ESDCTL_ESDMISC
	mww 0x63FD9000 0xc3190000	;# ESDCTL_ESDCTL
	mww 0x63FD900c 0x9f5152e3	;# ESDCTL_ESDCFG0
	mww 0x63FD9010 0xb68e8a63	;# ESDCTL_ESDCFG1
	mww 0x63FD9014 0x01ff00db	;# ESDCTL_ESDCFG2
	mww 0x63FD902c 0x000026d2	;# ESDCTL_ESDRWD
	mww 0x63FD9030 0x009f0e21	;# ESDCTL_ESDOR
	mww 0x63FD9008 0x12273030	;# ESDCTL_ESDOTC
	mww 0x63FD9004 0x0002002d	;# ESDCTL_ESDPDC
	mww 0x63FD901c 0x00008032	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x00008033	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x00028031	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x052080b0	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x04008040	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x0000803a	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x0000803b	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x00028039	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x05208138	;# ESDCTL_ESDSCR
	mww 0x63FD901c 0x04008048	;# ESDCTL_ESDSCR
	mww 0x63FD9020 0x00005800	;# ESDCTL_ESDREF
	mww 0x63FD9040 0x04b80003	;# ESDCTL_ZQHWCTRL
	mww 0x63FD9058 0x00022227	;# ESDCTL_ODTCTRL
	mww 0x63FD901C 0x00000000	;# ESDCTL_ESDSCR
#	dap apsel 0
}

# vim:filetype=tcl