commit
08ca213aca
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
/dts-v1/; |
||||
#include "ar933x.dtsi" |
||||
|
||||
/ { |
||||
model = "AP121 Reference Board"; |
||||
compatible = "qca,ap121", "qca,ar933x"; |
||||
|
||||
aliases { |
||||
spi0 = &spi0; |
||||
serial0 = &uart0; |
||||
}; |
||||
|
||||
chosen { |
||||
stdout-path = "serial0:115200n8"; |
||||
}; |
||||
}; |
||||
|
||||
&xtal { |
||||
clock-frequency = <25000000>; |
||||
}; |
||||
|
||||
&uart0 { |
||||
status = "okay"; |
||||
}; |
||||
|
||||
&spi0 { |
||||
spi-max-frequency = <25000000>; |
||||
status = "okay"; |
||||
spi-flash@0 { |
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
compatible = "spi-flash"; |
||||
memory-map = <0x9f000000 0x00800000>; |
||||
spi-max-frequency = <25000000>; |
||||
reg = <0>; |
||||
}; |
||||
}; |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
/dts-v1/; |
||||
#include "qca953x.dtsi" |
||||
|
||||
/ { |
||||
model = "AP143 Reference Board"; |
||||
compatible = "qca,ap143", "qca,qca953x"; |
||||
|
||||
aliases { |
||||
spi0 = &spi0; |
||||
serial0 = &uart0; |
||||
}; |
||||
|
||||
chosen { |
||||
stdout-path = "serial0:115200n8"; |
||||
}; |
||||
}; |
||||
|
||||
&xtal { |
||||
clock-frequency = <25000000>; |
||||
}; |
||||
|
||||
&uart0 { |
||||
status = "okay"; |
||||
}; |
||||
|
||||
&spi0 { |
||||
spi-max-frequency = <25000000>; |
||||
status = "okay"; |
||||
spi-flash@0 { |
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
compatible = "spi-flash"; |
||||
memory-map = <0x9f000000 0x00800000>; |
||||
spi-max-frequency = <25000000>; |
||||
reg = <0>; |
||||
}; |
||||
}; |
@ -0,0 +1,115 @@ |
||||
/* |
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <dt-bindings/interrupt-controller/irq.h> |
||||
#include "skeleton.dtsi" |
||||
|
||||
/ { |
||||
compatible = "qca,ar933x"; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
cpus { |
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
|
||||
cpu@0 { |
||||
device_type = "cpu"; |
||||
compatible = "mips,mips24Kc"; |
||||
reg = <0>; |
||||
}; |
||||
}; |
||||
|
||||
clocks { |
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
ranges; |
||||
|
||||
xtal: xtal { |
||||
#clock-cells = <0>; |
||||
compatible = "fixed-clock"; |
||||
clock-output-names = "xtal"; |
||||
}; |
||||
}; |
||||
|
||||
pinctrl { |
||||
u-boot,dm-pre-reloc; |
||||
compatible = "qca,ar933x-pinctrl"; |
||||
ranges; |
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
reg = <0x18040000 0x100>; |
||||
}; |
||||
|
||||
ahb { |
||||
compatible = "simple-bus"; |
||||
ranges; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
apb { |
||||
compatible = "simple-bus"; |
||||
ranges; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
ehci0: ehci@1b000100 { |
||||
compatible = "generic-ehci"; |
||||
reg = <0x1b000100 0x100>; |
||||
|
||||
status = "disabled"; |
||||
}; |
||||
|
||||
uart0: uart@18020000 { |
||||
compatible = "qca,ar9330-uart"; |
||||
reg = <0x18020000 0x20>; |
||||
interrupts = <128 IRQ_TYPE_LEVEL_HIGH>; |
||||
|
||||
status = "disabled"; |
||||
}; |
||||
|
||||
gmac0: eth@0x19000000 { |
||||
compatible = "qca,ag7240-mac"; |
||||
reg = <0x19000000 0x200>; |
||||
phy = <&phy0>; |
||||
phy-mode = "rmii"; |
||||
|
||||
status = "disabled"; |
||||
|
||||
mdio { |
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
phy0: ethernet-phy@0 { |
||||
reg = <0>; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
gmac1: eth@0x1a000000 { |
||||
compatible = "qca,ag7240-mac"; |
||||
reg = <0x1a000000 0x200>; |
||||
phy = <&phy0>; |
||||
phy-mode = "rgmii"; |
||||
|
||||
status = "disabled"; |
||||
}; |
||||
}; |
||||
|
||||
spi0: spi@1f000000 { |
||||
compatible = "qca,ar7100-spi"; |
||||
reg = <0x1f000000 0x10>; |
||||
interrupts = <129 IRQ_TYPE_LEVEL_HIGH>; |
||||
|
||||
status = "disabled"; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
}; |
||||
}; |
||||
}; |
@ -0,0 +1,112 @@ |
||||
/* |
||||
* Copyright (C) 2016 Marek Vasut <marex@denx.de> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include "skeleton.dtsi" |
||||
|
||||
/ { |
||||
compatible = "qca,ar934x"; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
cpus { |
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
|
||||
cpu@0 { |
||||
device_type = "cpu"; |
||||
compatible = "mips,mips74Kc"; |
||||
reg = <0>; |
||||
}; |
||||
}; |
||||
|
||||
clocks { |
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
ranges; |
||||
|
||||
xtal: xtal { |
||||
#clock-cells = <0>; |
||||
compatible = "fixed-clock"; |
||||
clock-output-names = "xtal"; |
||||
}; |
||||
}; |
||||
|
||||
ahb { |
||||
compatible = "simple-bus"; |
||||
ranges; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
apb { |
||||
compatible = "simple-bus"; |
||||
ranges; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
ehci0: ehci@1b000100 { |
||||
compatible = "generic-ehci"; |
||||
reg = <0x1b000100 0x100>; |
||||
|
||||
status = "disabled"; |
||||
}; |
||||
|
||||
uart0: uart@18020000 { |
||||
compatible = "ns16550"; |
||||
reg = <0x18020000 0x20>; |
||||
reg-shift = <2>; |
||||
|
||||
status = "disabled"; |
||||
}; |
||||
|
||||
gmac0: eth@0x19000000 { |
||||
compatible = "qca,ag934x-mac"; |
||||
reg = <0x19000000 0x200>; |
||||
phy = <&phy0>; |
||||
phy-mode = "rgmii"; |
||||
|
||||
status = "disabled"; |
||||
|
||||
mdio { |
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
phy0: ethernet-phy@0 { |
||||
reg = <0>; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
gmac1: eth@0x1a000000 { |
||||
compatible = "qca,ag934x-mac"; |
||||
reg = <0x1a000000 0x200>; |
||||
phy = <&phy1>; |
||||
phy-mode = "rgmii"; |
||||
|
||||
status = "disabled"; |
||||
|
||||
mdio { |
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
phy1: ethernet-phy@0 { |
||||
reg = <0>; |
||||
}; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
spi0: spi@1f000000 { |
||||
compatible = "qca,ar7100-spi"; |
||||
reg = <0x1f000000 0x10>; |
||||
|
||||
status = "disabled"; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
}; |
||||
}; |
||||
}; |
@ -0,0 +1,84 @@ |
||||
/* |
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <dt-bindings/interrupt-controller/irq.h> |
||||
#include "skeleton.dtsi" |
||||
|
||||
/ { |
||||
compatible = "qca,qca953x"; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
cpus { |
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
|
||||
cpu@0 { |
||||
device_type = "cpu"; |
||||
compatible = "mips,mips24Kc"; |
||||
reg = <0>; |
||||
}; |
||||
}; |
||||
|
||||
clocks { |
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
ranges; |
||||
|
||||
xtal: xtal { |
||||
#clock-cells = <0>; |
||||
compatible = "fixed-clock"; |
||||
clock-output-names = "xtal"; |
||||
}; |
||||
}; |
||||
|
||||
pinctrl { |
||||
u-boot,dm-pre-reloc; |
||||
compatible = "qca,qca953x-pinctrl"; |
||||
ranges; |
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
reg = <0x18040000 0x100>; |
||||
}; |
||||
|
||||
ahb { |
||||
compatible = "simple-bus"; |
||||
ranges; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
apb { |
||||
compatible = "simple-bus"; |
||||
ranges; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
|
||||
uart0: uart@18020000 { |
||||
compatible = "ns16550"; |
||||
reg = <0x18020000 0x20>; |
||||
reg-shift = <2>; |
||||
clock-frequency = <25000000>; |
||||
interrupts = <128 IRQ_TYPE_LEVEL_HIGH>; |
||||
|
||||
status = "disabled"; |
||||
}; |
||||
}; |
||||
|
||||
spi0: spi@1f000000 { |
||||
compatible = "qca,ar7100-spi"; |
||||
reg = <0x1f000000 0x10>; |
||||
interrupts = <129 IRQ_TYPE_LEVEL_HIGH>; |
||||
|
||||
status = "disabled"; |
||||
|
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
}; |
||||
}; |
||||
}; |
@ -0,0 +1,53 @@ |
||||
/* |
||||
* Copyright (C) 2016 Marek Vasut <marex@denx.de> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
/dts-v1/; |
||||
#include "ar934x.dtsi" |
||||
|
||||
/ { |
||||
model = "TP-Link WDR4300 Board"; |
||||
compatible = "tplink,wdr4300", "qca,ar934x"; |
||||
|
||||
aliases { |
||||
serial0 = &uart0; |
||||
spi0 = &spi0; |
||||
}; |
||||
|
||||
chosen { |
||||
stdout-path = "serial0:115200n8"; |
||||
}; |
||||
}; |
||||
|
||||
&ehci0 { |
||||
status = "okay"; |
||||
}; |
||||
|
||||
&gmac0 { |
||||
phy-mode = "rgmii"; |
||||
status = "okay"; |
||||
}; |
||||
|
||||
&spi0 { |
||||
spi-max-frequency = <25000000>; |
||||
status = "okay"; |
||||
spi-flash@0 { |
||||
#address-cells = <1>; |
||||
#size-cells = <1>; |
||||
compatible = "spi-flash"; |
||||
memory-map = <0x1e000000 0x00800000>; |
||||
spi-max-frequency = <25000000>; |
||||
reg = <0>; |
||||
}; |
||||
}; |
||||
|
||||
&uart0 { |
||||
clock-frequency = <40000000>; |
||||
status = "okay"; |
||||
}; |
||||
|
||||
&xtal { |
||||
clock-frequency = <40000000>; |
||||
}; |
@ -0,0 +1,55 @@ |
||||
menu "QCA/Atheros 7xxx/9xxx platforms" |
||||
depends on ARCH_ATH79 |
||||
|
||||
config SYS_SOC |
||||
default "ath79" |
||||
|
||||
config SOC_AR933X |
||||
bool |
||||
select SUPPORTS_BIG_ENDIAN |
||||
select SUPPORTS_CPU_MIPS32_R1 |
||||
select SUPPORTS_CPU_MIPS32_R2 |
||||
select MIPS_TUNE_24KC |
||||
help |
||||
This supports QCA/Atheros ar933x family SOCs. |
||||
|
||||
config SOC_AR934X |
||||
bool |
||||
select SUPPORTS_BIG_ENDIAN |
||||
select SUPPORTS_CPU_MIPS32_R1 |
||||
select SUPPORTS_CPU_MIPS32_R2 |
||||
select MIPS_TUNE_74KC |
||||
help |
||||
This supports QCA/Atheros ar934x family SOCs. |
||||
|
||||
config SOC_QCA953X |
||||
bool |
||||
select SUPPORTS_BIG_ENDIAN |
||||
select SUPPORTS_CPU_MIPS32_R1 |
||||
select SUPPORTS_CPU_MIPS32_R2 |
||||
select MIPS_TUNE_24KC |
||||
help |
||||
This supports QCA/Atheros qca953x family SOCs. |
||||
|
||||
choice |
||||
prompt "Board select" |
||||
|
||||
config TARGET_AP121 |
||||
bool "AP121 Reference Board" |
||||
select SOC_AR933X |
||||
|
||||
config TARGET_AP143 |
||||
bool "AP143 Reference Board" |
||||
select SOC_QCA953X |
||||
|
||||
config BOARD_TPLINK_WDR4300 |
||||
bool "TP-Link WDR4300 Board" |
||||
select SOC_AR934X |
||||
|
||||
endchoice |
||||
|
||||
source "board/qca/ap121/Kconfig" |
||||
source "board/qca/ap143/Kconfig" |
||||
source "board/tplink/wdr4300/Kconfig" |
||||
|
||||
endmenu |
@ -0,0 +1,11 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += reset.o
|
||||
obj-y += cpu.o
|
||||
obj-y += dram.o
|
||||
|
||||
obj-$(CONFIG_SOC_AR933X) += ar933x/
|
||||
obj-$(CONFIG_SOC_AR934X) += ar934x/
|
||||
obj-$(CONFIG_SOC_QCA953X) += qca953x/
|
@ -0,0 +1,7 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += clk.o
|
||||
obj-y += ddr.o
|
||||
obj-y += lowlevel_init.o
|
@ -0,0 +1,89 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/reset.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
static u32 ar933x_get_xtal(void) |
||||
{ |
||||
u32 val; |
||||
|
||||
val = get_bootstrap(); |
||||
if (val & AR933X_BOOTSTRAP_REF_CLK_40) |
||||
return 40000000; |
||||
else |
||||
return 25000000; |
||||
} |
||||
|
||||
int get_serial_clock(void) |
||||
{ |
||||
return ar933x_get_xtal(); |
||||
} |
||||
|
||||
int get_clocks(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 val, xtal, pll, div; |
||||
|
||||
regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE, |
||||
MAP_NOCACHE); |
||||
xtal = ar933x_get_xtal(); |
||||
val = readl(regs + AR933X_PLL_CPU_CONFIG_REG); |
||||
|
||||
/* VCOOUT = XTAL * DIV_INT */ |
||||
div = (val >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) |
||||
& AR933X_PLL_CPU_CONFIG_REFDIV_MASK; |
||||
pll = xtal / div; |
||||
|
||||
/* PLLOUT = VCOOUT * (1/2^OUTDIV) */ |
||||
div = (val >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) |
||||
& AR933X_PLL_CPU_CONFIG_NINT_MASK; |
||||
pll *= div; |
||||
div = (val >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) |
||||
& AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; |
||||
if (!div) |
||||
div = 1; |
||||
pll >>= div; |
||||
|
||||
val = readl(regs + AR933X_PLL_CLK_CTRL_REG); |
||||
|
||||
/* CPU_CLK = PLLOUT / CPU_POST_DIV */ |
||||
div = ((val >> AR933X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) |
||||
& AR933X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1; |
||||
gd->cpu_clk = pll / div; |
||||
|
||||
/* DDR_CLK = PLLOUT / DDR_POST_DIV */ |
||||
div = ((val >> AR933X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) |
||||
& AR933X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1; |
||||
gd->mem_clk = pll / div; |
||||
|
||||
/* AHB_CLK = PLLOUT / AHB_POST_DIV */ |
||||
div = ((val >> AR933X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) |
||||
& AR933X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1; |
||||
gd->bus_clk = pll / div; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
ulong get_bus_freq(ulong dummy) |
||||
{ |
||||
if (!gd->bus_clk) |
||||
get_clocks(); |
||||
return gd->bus_clk; |
||||
} |
||||
|
||||
ulong get_ddr_freq(ulong dummy) |
||||
{ |
||||
if (!gd->mem_clk) |
||||
get_clocks(); |
||||
return gd->mem_clk; |
||||
} |
@ -0,0 +1,333 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* Based on Atheros LSDK/QSDK |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/reset.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
#define DDR_CTRL_UPD_EMR3S BIT(5) |
||||
#define DDR_CTRL_UPD_EMR2S BIT(4) |
||||
#define DDR_CTRL_PRECHARGE BIT(3) |
||||
#define DDR_CTRL_AUTO_REFRESH BIT(2) |
||||
#define DDR_CTRL_UPD_EMRS BIT(1) |
||||
#define DDR_CTRL_UPD_MRS BIT(0) |
||||
|
||||
#define DDR_REFRESH_EN BIT(14) |
||||
#define DDR_REFRESH_M 0x3ff |
||||
#define DDR_REFRESH(x) ((x) & 0x3ff) |
||||
#define DDR_REFRESH_VAL_25M (DDR_REFRESH_EN | DDR_REFRESH(390)) |
||||
#define DDR_REFRESH_VAL_40M (DDR_REFRESH_EN | DDR_REFRESH(624)) |
||||
|
||||
#define DDR_TRAS_S 0 |
||||
#define DDR_TRAS_M 0x1f |
||||
#define DDR_TRAS(x) ((x) << DDR_TRAS_S) |
||||
#define DDR_TRCD_M 0xf |
||||
#define DDR_TRCD_S 5 |
||||
#define DDR_TRCD(x) ((x) << DDR_TRCD_S) |
||||
#define DDR_TRP_M 0xf |
||||
#define DDR_TRP_S 9 |
||||
#define DDR_TRP(x) ((x) << DDR_TRP_S) |
||||
#define DDR_TRRD_M 0xf |
||||
#define DDR_TRRD_S 13 |
||||
#define DDR_TRRD(x) ((x) << DDR_TRRD_S) |
||||
#define DDR_TRFC_M 0x7f |
||||
#define DDR_TRFC_S 17 |
||||
#define DDR_TRFC(x) ((x) << DDR_TRFC_S) |
||||
#define DDR_TMRD_M 0xf |
||||
#define DDR_TMRD_S 23 |
||||
#define DDR_TMRD(x) ((x) << DDR_TMRD_S) |
||||
#define DDR_CAS_L_M 0x17 |
||||
#define DDR_CAS_L_S 27 |
||||
#define DDR_CAS_L(x) (((x) & DDR_CAS_L_M) << DDR_CAS_L_S) |
||||
#define DDR_OPEN BIT(30) |
||||
#define DDR_CONF_REG_VAL (DDR_TRAS(16) | DDR_TRCD(6) | \ |
||||
DDR_TRP(6) | DDR_TRRD(4) | \
|
||||
DDR_TRFC(30) | DDR_TMRD(15) | \
|
||||
DDR_CAS_L(7) | DDR_OPEN) |
||||
|
||||
#define DDR_BURST_LEN_S 0 |
||||
#define DDR_BURST_LEN_M 0xf |
||||
#define DDR_BURST_LEN(x) ((x) << DDR_BURST_LEN_S) |
||||
#define DDR_BURST_TYPE BIT(4) |
||||
#define DDR_CNTL_OE_EN BIT(5) |
||||
#define DDR_PHASE_SEL BIT(6) |
||||
#define DDR_CKE BIT(7) |
||||
#define DDR_TWR_S 8 |
||||
#define DDR_TWR_M 0xf |
||||
#define DDR_TWR(x) ((x) << DDR_TWR_S) |
||||
#define DDR_TRTW_S 12 |
||||
#define DDR_TRTW_M 0x1f |
||||
#define DDR_TRTW(x) ((x) << DDR_TRTW_S) |
||||
#define DDR_TRTP_S 17 |
||||
#define DDR_TRTP_M 0xf |
||||
#define DDR_TRTP(x) ((x) << DDR_TRTP_S) |
||||
#define DDR_TWTR_S 21 |
||||
#define DDR_TWTR_M 0x1f |
||||
#define DDR_TWTR(x) ((x) << DDR_TWTR_S) |
||||
#define DDR_G_OPEN_L_S 26 |
||||
#define DDR_G_OPEN_L_M 0xf |
||||
#define DDR_G_OPEN_L(x) ((x) << DDR_G_OPEN_L_S) |
||||
#define DDR_HALF_WIDTH_LOW BIT(31) |
||||
#define DDR_CONF2_REG_VAL (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \ |
||||
DDR_CKE | DDR_TWR(6) | DDR_TRTW(14) | \
|
||||
DDR_TRTP(8) | DDR_TWTR(14) | \
|
||||
DDR_G_OPEN_L(7) | DDR_HALF_WIDTH_LOW) |
||||
|
||||
#define DDR2_CONF_TWL_S 10 |
||||
#define DDR2_CONF_TWL_M 0xf |
||||
#define DDR2_CONF_TWL(x) (((x) & DDR2_CONF_TWL_M) << DDR2_CONF_TWL_S) |
||||
#define DDR2_CONF_ODT BIT(9) |
||||
#define DDR2_CONF_TFAW_S 2 |
||||
#define DDR2_CONF_TFAW_M 0x3f |
||||
#define DDR2_CONF_TFAW(x) (((x) & DDR2_CONF_TFAW_M) << DDR2_CONF_TFAW_S) |
||||
#define DDR2_CONF_EN BIT(0) |
||||
#define DDR2_CONF_VAL (DDR2_CONF_TWL(2) | DDR2_CONF_ODT | \ |
||||
DDR2_CONF_TFAW(22) | DDR2_CONF_EN) |
||||
|
||||
#define DDR1_EXT_MODE_VAL 0x02 |
||||
#define DDR2_EXT_MODE_VAL 0x402 |
||||
#define DDR2_EXT_MODE_OCD_VAL 0x382 |
||||
#define DDR1_MODE_DLL_VAL 0x133 |
||||
#define DDR2_MODE_DLL_VAL 0x100 |
||||
#define DDR1_MODE_VAL 0x33 |
||||
#define DDR2_MODE_VAL 0xa33 |
||||
#define DDR_TAP_VAL0 0x08 |
||||
#define DDR_TAP_VAL1 0x09 |
||||
|
||||
void ddr_init(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 val; |
||||
|
||||
regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
writel(DDR_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG); |
||||
writel(DDR_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2); |
||||
|
||||
val = get_bootstrap(); |
||||
if (val & AR933X_BOOTSTRAP_DDR2) { |
||||
/* AHB maximum timeout */ |
||||
writel(0xfffff, regs + AR933X_DDR_REG_TIMEOUT_MAX); |
||||
|
||||
/* Enable DDR2 */ |
||||
writel(DDR2_CONF_VAL, regs + AR933X_DDR_REG_DDR2_CONFIG); |
||||
|
||||
/* Precharge All */ |
||||
writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Disable High Temperature Self-Refresh, Full Array */ |
||||
writel(0x00, regs + AR933X_DDR_REG_EMR2); |
||||
|
||||
/* Extended Mode Register 2 Set (EMR2S) */ |
||||
writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
writel(0x00, regs + AR933X_DDR_REG_EMR3); |
||||
|
||||
/* Extended Mode Register 3 Set (EMR3S) */ |
||||
writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Enable DLL, Full strength, ODT Disabled */ |
||||
writel(0x00, regs + AR71XX_DDR_REG_EMR); |
||||
|
||||
/* Extended Mode Register Set (EMRS) */ |
||||
writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Reset DLL */ |
||||
writel(DDR2_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE); |
||||
|
||||
/* Mode Register Set (MRS) */ |
||||
writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Precharge All */ |
||||
writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Auto Refresh */ |
||||
writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL); |
||||
writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Write recovery (WR) 6 clock, CAS Latency 3, Burst Length 8 */ |
||||
writel(DDR2_MODE_VAL, regs + AR71XX_DDR_REG_MODE); |
||||
/* Mode Register Set (MRS) */ |
||||
writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Enable OCD defaults, Enable DLL, Reduced Drive Strength */ |
||||
writel(DDR2_EXT_MODE_OCD_VAL, regs + AR71XX_DDR_REG_EMR); |
||||
|
||||
/* Extended Mode Register Set (EMRS) */ |
||||
writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* OCD exit, Enable DLL, Enable /DQS, Reduced Drive Strength */ |
||||
writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR); |
||||
/* Extended Mode Register Set (EMRS) */ |
||||
writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Refresh time control */ |
||||
if (val & AR933X_BOOTSTRAP_REF_CLK_40) |
||||
writel(DDR_REFRESH_VAL_40M, regs + |
||||
AR71XX_DDR_REG_REFRESH); |
||||
else |
||||
writel(DDR_REFRESH_VAL_25M, regs + |
||||
AR71XX_DDR_REG_REFRESH); |
||||
|
||||
/* DQS 0 Tap Control */ |
||||
writel(DDR_TAP_VAL0, regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
|
||||
/* DQS 1 Tap Control */ |
||||
writel(DDR_TAP_VAL1, regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
|
||||
/* For 16-bit DDR */ |
||||
writel(0xff, regs + AR71XX_DDR_REG_RD_CYCLE); |
||||
} else { |
||||
/* AHB maximum timeout */ |
||||
writel(0xfffff, regs + AR933X_DDR_REG_TIMEOUT_MAX); |
||||
|
||||
/* Precharge All */ |
||||
writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Reset DLL, Burst Length 8, CAS Latency 3 */ |
||||
writel(DDR1_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE); |
||||
|
||||
/* Forces an MRS update cycle in DDR */ |
||||
writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Enable DLL, Full strength */ |
||||
writel(DDR1_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR); |
||||
|
||||
/* Extended Mode Register Set (EMRS) */ |
||||
writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Precharge All */ |
||||
writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Normal DLL, Burst Length 8, CAS Latency 3 */ |
||||
writel(DDR1_MODE_VAL, regs + AR71XX_DDR_REG_MODE); |
||||
|
||||
/* Mode Register Set (MRS) */ |
||||
writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
|
||||
/* Refresh time control */ |
||||
if (val & AR933X_BOOTSTRAP_REF_CLK_40) |
||||
writel(DDR_REFRESH_VAL_40M, regs + |
||||
AR71XX_DDR_REG_REFRESH); |
||||
else |
||||
writel(DDR_REFRESH_VAL_25M, regs + |
||||
AR71XX_DDR_REG_REFRESH); |
||||
|
||||
/* DQS 0 Tap Control */ |
||||
writel(DDR_TAP_VAL0, regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
|
||||
/* DQS 1 Tap Control */ |
||||
writel(DDR_TAP_VAL1, regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
|
||||
/* For 16-bit DDR */ |
||||
writel(0xff, regs + AR71XX_DDR_REG_RD_CYCLE); |
||||
} |
||||
} |
||||
|
||||
void ddr_tap_tuning(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 *addr_k0, *addr_k1, *addr; |
||||
u32 val, tap, upper, lower; |
||||
int i, j, dir, err, done; |
||||
|
||||
regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
/* Init memory pattern */ |
||||
addr = (void *)CKSEG0ADDR(0x2000); |
||||
for (i = 0; i < 256; i++) { |
||||
val = 0; |
||||
for (j = 0; j < 8; j++) { |
||||
if (i & (1 << j)) { |
||||
if (j % 2) |
||||
val |= 0xffff0000; |
||||
else |
||||
val |= 0x0000ffff; |
||||
} |
||||
|
||||
if (j % 2) { |
||||
*addr++ = val; |
||||
val = 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
err = 0; |
||||
done = 0; |
||||
dir = 1; |
||||
tap = readl(regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
val = tap; |
||||
while (!done) { |
||||
err = 0; |
||||
|
||||
/* Update new DDR tap value */ |
||||
writel(val, regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
writel(val, regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
|
||||
/* Compare DDR with cache */ |
||||
for (i = 0; i < 2; i++) { |
||||
addr_k1 = (void *)CKSEG1ADDR(0x2000); |
||||
addr_k0 = (void *)CKSEG0ADDR(0x2000); |
||||
addr = (void *)CKSEG0ADDR(0x3000); |
||||
|
||||
while (addr_k0 < addr) { |
||||
if (*addr_k1++ != *addr_k0++) { |
||||
err = 1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (err) |
||||
break; |
||||
} |
||||
|
||||
if (err) { |
||||
/* Save upper/lower threshold if error */ |
||||
if (dir) { |
||||
dir = 0; |
||||
val--; |
||||
upper = val; |
||||
val = tap; |
||||
} else { |
||||
val++; |
||||
lower = val; |
||||
done = 1; |
||||
} |
||||
} else { |
||||
/* Try the next value until limitation */ |
||||
if (dir) { |
||||
if (val < 0x20) { |
||||
val++; |
||||
} else { |
||||
dir = 0; |
||||
upper = val; |
||||
val = tap; |
||||
} |
||||
} else { |
||||
if (!val) { |
||||
lower = val; |
||||
done = 1; |
||||
} else { |
||||
val--; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* compute an intermediate value and write back */ |
||||
val = (upper + lower) / 2; |
||||
writel(val, regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
val++; |
||||
writel(val, regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
} |
@ -0,0 +1,280 @@ |
||||
/* |
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
|
||||
* Based on Atheros LSDK/QSDK and u-boot_mod project |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <config.h> |
||||
#include <asm/asm.h> |
||||
#include <asm/regdef.h> |
||||
#include <asm/mipsregs.h> |
||||
#include <asm/addrspace.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
|
||||
#define SET_BIT(val, bit) ((val) | (1 << (bit))) |
||||
#define SET_PLL_PD(val) SET_BIT(val, 30) |
||||
#define AHB_DIV_TO_4(val) SET_BIT(SET_BIT(val, 15), 16) |
||||
#define PLL_BYPASS(val) SET_BIT(val, 2) |
||||
|
||||
#define MK_PLL_CONF(divint, refdiv, range, outdiv) \ |
||||
(((0x3F & divint) << 10) | \ |
||||
((0x1F & refdiv) << 16) | \ |
||||
((0x1 & range) << 21) | \ |
||||
((0x7 & outdiv) << 23) ) |
||||
|
||||
#define MK_CLK_CNTL(cpudiv, ddrdiv, ahbdiv) \ |
||||
(((0x3 & (cpudiv - 1)) << 5) | \ |
||||
((0x3 & (ddrdiv - 1)) << 10) | \ |
||||
((0x3 & (ahbdiv - 1)) << 15) ) |
||||
|
||||
/* |
||||
* PLL_CPU_CONFIG_VAL |
||||
* |
||||
* Bit30 is set (CPU_PLLPWD = 1 -> power down control for CPU PLL) |
||||
* After PLL configuration we need to clear this bit |
||||
* |
||||
* Values written into CPU PLL Configuration (CPU_PLL_CONFIG) |
||||
* |
||||
* bits 10..15 (6bit) DIV_INT (Integer part of the DIV to CPU PLL) |
||||
* => 32 (0x20) VCOOUT = XTAL * DIV_INT |
||||
* bits 16..20 (5bit) REFDIV (Reference clock divider) |
||||
* => 1 (0x1) [Must start at values 1] |
||||
* bits 21 (1bit) RANGE (VCO frequency range of the CPU PLL) |
||||
* => 0 (0x0) [Doesn't impact clock values] |
||||
* bits 23..25 (3bit) OUTDIV (Ratio between VCO and PLL output) |
||||
* => 1 (0x1) [0 is illegal!] |
||||
* PLLOUT = VCOOUT * (1/2^OUTDIV) |
||||
*/ |
||||
/* DIV_INT=32 (25MHz*32/2=400MHz), REFDIV=1, RANGE=0, OUTDIV=1 */ |
||||
#define PLL_CPU_CONFIG_VAL_40M MK_PLL_CONF(20, 1, 0, 1) |
||||
/* DIV_INT=20 (40MHz*20/2=400MHz), REFDIV=1, RANGE=0, OUTDIV=1 */ |
||||
#define PLL_CPU_CONFIG_VAL_25M MK_PLL_CONF(32, 1, 0, 1) |
||||
|
||||
/* |
||||
* PLL_CLK_CONTROL_VAL |
||||
* |
||||
* In PLL_CLK_CONTROL_VAL bit 2 is set (BYPASS = 1 -> bypass PLL) |
||||
* After PLL configuration we need to clear this bit |
||||
* |
||||
* Values written into CPU Clock Control Register CLOCK_CONTROL |
||||
* |
||||
* bits 2 (1bit) BYPASS (Bypass PLL. This defaults to 1 for test. |
||||
* Software must enable the CPU PLL for normal and |
||||
* then set this bit to 0) |
||||
* bits 5..6 (2bit) CPU_POST_DIV => 0 (DEFAULT, Ratio = 1) |
||||
* CPU_CLK = PLLOUT / CPU_POST_DIV |
||||
* bits 10..11 (2bit) DDR_POST_DIV => 0 (DEFAULT, Ratio = 1) |
||||
* DDR_CLK = PLLOUT / DDR_POST_DIV |
||||
* bits 15..16 (2bit) AHB_POST_DIV => 1 (DEFAULT, Ratio = 2) |
||||
* AHB_CLK = PLLOUT / AHB_POST_DIV |
||||
* |
||||
*/ |
||||
#define PLL_CLK_CONTROL_VAL MK_CLK_CNTL(1, 1, 2) |
||||
|
||||
.text |
||||
.set noreorder
|
||||
|
||||
LEAF(lowlevel_init) |
||||
/* These three WLAN_RESET will avoid original issue */ |
||||
li t3, 0x03 |
||||
1: |
||||
li t0, CKSEG1ADDR(AR71XX_RESET_BASE) |
||||
lw t1, AR933X_RESET_REG_RESET_MODULE(t0) |
||||
ori t1, t1, 0x0800 |
||||
sw t1, AR933X_RESET_REG_RESET_MODULE(t0) |
||||
nop |
||||
lw t1, AR933X_RESET_REG_RESET_MODULE(t0) |
||||
li t2, 0xfffff7ff |
||||
and t1, t1, t2 |
||||
sw t1, AR933X_RESET_REG_RESET_MODULE(t0) |
||||
nop |
||||
addi t3, t3, -1 |
||||
bnez t3, 1b |
||||
nop |
||||
|
||||
li t2, 0x20 |
||||
2: |
||||
beqz t2, 1b |
||||
nop |
||||
addi t2, t2, -1 |
||||
lw t5, AR933X_RESET_REG_BOOTSTRAP(t0) |
||||
andi t1, t5, 0x10 |
||||
bnez t1, 2b |
||||
nop |
||||
|
||||
li t1, 0x02110E |
||||
sw t1, AR933X_RESET_REG_BOOTSTRAP(t0) |
||||
nop |
||||
|
||||
/* RTC Force Wake */ |
||||
li t0, CKSEG1ADDR(AR933X_RTC_BASE) |
||||
li t1, 0x03 |
||||
sw t1, AR933X_RTC_REG_FORCE_WAKE(t0) |
||||
nop |
||||
nop |
||||
|
||||
/* RTC Reset */ |
||||
li t1, 0x00 |
||||
sw t1, AR933X_RTC_REG_RESET(t0) |
||||
nop |
||||
nop |
||||
|
||||
li t1, 0x01 |
||||
sw t1, AR933X_RTC_REG_RESET(t0) |
||||
nop |
||||
nop |
||||
|
||||
/* Wait for RTC in on state */ |
||||
1: |
||||
lw t1, AR933X_RTC_REG_STATUS(t0) |
||||
andi t1, t1, 0x02 |
||||
beqz t1, 1b |
||||
nop |
||||
|
||||
/* Program ki/kd */ |
||||
li t0, CKSEG1ADDR(AR933X_SRIF_BASE) |
||||
andi t1, t5, 0x01 # t5 BOOT_STRAP |
||||
bnez t1, 1f |
||||
nop |
||||
li t1, 0x19e82f01 |
||||
b 2f |
||||
nop |
||||
1: |
||||
li t1, 0x18e82f01 |
||||
2: |
||||
sw t1, AR933X_SRIF_DDR_DPLL2_REG(t0) |
||||
|
||||
/* Program phase shift */ |
||||
lw t1, AR933X_SRIF_DDR_DPLL3_REG(t0) |
||||
li t2, 0xc07fffff |
||||
and t1, t1, t2 |
||||
li t2, 0x800000 |
||||
or t1, t1, t2 |
||||
sw t1, AR933X_SRIF_DDR_DPLL3_REG(t0) |
||||
nop |
||||
|
||||
/* in some cases, the SoC doesn't start with higher clock on AHB */ |
||||
li t0, CKSEG1ADDR(AR71XX_PLL_BASE) |
||||
li t1, AHB_DIV_TO_4(PLL_BYPASS(PLL_CLK_CONTROL_VAL)) |
||||
sw t1, AR933X_PLL_CLK_CTRL_REG(t0) |
||||
nop |
||||
|
||||
/* Set SETTLE_TIME in CPU PLL */ |
||||
andi t1, t5, 0x01 # t5 BOOT_STRAP |
||||
bnez t1, 1f |
||||
nop |
||||
li t1, 0x0352 |
||||
b 2f |
||||
nop |
||||
1: |
||||
li t1, 0x0550 |
||||
2: |
||||
sw t1, AR71XX_PLL_REG_SEC_CONFIG(t0) |
||||
nop |
||||
|
||||
/* Set nint, frac, refdiv, outdiv, range according to xtal */ |
||||
0: |
||||
andi t1, t5, 0x01 # t5 BOOT_STRAP |
||||
bnez t1, 1f |
||||
nop |
||||
li t1, SET_PLL_PD(PLL_CPU_CONFIG_VAL_25M) |
||||
b 2f |
||||
nop |
||||
1: |
||||
li t1, SET_PLL_PD(PLL_CPU_CONFIG_VAL_40M) |
||||
2: |
||||
sw t1, AR933X_PLL_CPU_CONFIG_REG(t0) |
||||
nop |
||||
1: |
||||
lw t1, AR933X_PLL_CPU_CONFIG_REG(t0) |
||||
li t2, 0x80000000 |
||||
and t1, t1, t2 |
||||
bnez t1, 1b |
||||
nop |
||||
|
||||
/* Put frac bit19:10 configuration */ |
||||
li t1, 0x1003E8 |
||||
sw t1, AR933X_PLL_DITHER_FRAC_REG(t0) |
||||
nop |
||||
|
||||
/* Clear PLL power down bit in CPU PLL configuration */ |
||||
andi t1, t5, 0x01 # t5 BOOT_STRAP |
||||
bnez t1, 1f |
||||
nop |
||||
li t1, PLL_CPU_CONFIG_VAL_25M |
||||
b 2f |
||||
nop |
||||
1: |
||||
li t1, PLL_CPU_CONFIG_VAL_40M |
||||
2: |
||||
sw t1, AR933X_PLL_CPU_CONFIG_REG(t0) |
||||
nop |
||||
|
||||
/* Wait for PLL update -> bit 31 in CPU_PLL_CONFIG should be 0 */ |
||||
1: |
||||
lw t1, AR933X_PLL_CPU_CONFIG_REG(t0) |
||||
li t2, 0x80000000 |
||||
and t1, t1, t2 |
||||
bnez t1, 1b |
||||
nop |
||||
|
||||
/* Confirm DDR PLL lock */ |
||||
li t3, 100 |
||||
li t4, 0 |
||||
|
||||
2: |
||||
addi t4, t4, 1 |
||||
bgt t4, t3, 0b |
||||
nop |
||||
|
||||
li t3, 5 |
||||
3: |
||||
/* Clear do_meas */ |
||||
li t0, CKSEG1ADDR(AR933X_SRIF_BASE) |
||||
lw t1, AR933X_SRIF_DDR_DPLL3_REG(t0) |
||||
li t2, 0xBFFFFFFF |
||||
and t1, t1, t2 |
||||
sw t1, AR933X_SRIF_DDR_DPLL3_REG(t0) |
||||
nop |
||||
|
||||
li t2, 10 |
||||
1: |
||||
subu t2, t2, 1 |
||||
bnez t2, 1b |
||||
nop |
||||
|
||||
/* Set do_meas */ |
||||
li t2, 0x40000000 |
||||
or t1, t1, t2 |
||||
sw t1, AR933X_SRIF_DDR_DPLL3_REG(t0) |
||||
nop |
||||
|
||||
/* Check meas_done */ |
||||
1: |
||||
lw t1, AR933X_SRIF_DDR_DPLL4_REG(t0) |
||||
andi t1, t1, 0x8 |
||||
beqz t1, 1b |
||||
nop |
||||
|
||||
lw t1, AR933X_SRIF_DDR_DPLL3_REG(t0) |
||||
li t2, 0x007FFFF8 |
||||
and t1, t1, t2 |
||||
srl t1, t1, 3 |
||||
li t2, 0x4000 |
||||
bgt t1, t2, 2b |
||||
nop |
||||
addi t3, t3, -1 |
||||
bnez t3, 3b |
||||
nop |
||||
|
||||
/* clear PLL bypass (bit 2) in CPU CLOCK CONTROL register */ |
||||
li t0, CKSEG1ADDR(AR71XX_PLL_BASE) |
||||
li t1, PLL_CLK_CONTROL_VAL |
||||
sw t1, AR933X_PLL_CLK_CTRL_REG(t0) |
||||
nop |
||||
|
||||
nop |
||||
jr ra |
||||
nop |
||||
END(lowlevel_init) |
@ -0,0 +1,7 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += cpu.o
|
||||
obj-y += clk.o
|
||||
obj-y += ddr.o
|
@ -0,0 +1,334 @@ |
||||
/*
|
||||
* Copyright (C) 2016 Marek Vasut <marex@denx.de> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/reset.h> |
||||
#include <wait_bit.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
/*
|
||||
* The math for calculating PLL: |
||||
* NFRAC * 2^8 |
||||
* NINT + ------------- |
||||
* XTAL [MHz] 2^(18 - 1) |
||||
* PLL [MHz] = ------------ * ---------------------- |
||||
* REFDIV 2^OUTDIV |
||||
* |
||||
* Unfortunatelly, there is no way to reliably compute the variables. |
||||
* The vendor U-Boot port contains macros for various combinations of |
||||
* CPU PLL / DDR PLL / AHB bus speed and there is no obvious pattern |
||||
* in those numbers. |
||||
*/ |
||||
struct ar934x_pll_config { |
||||
u8 range; |
||||
u8 refdiv; |
||||
u8 outdiv; |
||||
/* Index 0 is for XTAL=25MHz , Index 1 is for XTAL=40MHz */ |
||||
u8 nint[2]; |
||||
}; |
||||
|
||||
struct ar934x_clock_config { |
||||
u16 cpu_freq; |
||||
u16 ddr_freq; |
||||
u16 ahb_freq; |
||||
|
||||
struct ar934x_pll_config cpu_pll; |
||||
struct ar934x_pll_config ddr_pll; |
||||
}; |
||||
|
||||
static const struct ar934x_clock_config ar934x_clock_config[] = { |
||||
{ 300, 300, 150, { 1, 1, 1, { 24, 15 } }, { 1, 1, 1, { 24, 15 } } }, |
||||
{ 400, 200, 200, { 1, 1, 1, { 32, 20 } }, { 1, 1, 2, { 32, 20 } } }, |
||||
{ 400, 400, 200, { 0, 1, 1, { 32, 20 } }, { 0, 1, 1, { 32, 20 } } }, |
||||
{ 500, 400, 200, { 1, 1, 0, { 20, 12 } }, { 0, 1, 1, { 32, 20 } } }, |
||||
{ 533, 400, 200, { 1, 1, 0, { 21, 13 } }, { 0, 1, 1, { 32, 20 } } }, |
||||
{ 533, 500, 250, { 1, 1, 0, { 21, 13 } }, { 0, 1, 0, { 20, 12 } } }, |
||||
{ 560, 480, 240, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 12 } } }, |
||||
{ 566, 400, 200, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 16, 10 } } }, |
||||
{ 566, 450, 225, { 1, 1, 0, { 22, 14 } }, { 0, 1, 1, { 36, 22 } } }, |
||||
{ 566, 475, 237, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 11 } } }, |
||||
{ 566, 500, 250, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 20, 12 } } }, |
||||
{ 566, 525, 262, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 21, 13 } } }, |
||||
{ 566, 550, 275, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 22, 13 } } }, |
||||
{ 600, 266, 133, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } }, |
||||
{ 600, 266, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } }, |
||||
{ 600, 300, 150, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 24, 15 } } }, |
||||
{ 600, 332, 166, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } }, |
||||
{ 600, 332, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } }, |
||||
{ 600, 400, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 32, 20 } } }, |
||||
{ 600, 450, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 18, 20 } } }, |
||||
{ 600, 500, 250, { 0, 1, 0, { 24, 15 } }, { 1, 1, 0, { 20, 12 } } }, |
||||
{ 600, 525, 262, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 21, 20 } } }, |
||||
{ 600, 550, 275, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 22, 20 } } }, |
||||
{ 600, 575, 287, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 23, 14 } } }, |
||||
{ 600, 600, 300, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 24, 20 } } }, |
||||
{ 600, 650, 325, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 26, 20 } } }, |
||||
{ 650, 600, 300, { 0, 1, 0, { 26, 15 } }, { 0, 1, 0, { 24, 20 } } }, |
||||
{ 700, 400, 200, { 3, 1, 0, { 28, 17 } }, { 0, 1, 1, { 32, 20 } } }, |
||||
}; |
||||
|
||||
static void ar934x_srif_pll_cfg(void __iomem *pll_reg_base, const u32 srif_val) |
||||
{ |
||||
u32 reg; |
||||
do { |
||||
writel(0x10810f00, pll_reg_base + 0x4); |
||||
writel(srif_val, pll_reg_base + 0x0); |
||||
writel(0xd0810f00, pll_reg_base + 0x4); |
||||
writel(0x03000000, pll_reg_base + 0x8); |
||||
writel(0xd0800f00, pll_reg_base + 0x4); |
||||
|
||||
clrbits_be32(pll_reg_base + 0x8, BIT(30)); |
||||
udelay(5); |
||||
setbits_be32(pll_reg_base + 0x8, BIT(30)); |
||||
udelay(5); |
||||
|
||||
wait_for_bit("clk", pll_reg_base + 0xc, BIT(3), 1, 10, 0); |
||||
|
||||
clrbits_be32(pll_reg_base + 0x8, BIT(30)); |
||||
udelay(5); |
||||
|
||||
/* Check if CPU SRIF PLL locked. */ |
||||
reg = readl(pll_reg_base + 0x8); |
||||
reg = (reg & 0x7ffff8) >> 3; |
||||
} while (reg >= 0x40000); |
||||
} |
||||
|
||||
void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz) |
||||
{ |
||||
void __iomem *srif_regs = map_physmem(AR934X_SRIF_BASE, |
||||
AR934X_SRIF_SIZE, MAP_NOCACHE); |
||||
void __iomem *pll_regs = map_physmem(AR71XX_PLL_BASE, |
||||
AR71XX_PLL_SIZE, MAP_NOCACHE); |
||||
const struct ar934x_pll_config *pll_cfg; |
||||
int i, pll_nint, pll_refdiv, xtal_40 = 0; |
||||
u32 reg, cpu_pll, cpu_srif, ddr_pll, ddr_srif; |
||||
|
||||
/* Configure SRIF PLL with initial values. */ |
||||
writel(0x13210f00, srif_regs + AR934X_SRIF_CPU_DPLL2_REG); |
||||
writel(0x03000000, srif_regs + AR934X_SRIF_CPU_DPLL3_REG); |
||||
writel(0x13210f00, srif_regs + AR934X_SRIF_DDR_DPLL2_REG); |
||||
writel(0x03000000, srif_regs + AR934X_SRIF_DDR_DPLL3_REG); |
||||
writel(0x03000000, srif_regs + 0x188); /* Undocumented reg :-) */ |
||||
|
||||
/* Test for 40MHz XTAL */ |
||||
reg = get_bootstrap(); |
||||
if (reg & AR934X_BOOTSTRAP_REF_CLK_40) { |
||||
xtal_40 = 1; |
||||
cpu_srif = 0x41c00000; |
||||
ddr_srif = 0x41680000; |
||||
} else { |
||||
xtal_40 = 0; |
||||
cpu_srif = 0x29c00000; |
||||
ddr_srif = 0x29680000; |
||||
} |
||||
|
||||
/* Locate CPU/DDR PLL configuration */ |
||||
for (i = 0; i < ARRAY_SIZE(ar934x_clock_config); i++) { |
||||
if (cpu_mhz != ar934x_clock_config[i].cpu_freq) |
||||
continue; |
||||
if (ddr_mhz != ar934x_clock_config[i].ddr_freq) |
||||
continue; |
||||
if (ahb_mhz != ar934x_clock_config[i].ahb_freq) |
||||
continue; |
||||
|
||||
/* Entry found */ |
||||
pll_cfg = &ar934x_clock_config[i].cpu_pll; |
||||
pll_nint = pll_cfg->nint[xtal_40]; |
||||
pll_refdiv = pll_cfg->refdiv; |
||||
cpu_pll = |
||||
(pll_nint << AR934X_PLL_CPU_CONFIG_NINT_SHIFT) | |
||||
(pll_refdiv << AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) | |
||||
(pll_cfg->range << AR934X_PLL_CPU_CONFIG_RANGE_SHIFT) | |
||||
(pll_cfg->outdiv << AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT); |
||||
|
||||
pll_cfg = &ar934x_clock_config[i].ddr_pll; |
||||
pll_nint = pll_cfg->nint[xtal_40]; |
||||
pll_refdiv = pll_cfg->refdiv; |
||||
ddr_pll = |
||||
(pll_nint << AR934X_PLL_DDR_CONFIG_NINT_SHIFT) | |
||||
(pll_refdiv << AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) | |
||||
(pll_cfg->range << AR934X_PLL_DDR_CONFIG_RANGE_SHIFT) | |
||||
(pll_cfg->outdiv << AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT); |
||||
break; |
||||
} |
||||
|
||||
/* PLL configuration not found, hang. */ |
||||
if (i == ARRAY_SIZE(ar934x_clock_config)) |
||||
hang(); |
||||
|
||||
/* Set PLL Bypass */ |
||||
setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG, |
||||
AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS); |
||||
setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG, |
||||
AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS); |
||||
setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG, |
||||
AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS); |
||||
|
||||
/* Configure CPU PLL */ |
||||
writel(cpu_pll | AR934X_PLL_CPU_CONFIG_PLLPWD, |
||||
pll_regs + AR934X_PLL_CPU_CONFIG_REG); |
||||
/* Configure DDR PLL */ |
||||
writel(ddr_pll | AR934X_PLL_DDR_CONFIG_PLLPWD, |
||||
pll_regs + AR934X_PLL_DDR_CONFIG_REG); |
||||
/* Configure PLL routing */ |
||||
writel(AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS | |
||||
AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS | |
||||
AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS | |
||||
(0 << AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) | |
||||
(0 << AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) | |
||||
(1 << AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) | |
||||
AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL | |
||||
AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL | |
||||
AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL, |
||||
pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG); |
||||
|
||||
/* Configure SRIF PLLs, which is completely undocumented :-) */ |
||||
ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_CPU_DPLL1_REG, cpu_srif); |
||||
ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_DDR_DPLL1_REG, ddr_srif); |
||||
|
||||
/* Unset PLL Bypass */ |
||||
clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG, |
||||
AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS); |
||||
clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG, |
||||
AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS); |
||||
clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG, |
||||
AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS); |
||||
|
||||
/* Enable PLL dithering */ |
||||
writel((1 << AR934X_PLL_DDR_DIT_FRAC_STEP_SHIFT) | |
||||
(0xf << AR934X_PLL_DDR_DIT_UPD_CNT_SHIFT), |
||||
pll_regs + AR934X_PLL_DDR_DIT_FRAC_REG); |
||||
writel(48 << AR934X_PLL_CPU_DIT_UPD_CNT_SHIFT, |
||||
pll_regs + AR934X_PLL_CPU_DIT_FRAC_REG); |
||||
} |
||||
|
||||
static u32 ar934x_get_xtal(void) |
||||
{ |
||||
u32 val; |
||||
|
||||
val = get_bootstrap(); |
||||
if (val & AR934X_BOOTSTRAP_REF_CLK_40) |
||||
return 40000000; |
||||
else |
||||
return 25000000; |
||||
} |
||||
|
||||
int get_serial_clock(void) |
||||
{ |
||||
return ar934x_get_xtal(); |
||||
} |
||||
|
||||
static u32 ar934x_cpupll_to_hz(const u32 regval) |
||||
{ |
||||
const u32 outdiv = (regval >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & |
||||
AR934X_PLL_CPU_CONFIG_OUTDIV_MASK; |
||||
const u32 refdiv = (regval >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) & |
||||
AR934X_PLL_CPU_CONFIG_REFDIV_MASK; |
||||
const u32 nint = (regval >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) & |
||||
AR934X_PLL_CPU_CONFIG_NINT_MASK; |
||||
const u32 nfrac = (regval >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) & |
||||
AR934X_PLL_CPU_CONFIG_NFRAC_MASK; |
||||
const u32 xtal = ar934x_get_xtal(); |
||||
|
||||
return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv)); |
||||
} |
||||
|
||||
static u32 ar934x_ddrpll_to_hz(const u32 regval) |
||||
{ |
||||
const u32 outdiv = (regval >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & |
||||
AR934X_PLL_DDR_CONFIG_OUTDIV_MASK; |
||||
const u32 refdiv = (regval >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) & |
||||
AR934X_PLL_DDR_CONFIG_REFDIV_MASK; |
||||
const u32 nint = (regval >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) & |
||||
AR934X_PLL_DDR_CONFIG_NINT_MASK; |
||||
const u32 nfrac = (regval >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) & |
||||
AR934X_PLL_DDR_CONFIG_NFRAC_MASK; |
||||
const u32 xtal = ar934x_get_xtal(); |
||||
|
||||
return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv)); |
||||
} |
||||
|
||||
static void ar934x_update_clock(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 ctrl, cpu, cpupll, ddr, ddrpll; |
||||
u32 cpudiv, ddrdiv, busdiv; |
||||
u32 cpuclk, ddrclk, busclk; |
||||
|
||||
regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
cpu = readl(regs + AR934X_PLL_CPU_CONFIG_REG); |
||||
ddr = readl(regs + AR934X_PLL_DDR_CONFIG_REG); |
||||
ctrl = readl(regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG); |
||||
|
||||
cpupll = ar934x_cpupll_to_hz(cpu); |
||||
ddrpll = ar934x_ddrpll_to_hz(ddr); |
||||
|
||||
if (ctrl & AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS) |
||||
cpuclk = ar934x_get_xtal(); |
||||
else if (ctrl & AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL) |
||||
cpuclk = cpupll; |
||||
else |
||||
cpuclk = ddrpll; |
||||
|
||||
if (ctrl & AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS) |
||||
ddrclk = ar934x_get_xtal(); |
||||
else if (ctrl & AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL) |
||||
ddrclk = ddrpll; |
||||
else |
||||
ddrclk = cpupll; |
||||
|
||||
if (ctrl & AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS) |
||||
busclk = ar934x_get_xtal(); |
||||
else if (ctrl & AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL) |
||||
busclk = ddrpll; |
||||
else |
||||
busclk = cpupll; |
||||
|
||||
cpudiv = (ctrl >> AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) & |
||||
AR934X_PLL_CLK_CTRL_CPU_POST_DIV_MASK; |
||||
ddrdiv = (ctrl >> AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) & |
||||
AR934X_PLL_CLK_CTRL_DDR_POST_DIV_MASK; |
||||
busdiv = (ctrl >> AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) & |
||||
AR934X_PLL_CLK_CTRL_AHB_POST_DIV_MASK; |
||||
|
||||
gd->cpu_clk = cpuclk / (cpudiv + 1); |
||||
gd->mem_clk = ddrclk / (ddrdiv + 1); |
||||
gd->bus_clk = busclk / (busdiv + 1); |
||||
} |
||||
|
||||
ulong get_bus_freq(ulong dummy) |
||||
{ |
||||
ar934x_update_clock(); |
||||
return gd->bus_clk; |
||||
} |
||||
|
||||
ulong get_ddr_freq(ulong dummy) |
||||
{ |
||||
ar934x_update_clock(); |
||||
return gd->mem_clk; |
||||
} |
||||
|
||||
int do_ar934x_showclk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
ar934x_update_clock(); |
||||
printf("CPU: %8ld MHz\n", gd->cpu_clk / 1000000); |
||||
printf("Memory: %8ld MHz\n", gd->mem_clk / 1000000); |
||||
printf("AHB: %8ld MHz\n", gd->bus_clk / 1000000); |
||||
return 0; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
clocks, CONFIG_SYS_MAXARGS, 1, do_ar934x_showclk, |
||||
"display clocks", |
||||
"" |
||||
); |
@ -0,0 +1,10 @@ |
||||
/*
|
||||
* Copyright (C) 2016 Marek Vasut <marex@denx.de> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
|
||||
/* The lowlevel_init() is not needed on AR934x */ |
||||
void lowlevel_init(void) {} |
@ -0,0 +1,163 @@ |
||||
/*
|
||||
* Copyright (C) 2016 Marek Vasut <marex@denx.de> |
||||
* |
||||
* Based on RAM init sequence by Piotr Dymacz <pepe2k@gmail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/reset.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
enum { |
||||
AR934X_SDRAM = 0, |
||||
AR934X_DDR1, |
||||
AR934X_DDR2, |
||||
}; |
||||
|
||||
struct ar934x_mem_config { |
||||
u32 config1; |
||||
u32 config2; |
||||
u32 mode; |
||||
u32 extmode; |
||||
u32 tap; |
||||
}; |
||||
|
||||
static const struct ar934x_mem_config ar934x_mem_config[] = { |
||||
[AR934X_SDRAM] = { 0x7fbe8cd0, 0x959f66a8, 0x33, 0, 0x1f1f }, |
||||
[AR934X_DDR1] = { 0x7fd48cd0, 0x99d0e6a8, 0x33, 0, 0x14 }, |
||||
[AR934X_DDR2] = { 0xc7d48cd0, 0x9dd0e6a8, 0x33, 0, 0x10012 }, |
||||
}; |
||||
|
||||
void ar934x_ddr_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz) |
||||
{ |
||||
void __iomem *ddr_regs; |
||||
const struct ar934x_mem_config *memcfg; |
||||
int memtype; |
||||
u32 reg, cycle, ctl; |
||||
|
||||
ddr_regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
reg = get_bootstrap(); |
||||
if (reg & AR934X_BOOTSTRAP_SDRAM_DISABLED) { /* DDR */ |
||||
if (reg & AR934X_BOOTSTRAP_DDR1) { /* DDR 1 */ |
||||
memtype = AR934X_DDR1; |
||||
cycle = 0xffff; |
||||
} else { /* DDR 2 */ |
||||
memtype = AR934X_DDR2; |
||||
if (gd->arch.rev) { |
||||
ctl = BIT(6); /* Undocumented bit :-( */ |
||||
if (reg & BIT(3)) |
||||
cycle = 0xff; |
||||
else |
||||
cycle = 0xffff; |
||||
} else { |
||||
/* Force DDR2/x16 configuratio on old chips. */ |
||||
ctl = 0; |
||||
cycle = 0xffff; /* DDR2 16bit */ |
||||
} |
||||
|
||||
writel(0xe59, ddr_regs + AR934X_DDR_REG_DDR2_CONFIG); |
||||
udelay(100); |
||||
|
||||
writel(0x10, ddr_regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
|
||||
writel(0x20, ddr_regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
|
||||
writel(ctl, ddr_regs + AR934X_DDR_REG_CTL_CONF); |
||||
udelay(10); |
||||
} |
||||
} else { /* SDRAM */ |
||||
memtype = AR934X_SDRAM; |
||||
cycle = 0xffffffff; |
||||
|
||||
writel(0x13b, ddr_regs + AR934X_DDR_REG_CTL_CONF); |
||||
udelay(100); |
||||
|
||||
/* Undocumented register */ |
||||
writel(0x13b, ddr_regs + 0x118); |
||||
udelay(100); |
||||
} |
||||
|
||||
memcfg = &ar934x_mem_config[memtype]; |
||||
|
||||
writel(memcfg->config1, ddr_regs + AR71XX_DDR_REG_CONFIG); |
||||
udelay(100); |
||||
|
||||
writel(memcfg->config2, ddr_regs + AR71XX_DDR_REG_CONFIG2); |
||||
udelay(100); |
||||
|
||||
writel(0x8, ddr_regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
|
||||
writel(memcfg->mode | 0x100, ddr_regs + AR71XX_DDR_REG_MODE); |
||||
mdelay(1); |
||||
|
||||
writel(0x1, ddr_regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
|
||||
if (memtype == AR934X_DDR2) { |
||||
writel(memcfg->mode | 0x100, ddr_regs + AR71XX_DDR_REG_EMR); |
||||
udelay(100); |
||||
|
||||
writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
} |
||||
|
||||
if (memtype != AR934X_SDRAM) |
||||
writel(0x402, ddr_regs + AR71XX_DDR_REG_EMR); |
||||
|
||||
udelay(100); |
||||
|
||||
writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
|
||||
writel(0x8, ddr_regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
|
||||
writel(memcfg->mode, ddr_regs + AR71XX_DDR_REG_MODE); |
||||
udelay(100); |
||||
|
||||
writel(0x1, ddr_regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
|
||||
writel(0x412c /* FIXME */, ddr_regs + AR71XX_DDR_REG_REFRESH); |
||||
udelay(100); |
||||
|
||||
writel(memcfg->tap, ddr_regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
writel(memcfg->tap, ddr_regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
|
||||
if (memtype != AR934X_SDRAM) { |
||||
if ((gd->arch.rev && (reg & BIT(3))) || !gd->arch.rev) { |
||||
writel(memcfg->tap, |
||||
ddr_regs + AR934X_DDR_REG_TAP_CTRL2); |
||||
writel(memcfg->tap, |
||||
ddr_regs + AR934X_DDR_REG_TAP_CTRL3); |
||||
} |
||||
} |
||||
|
||||
writel(cycle, ddr_regs + AR71XX_DDR_REG_RD_CYCLE); |
||||
udelay(100); |
||||
|
||||
writel(0x74444444, ddr_regs + AR934X_DDR_REG_BURST); |
||||
udelay(100); |
||||
|
||||
writel(0x222, ddr_regs + AR934X_DDR_REG_BURST2); |
||||
udelay(100); |
||||
|
||||
writel(0xfffff, ddr_regs + AR934X_DDR_REG_TIMEOUT_MAX); |
||||
udelay(100); |
||||
} |
||||
|
||||
void ddr_tap_tuning(void) |
||||
{ |
||||
} |
@ -0,0 +1,142 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ath79.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
|
||||
struct ath79_soc_desc { |
||||
const enum ath79_soc_type soc; |
||||
const char *chip; |
||||
const int major; |
||||
const int minor; |
||||
}; |
||||
|
||||
static const struct ath79_soc_desc desc[] = { |
||||
{ATH79_SOC_AR7130, "7130", |
||||
REV_ID_MAJOR_AR71XX, AR71XX_REV_ID_MINOR_AR7130}, |
||||
{ATH79_SOC_AR7141, "7141", |
||||
REV_ID_MAJOR_AR71XX, AR71XX_REV_ID_MINOR_AR7141}, |
||||
{ATH79_SOC_AR7161, "7161", |
||||
REV_ID_MAJOR_AR71XX, AR71XX_REV_ID_MINOR_AR7161}, |
||||
{ATH79_SOC_AR7240, "7240", REV_ID_MAJOR_AR7240, 0}, |
||||
{ATH79_SOC_AR7241, "7241", REV_ID_MAJOR_AR7241, 0}, |
||||
{ATH79_SOC_AR7242, "7242", REV_ID_MAJOR_AR7242, 0}, |
||||
{ATH79_SOC_AR9130, "9130", |
||||
REV_ID_MAJOR_AR913X, AR913X_REV_ID_MINOR_AR9130}, |
||||
{ATH79_SOC_AR9132, "9132", |
||||
REV_ID_MAJOR_AR913X, AR913X_REV_ID_MINOR_AR9132}, |
||||
{ATH79_SOC_AR9330, "9330", REV_ID_MAJOR_AR9330, 0}, |
||||
{ATH79_SOC_AR9331, "9331", REV_ID_MAJOR_AR9331, 0}, |
||||
{ATH79_SOC_AR9341, "9341", REV_ID_MAJOR_AR9341, 0}, |
||||
{ATH79_SOC_AR9342, "9342", REV_ID_MAJOR_AR9342, 0}, |
||||
{ATH79_SOC_AR9344, "9344", REV_ID_MAJOR_AR9344, 0}, |
||||
{ATH79_SOC_QCA9533, "9533", REV_ID_MAJOR_QCA9533, 0}, |
||||
{ATH79_SOC_QCA9533, "9533", |
||||
REV_ID_MAJOR_QCA9533_V2, 0}, |
||||
{ATH79_SOC_QCA9556, "9556", REV_ID_MAJOR_QCA9556, 0}, |
||||
{ATH79_SOC_QCA9558, "9558", REV_ID_MAJOR_QCA9558, 0}, |
||||
{ATH79_SOC_TP9343, "9343", REV_ID_MAJOR_TP9343, 0}, |
||||
{ATH79_SOC_QCA9561, "9561", REV_ID_MAJOR_QCA9561, 0}, |
||||
}; |
||||
|
||||
int arch_cpu_init(void) |
||||
{ |
||||
void __iomem *base; |
||||
enum ath79_soc_type soc = ATH79_SOC_UNKNOWN; |
||||
u32 id, major, minor = 0; |
||||
u32 rev = 0, ver = 1; |
||||
int i; |
||||
|
||||
base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
id = readl(base + AR71XX_RESET_REG_REV_ID); |
||||
major = id & REV_ID_MAJOR_MASK; |
||||
switch (major) { |
||||
case REV_ID_MAJOR_AR71XX: |
||||
case REV_ID_MAJOR_AR913X: |
||||
minor = id & AR71XX_REV_ID_MINOR_MASK; |
||||
rev = id >> AR71XX_REV_ID_REVISION_SHIFT; |
||||
rev &= AR71XX_REV_ID_REVISION_MASK; |
||||
break; |
||||
|
||||
case REV_ID_MAJOR_QCA9533_V2: |
||||
ver = 2; |
||||
/* drop through */ |
||||
|
||||
case REV_ID_MAJOR_AR9341: |
||||
case REV_ID_MAJOR_AR9342: |
||||
case REV_ID_MAJOR_AR9344: |
||||
case REV_ID_MAJOR_QCA9533: |
||||
case REV_ID_MAJOR_QCA9556: |
||||
case REV_ID_MAJOR_QCA9558: |
||||
case REV_ID_MAJOR_TP9343: |
||||
case REV_ID_MAJOR_QCA9561: |
||||
rev = id & AR71XX_REV_ID_REVISION2_MASK; |
||||
break; |
||||
default: |
||||
rev = id & AR71XX_REV_ID_REVISION_MASK; |
||||
break; |
||||
} |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(desc); i++) { |
||||
if ((desc[i].major == major) && |
||||
(desc[i].minor == minor)) { |
||||
soc = desc[i].soc; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
gd->arch.id = id; |
||||
gd->arch.soc = soc; |
||||
gd->arch.rev = rev; |
||||
gd->arch.ver = ver; |
||||
return 0; |
||||
} |
||||
|
||||
int print_cpuinfo(void) |
||||
{ |
||||
enum ath79_soc_type soc = ATH79_SOC_UNKNOWN; |
||||
const char *chip = "????"; |
||||
u32 id, rev, ver; |
||||
int i; |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(desc); i++) { |
||||
if (desc[i].soc == gd->arch.soc) { |
||||
chip = desc[i].chip; |
||||
soc = desc[i].soc; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
id = gd->arch.id; |
||||
rev = gd->arch.rev; |
||||
ver = gd->arch.ver; |
||||
|
||||
switch (soc) { |
||||
case ATH79_SOC_QCA9533: |
||||
case ATH79_SOC_QCA9556: |
||||
case ATH79_SOC_QCA9558: |
||||
case ATH79_SOC_QCA9561: |
||||
printf("Qualcomm Atheros QCA%s ver %u rev %u\n", chip, |
||||
ver, rev); |
||||
break; |
||||
case ATH79_SOC_TP9343: |
||||
printf("Qualcomm Atheros TP%s rev %u\n", chip, rev); |
||||
break; |
||||
case ATH79_SOC_UNKNOWN: |
||||
printf("ATH79: unknown SoC, id:0x%08x", id); |
||||
break; |
||||
default: |
||||
printf("Atheros AR%s rev %u\n", chip, rev); |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,16 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <linux/sizes.h> |
||||
#include <asm/addrspace.h> |
||||
#include <mach/ddr.h> |
||||
|
||||
phys_size_t initdram(int board_type) |
||||
{ |
||||
ddr_tap_tuning(); |
||||
return get_ram_size((void *)KSEG1, SZ_256M); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,149 @@ |
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X common definitions |
||||
* |
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> |
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef __ASM_MACH_ATH79_H |
||||
#define __ASM_MACH_ATH79_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
enum ath79_soc_type { |
||||
ATH79_SOC_UNKNOWN, |
||||
ATH79_SOC_AR7130, |
||||
ATH79_SOC_AR7141, |
||||
ATH79_SOC_AR7161, |
||||
ATH79_SOC_AR7240, |
||||
ATH79_SOC_AR7241, |
||||
ATH79_SOC_AR7242, |
||||
ATH79_SOC_AR9130, |
||||
ATH79_SOC_AR9132, |
||||
ATH79_SOC_AR9330, |
||||
ATH79_SOC_AR9331, |
||||
ATH79_SOC_AR9341, |
||||
ATH79_SOC_AR9342, |
||||
ATH79_SOC_AR9344, |
||||
ATH79_SOC_QCA9533, |
||||
ATH79_SOC_QCA9556, |
||||
ATH79_SOC_QCA9558, |
||||
ATH79_SOC_TP9343, |
||||
ATH79_SOC_QCA9561, |
||||
}; |
||||
|
||||
static inline int soc_is_ar71xx(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR7130 || |
||||
gd->arch.soc == ATH79_SOC_AR7141 || |
||||
gd->arch.soc == ATH79_SOC_AR7161; |
||||
} |
||||
|
||||
static inline int soc_is_ar724x(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR7240 || |
||||
gd->arch.soc == ATH79_SOC_AR7241 || |
||||
gd->arch.soc == ATH79_SOC_AR7242; |
||||
} |
||||
|
||||
static inline int soc_is_ar7240(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR7240; |
||||
} |
||||
|
||||
static inline int soc_is_ar7241(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR7241; |
||||
} |
||||
|
||||
static inline int soc_is_ar7242(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR7242; |
||||
} |
||||
|
||||
static inline int soc_is_ar913x(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR9130 || |
||||
gd->arch.soc == ATH79_SOC_AR9132; |
||||
} |
||||
|
||||
static inline int soc_is_ar933x(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR9330 || |
||||
gd->arch.soc == ATH79_SOC_AR9331; |
||||
} |
||||
|
||||
static inline int soc_is_ar9341(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR9341; |
||||
} |
||||
|
||||
static inline int soc_is_ar9342(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR9342; |
||||
} |
||||
|
||||
static inline int soc_is_ar9344(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_AR9344; |
||||
} |
||||
|
||||
static inline int soc_is_ar934x(void) |
||||
{ |
||||
return soc_is_ar9341() || |
||||
soc_is_ar9342() || |
||||
soc_is_ar9344(); |
||||
} |
||||
|
||||
static inline int soc_is_qca9533(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_QCA9533; |
||||
} |
||||
|
||||
static inline int soc_is_qca953x(void) |
||||
{ |
||||
return soc_is_qca9533(); |
||||
} |
||||
|
||||
static inline int soc_is_qca9556(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_QCA9556; |
||||
} |
||||
|
||||
static inline int soc_is_qca9558(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_QCA9558; |
||||
} |
||||
|
||||
static inline int soc_is_qca955x(void) |
||||
{ |
||||
return soc_is_qca9556() || soc_is_qca9558(); |
||||
} |
||||
|
||||
static inline int soc_is_tp9343(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_TP9343; |
||||
} |
||||
|
||||
static inline int soc_is_qca9561(void) |
||||
{ |
||||
return gd->arch.soc == ATH79_SOC_QCA9561; |
||||
} |
||||
|
||||
static inline int soc_is_qca956x(void) |
||||
{ |
||||
return soc_is_tp9343() || soc_is_qca9561(); |
||||
} |
||||
|
||||
int ath79_eth_reset(void); |
||||
int ath79_usb_reset(void); |
||||
|
||||
void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz); |
||||
void ar934x_ddr_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz); |
||||
|
||||
#endif /* __ASM_MACH_ATH79_H */ |
@ -0,0 +1,13 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef __ASM_MACH_DDR_H |
||||
#define __ASM_MACH_DDR_H |
||||
|
||||
void ddr_init(void); |
||||
void ddr_tap_tuning(void); |
||||
|
||||
#endif /* __ASM_MACH_DDR_H */ |
@ -0,0 +1,14 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef __ASM_MACH_RESET_H |
||||
#define __ASM_MACH_RESET_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
u32 get_bootstrap(void); |
||||
|
||||
#endif /* __ASM_MACH_RESET_H */ |
@ -0,0 +1,7 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += clk.o
|
||||
obj-y += ddr.o
|
||||
obj-y += lowlevel_init.o
|
@ -0,0 +1,111 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/reset.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
static u32 qca953x_get_xtal(void) |
||||
{ |
||||
u32 val; |
||||
|
||||
val = get_bootstrap(); |
||||
if (val & QCA953X_BOOTSTRAP_REF_CLK_40) |
||||
return 40000000; |
||||
else |
||||
return 25000000; |
||||
} |
||||
|
||||
int get_serial_clock(void) |
||||
{ |
||||
return qca953x_get_xtal(); |
||||
} |
||||
|
||||
int get_clocks(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 val, ctrl, xtal, pll, div; |
||||
|
||||
regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
xtal = qca953x_get_xtal(); |
||||
ctrl = readl(regs + QCA953X_PLL_CLK_CTRL_REG); |
||||
val = readl(regs + QCA953X_PLL_CPU_CONFIG_REG); |
||||
|
||||
/* VCOOUT = XTAL * DIV_INT */ |
||||
div = (val >> QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT) |
||||
& QCA953X_PLL_CPU_CONFIG_REFDIV_MASK; |
||||
pll = xtal / div; |
||||
|
||||
/* PLLOUT = VCOOUT * (1/2^OUTDIV) */ |
||||
div = (val >> QCA953X_PLL_CPU_CONFIG_NINT_SHIFT) |
||||
& QCA953X_PLL_CPU_CONFIG_NINT_MASK; |
||||
pll *= div; |
||||
div = (val >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT) |
||||
& QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK; |
||||
if (!div) |
||||
div = 1; |
||||
pll >>= div; |
||||
|
||||
/* CPU_CLK = PLLOUT / CPU_POST_DIV */ |
||||
div = ((ctrl >> QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) |
||||
& QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1; |
||||
gd->cpu_clk = pll / div; |
||||
|
||||
|
||||
val = readl(regs + QCA953X_PLL_DDR_CONFIG_REG); |
||||
/* VCOOUT = XTAL * DIV_INT */ |
||||
div = (val >> QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT) |
||||
& QCA953X_PLL_DDR_CONFIG_REFDIV_MASK; |
||||
pll = xtal / div; |
||||
|
||||
/* PLLOUT = VCOOUT * (1/2^OUTDIV) */ |
||||
div = (val >> QCA953X_PLL_DDR_CONFIG_NINT_SHIFT) |
||||
& QCA953X_PLL_DDR_CONFIG_NINT_MASK; |
||||
pll *= div; |
||||
div = (val >> QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT) |
||||
& QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK; |
||||
if (!div) |
||||
div = 1; |
||||
pll >>= div; |
||||
|
||||
/* DDR_CLK = PLLOUT / DDR_POST_DIV */ |
||||
div = ((ctrl >> QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) |
||||
& QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1; |
||||
gd->mem_clk = pll / div; |
||||
|
||||
div = ((ctrl >> QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) |
||||
& QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1; |
||||
if (ctrl & QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL) { |
||||
/* AHB_CLK = DDR_CLK / AHB_POST_DIV */ |
||||
gd->bus_clk = gd->mem_clk / (div + 1); |
||||
} else { |
||||
/* AHB_CLK = CPU_CLK / AHB_POST_DIV */ |
||||
gd->bus_clk = gd->cpu_clk / (div + 1); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
ulong get_bus_freq(ulong dummy) |
||||
{ |
||||
if (!gd->bus_clk) |
||||
get_clocks(); |
||||
return gd->bus_clk; |
||||
} |
||||
|
||||
ulong get_ddr_freq(ulong dummy) |
||||
{ |
||||
if (!gd->mem_clk) |
||||
get_clocks(); |
||||
return gd->mem_clk; |
||||
} |
@ -0,0 +1,472 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* Based on Atheros LSDK/QSDK |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/reset.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
#define DDR_CTRL_UPD_EMR3S BIT(5) |
||||
#define DDR_CTRL_UPD_EMR2S BIT(4) |
||||
#define DDR_CTRL_PRECHARGE BIT(3) |
||||
#define DDR_CTRL_AUTO_REFRESH BIT(2) |
||||
#define DDR_CTRL_UPD_EMRS BIT(1) |
||||
#define DDR_CTRL_UPD_MRS BIT(0) |
||||
|
||||
#define DDR_REFRESH_EN BIT(14) |
||||
#define DDR_REFRESH_M 0x3ff |
||||
#define DDR_REFRESH(x) ((x) & DDR_REFRESH_M) |
||||
#define DDR_REFRESH_VAL (DDR_REFRESH_EN | DDR_REFRESH(312)) |
||||
|
||||
#define DDR_TRAS_S 0 |
||||
#define DDR_TRAS_M 0x1f |
||||
#define DDR_TRAS(x) (((x) & DDR_TRAS_M) << DDR_TRAS_S) |
||||
#define DDR_TRCD_M 0xf |
||||
#define DDR_TRCD_S 5 |
||||
#define DDR_TRCD(x) (((x) & DDR_TRCD_M) << DDR_TRCD_S) |
||||
#define DDR_TRP_M 0xf |
||||
#define DDR_TRP_S 9 |
||||
#define DDR_TRP(x) (((x) & DDR_TRP_M) << DDR_TRP_S) |
||||
#define DDR_TRRD_M 0xf |
||||
#define DDR_TRRD_S 13 |
||||
#define DDR_TRRD(x) (((x) & DDR_TRRD_M) << DDR_TRRD_S) |
||||
#define DDR_TRFC_M 0x7f |
||||
#define DDR_TRFC_S 17 |
||||
#define DDR_TRFC(x) (((x) & DDR_TRFC_M) << DDR_TRFC_S) |
||||
#define DDR_TMRD_M 0xf |
||||
#define DDR_TMRD_S 23 |
||||
#define DDR_TMRD(x) (((x) & DDR_TMRD_M) << DDR_TMRD_S) |
||||
#define DDR_CAS_L_M 0x17 |
||||
#define DDR_CAS_L_S 27 |
||||
#define DDR_CAS_L(x) (((x) & DDR_CAS_L_M) << DDR_CAS_L_S) |
||||
#define DDR_OPEN BIT(30) |
||||
#define DDR1_CONF_REG_VAL (DDR_TRAS(16) | DDR_TRCD(6) | \ |
||||
DDR_TRP(6) | DDR_TRRD(4) | \
|
||||
DDR_TRFC(7) | DDR_TMRD(5) | \
|
||||
DDR_CAS_L(7) | DDR_OPEN) |
||||
#define DDR2_CONF_REG_VAL (DDR_TRAS(27) | DDR_TRCD(9) | \ |
||||
DDR_TRP(9) | DDR_TRRD(7) | \
|
||||
DDR_TRFC(21) | DDR_TMRD(15) | \
|
||||
DDR_CAS_L(17) | DDR_OPEN) |
||||
|
||||
#define DDR_BURST_LEN_S 0 |
||||
#define DDR_BURST_LEN_M 0xf |
||||
#define DDR_BURST_LEN(x) ((x) << DDR_BURST_LEN_S) |
||||
#define DDR_BURST_TYPE BIT(4) |
||||
#define DDR_CNTL_OE_EN BIT(5) |
||||
#define DDR_PHASE_SEL BIT(6) |
||||
#define DDR_CKE BIT(7) |
||||
#define DDR_TWR_S 8 |
||||
#define DDR_TWR_M 0xf |
||||
#define DDR_TWR(x) (((x) & DDR_TWR_M) << DDR_TWR_S) |
||||
#define DDR_TRTW_S 12 |
||||
#define DDR_TRTW_M 0x1f |
||||
#define DDR_TRTW(x) (((x) & DDR_TRTW_M) << DDR_TRTW_S) |
||||
#define DDR_TRTP_S 17 |
||||
#define DDR_TRTP_M 0xf |
||||
#define DDR_TRTP(x) (((x) & DDR_TRTP_M) << DDR_TRTP_S) |
||||
#define DDR_TWTR_S 21 |
||||
#define DDR_TWTR_M 0x1f |
||||
#define DDR_TWTR(x) (((x) & DDR_TWTR_M) << DDR_TWTR_S) |
||||
#define DDR_G_OPEN_L_S 26 |
||||
#define DDR_G_OPEN_L_M 0xf |
||||
#define DDR_G_OPEN_L(x) ((x) << DDR_G_OPEN_L_S) |
||||
#define DDR_HALF_WIDTH_LOW BIT(31) |
||||
#define DDR1_CONF2_REG_VAL (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \ |
||||
DDR_CKE | DDR_TWR(13) | DDR_TRTW(14) | \
|
||||
DDR_TRTP(8) | DDR_TWTR(14) | \
|
||||
DDR_G_OPEN_L(6) | DDR_HALF_WIDTH_LOW) |
||||
#define DDR2_CONF2_REG_VAL (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \ |
||||
DDR_CKE | DDR_TWR(1) | DDR_TRTW(14) | \
|
||||
DDR_TRTP(9) | DDR_TWTR(21) | \
|
||||
DDR_G_OPEN_L(8) | DDR_HALF_WIDTH_LOW) |
||||
|
||||
#define DDR_TWR_MSB BIT(3) |
||||
#define DDR_TRAS_MSB BIT(2) |
||||
#define DDR_TRFC_MSB_M 0x3 |
||||
#define DDR_TRFC_MSB(x) (x) |
||||
#define DDR1_CONF3_REG_VAL 0 |
||||
#define DDR2_CONF3_REG_VAL (DDR_TWR_MSB | DDR_TRFC_MSB(2)) |
||||
|
||||
#define DDR_CTL_SRAM_TSEL BIT(30) |
||||
#define DDR_CTL_SRAM_GE0_SYNC BIT(20) |
||||
#define DDR_CTL_SRAM_GE1_SYNC BIT(19) |
||||
#define DDR_CTL_SRAM_USB_SYNC BIT(18) |
||||
#define DDR_CTL_SRAM_PCIE_SYNC BIT(17) |
||||
#define DDR_CTL_SRAM_WMAC_SYNC BIT(16) |
||||
#define DDR_CTL_SRAM_MISC1_SYNC BIT(15) |
||||
#define DDR_CTL_SRAM_MISC2_SYNC BIT(14) |
||||
#define DDR_CTL_PAD_DDR2_SEL BIT(6) |
||||
#define DDR_CTL_HALF_WIDTH BIT(1) |
||||
#define DDR_CTL_CONFIG_VAL (DDR_CTL_SRAM_TSEL | \ |
||||
DDR_CTL_SRAM_GE0_SYNC | \
|
||||
DDR_CTL_SRAM_GE1_SYNC | \
|
||||
DDR_CTL_SRAM_USB_SYNC | \
|
||||
DDR_CTL_SRAM_PCIE_SYNC | \
|
||||
DDR_CTL_SRAM_WMAC_SYNC | \
|
||||
DDR_CTL_HALF_WIDTH) |
||||
|
||||
#define DDR_BURST_GE0_MAX_BL_S 0 |
||||
#define DDR_BURST_GE0_MAX_BL_M 0xf |
||||
#define DDR_BURST_GE0_MAX_BL(x) \ |
||||
(((x) & DDR_BURST_GE0_MAX_BL_M) << DDR_BURST_GE0_MAX_BL_S) |
||||
#define DDR_BURST_GE1_MAX_BL_S 4 |
||||
#define DDR_BURST_GE1_MAX_BL_M 0xf |
||||
#define DDR_BURST_GE1_MAX_BL(x) \ |
||||
(((x) & DDR_BURST_GE1_MAX_BL_M) << DDR_BURST_GE1_MAX_BL_S) |
||||
#define DDR_BURST_PCIE_MAX_BL_S 8 |
||||
#define DDR_BURST_PCIE_MAX_BL_M 0xf |
||||
#define DDR_BURST_PCIE_MAX_BL(x) \ |
||||
(((x) & DDR_BURST_PCIE_MAX_BL_M) << DDR_BURST_PCIE_MAX_BL_S) |
||||
#define DDR_BURST_USB_MAX_BL_S 12 |
||||
#define DDR_BURST_USB_MAX_BL_M 0xf |
||||
#define DDR_BURST_USB_MAX_BL(x) \ |
||||
(((x) & DDR_BURST_USB_MAX_BL_M) << DDR_BURST_USB_MAX_BL_S) |
||||
#define DDR_BURST_CPU_MAX_BL_S 16 |
||||
#define DDR_BURST_CPU_MAX_BL_M 0xf |
||||
#define DDR_BURST_CPU_MAX_BL(x) \ |
||||
(((x) & DDR_BURST_CPU_MAX_BL_M) << DDR_BURST_CPU_MAX_BL_S) |
||||
#define DDR_BURST_RD_MAX_BL_S 20 |
||||
#define DDR_BURST_RD_MAX_BL_M 0xf |
||||
#define DDR_BURST_RD_MAX_BL(x) \ |
||||
(((x) & DDR_BURST_RD_MAX_BL_M) << DDR_BURST_RD_MAX_BL_S) |
||||
#define DDR_BURST_WR_MAX_BL_S 24 |
||||
#define DDR_BURST_WR_MAX_BL_M 0xf |
||||
#define DDR_BURST_WR_MAX_BL(x) \ |
||||
(((x) & DDR_BURST_WR_MAX_BL_M) << DDR_BURST_WR_MAX_BL_S) |
||||
#define DDR_BURST_RWP_MASK_EN_S 28 |
||||
#define DDR_BURST_RWP_MASK_EN_M 0x3 |
||||
#define DDR_BURST_RWP_MASK_EN(x) \ |
||||
(((x) & DDR_BURST_RWP_MASK_EN_M) << DDR_BURST_RWP_MASK_EN_S) |
||||
#define DDR_BURST_CPU_PRI_BE BIT(30) |
||||
#define DDR_BURST_CPU_PRI BIT(31) |
||||
#define DDR_BURST_VAL (DDR_BURST_CPU_PRI_BE | \ |
||||
DDR_BURST_RWP_MASK_EN(3) | \
|
||||
DDR_BURST_WR_MAX_BL(4) | \
|
||||
DDR_BURST_RD_MAX_BL(4) | \
|
||||
DDR_BURST_CPU_MAX_BL(4) | \
|
||||
DDR_BURST_USB_MAX_BL(4) | \
|
||||
DDR_BURST_PCIE_MAX_BL(4) | \
|
||||
DDR_BURST_GE1_MAX_BL(4) | \
|
||||
DDR_BURST_GE0_MAX_BL(4)) |
||||
|
||||
#define DDR_BURST_WMAC_MAX_BL_S 0 |
||||
#define DDR_BURST_WMAC_MAX_BL_M 0xf |
||||
#define DDR_BURST_WMAC_MAX_BL(x) \ |
||||
(((x) & DDR_BURST_WMAC_MAX_BL_M) << DDR_BURST_WMAC_MAX_BL_S) |
||||
#define DDR_BURST2_VAL DDR_BURST_WMAC_MAX_BL(4) |
||||
|
||||
#define DDR2_CONF_TWL_S 10 |
||||
#define DDR2_CONF_TWL_M 0xf |
||||
#define DDR2_CONF_TWL(x) \ |
||||
(((x) & DDR2_CONF_TWL_M) << DDR2_CONF_TWL_S) |
||||
#define DDR2_CONF_ODT BIT(9) |
||||
#define DDR2_CONF_TFAW_S 2 |
||||
#define DDR2_CONF_TFAW_M 0x3f |
||||
#define DDR2_CONF_TFAW(x) \ |
||||
(((x) & DDR2_CONF_TFAW_M) << DDR2_CONF_TFAW_S) |
||||
#define DDR2_CONF_EN BIT(0) |
||||
#define DDR2_CONF_VAL (DDR2_CONF_TWL(5) | \ |
||||
DDR2_CONF_TFAW(31) | \
|
||||
DDR2_CONF_ODT | \
|
||||
DDR2_CONF_EN) |
||||
|
||||
#define DDR1_EXT_MODE_VAL 0 |
||||
#define DDR2_EXT_MODE_VAL 0x402 |
||||
#define DDR2_EXT_MODE_OCD_VAL 0x782 |
||||
#define DDR1_MODE_DLL_VAL 0x133 |
||||
#define DDR2_MODE_DLL_VAL 0x143 |
||||
#define DDR1_MODE_VAL 0x33 |
||||
#define DDR2_MODE_VAL 0x43 |
||||
#define DDR1_TAP_VAL 0x20 |
||||
#define DDR2_TAP_VAL 0x10 |
||||
|
||||
#define DDR_REG_BIST_MASK_ADDR_0 0x2c |
||||
#define DDR_REG_BIST_MASK_ADDR_1 0x30 |
||||
#define DDR_REG_BIST_MASK_AHB_GE0_0 0x34 |
||||
#define DDR_REG_BIST_COMP_AHB_GE0_0 0x38 |
||||
#define DDR_REG_BIST_MASK_AHB_GE1_0 0x3c |
||||
#define DDR_REG_BIST_COMP_AHB_GE1_0 0x40 |
||||
#define DDR_REG_BIST_COMP_ADDR_0 0x64 |
||||
#define DDR_REG_BIST_COMP_ADDR_1 0x68 |
||||
#define DDR_REG_BIST_MASK_AHB_GE0_1 0x6c |
||||
#define DDR_REG_BIST_COMP_AHB_GE0_1 0x70 |
||||
#define DDR_REG_BIST_MASK_AHB_GE1_1 0x74 |
||||
#define DDR_REG_BIST_COMP_AHB_GE1_1 0x78 |
||||
#define DDR_REG_BIST 0x11c |
||||
#define DDR_REG_BIST_STATUS 0x120 |
||||
|
||||
#define DDR_BIST_COMP_CNT_S 1 |
||||
#define DDR_BIST_COMP_CNT_M 0xff |
||||
#define DDR_BIST_COMP_CNT(x) \ |
||||
(((x) & DDR_BIST_COMP_CNT_M) << DDR_BIST_COMP_CNT_S) |
||||
#define DDR_BIST_COMP_CNT_MASK \ |
||||
(DDR_BIST_COMP_CNT_M << DDR_BIST_COMP_CNT_S) |
||||
#define DDR_BIST_TEST_START BIT(0) |
||||
#define DDR_BIST_STATUS_DONE BIT(0) |
||||
|
||||
/* 4 Row Address Bits, 4 Column Address Bits, 2 BA bits */ |
||||
#define DDR_BIST_MASK_ADDR_VAL 0xfa5de83f |
||||
|
||||
#define DDR_TAP_MAGIC_VAL 0xaa55aa55 |
||||
#define DDR_TAP_MAX_VAL 0x40 |
||||
|
||||
void ddr_init(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 val; |
||||
|
||||
regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE, |
||||
MAP_NOCACHE); |
||||
val = get_bootstrap(); |
||||
if (val & QCA953X_BOOTSTRAP_DDR1) { |
||||
writel(DDR_CTL_CONFIG_VAL, regs + QCA953X_DDR_REG_CTL_CONF); |
||||
udelay(10); |
||||
|
||||
/* For 16-bit DDR */ |
||||
writel(0xffff, regs + AR71XX_DDR_REG_RD_CYCLE); |
||||
udelay(100); |
||||
|
||||
/* Burst size */ |
||||
writel(DDR_BURST_VAL, regs + QCA953X_DDR_REG_BURST); |
||||
udelay(100); |
||||
writel(DDR_BURST2_VAL, regs + QCA953X_DDR_REG_BURST2); |
||||
udelay(100); |
||||
|
||||
/* AHB maximum timeout */ |
||||
writel(0xfffff, regs + QCA953X_DDR_REG_TIMEOUT_MAX); |
||||
udelay(100); |
||||
|
||||
/* DRAM timing */ |
||||
writel(DDR1_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG); |
||||
udelay(100); |
||||
writel(DDR1_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2); |
||||
udelay(100); |
||||
writel(DDR1_CONF3_REG_VAL, regs + QCA953X_DDR_REG_CONFIG3); |
||||
udelay(100); |
||||
|
||||
/* Precharge All */ |
||||
writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* ODT disable, Full strength, Enable DLL */ |
||||
writel(DDR1_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR); |
||||
udelay(100); |
||||
|
||||
/* Update Extended Mode Register Set (EMRS) */ |
||||
writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Reset DLL, CAS Latency 3, Burst Length 8 */ |
||||
writel(DDR1_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE); |
||||
udelay(100); |
||||
|
||||
/* Update Mode Register Set (MRS) */ |
||||
writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Precharge All */ |
||||
writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Auto Refresh */ |
||||
writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Normal DLL, CAS Latency 3, Burst Length 8 */ |
||||
writel(DDR1_MODE_VAL, regs + AR71XX_DDR_REG_MODE); |
||||
udelay(100); |
||||
|
||||
/* Update Mode Register Set (MRS) */ |
||||
writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Refresh time control */ |
||||
writel(DDR_REFRESH_VAL, regs + AR71XX_DDR_REG_REFRESH); |
||||
udelay(100); |
||||
|
||||
/* DQS 0 Tap Control */ |
||||
writel(DDR1_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
|
||||
/* DQS 1 Tap Control */ |
||||
writel(DDR1_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
} else { |
||||
writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(10); |
||||
writel(DDR_CTL_CONFIG_VAL | DDR_CTL_PAD_DDR2_SEL, |
||||
regs + QCA953X_DDR_REG_CTL_CONF); |
||||
udelay(10); |
||||
|
||||
/* For 16-bit DDR */ |
||||
writel(0xffff, regs + AR71XX_DDR_REG_RD_CYCLE); |
||||
udelay(100); |
||||
|
||||
/* Burst size */ |
||||
writel(DDR_BURST_VAL, regs + QCA953X_DDR_REG_BURST); |
||||
udelay(100); |
||||
writel(DDR_BURST2_VAL, regs + QCA953X_DDR_REG_BURST2); |
||||
udelay(100); |
||||
|
||||
/* AHB maximum timeout */ |
||||
writel(0xfffff, regs + QCA953X_DDR_REG_TIMEOUT_MAX); |
||||
udelay(100); |
||||
|
||||
/* DRAM timing */ |
||||
writel(DDR2_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG); |
||||
udelay(100); |
||||
writel(DDR2_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2); |
||||
udelay(100); |
||||
writel(DDR2_CONF3_REG_VAL, regs + QCA953X_DDR_REG_CONFIG3); |
||||
udelay(100); |
||||
|
||||
/* Enable DDR2 */ |
||||
writel(DDR2_CONF_VAL, regs + QCA953X_DDR_REG_DDR2_CONFIG); |
||||
udelay(100); |
||||
|
||||
/* Precharge All */ |
||||
writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Update Extended Mode Register 2 Set (EMR2S) */ |
||||
writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Update Extended Mode Register 3 Set (EMR3S) */ |
||||
writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* 150 ohm, Reduced strength, Enable DLL */ |
||||
writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR); |
||||
udelay(100); |
||||
|
||||
/* Update Extended Mode Register Set (EMRS) */ |
||||
writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Reset DLL, CAS Latency 4, Burst Length 8 */ |
||||
writel(DDR2_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE); |
||||
udelay(100); |
||||
|
||||
/* Update Mode Register Set (MRS) */ |
||||
writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Precharge All */ |
||||
writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Auto Refresh */ |
||||
writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Normal DLL, CAS Latency 4, Burst Length 8 */ |
||||
writel(DDR2_MODE_VAL, regs + AR71XX_DDR_REG_MODE); |
||||
udelay(100); |
||||
|
||||
/* Mode Register Set (MRS) */ |
||||
writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Enable OCD, Enable DLL, Reduced Drive Strength */ |
||||
writel(DDR2_EXT_MODE_OCD_VAL, regs + AR71XX_DDR_REG_EMR); |
||||
udelay(100); |
||||
|
||||
/* Update Extended Mode Register Set (EMRS) */ |
||||
writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* OCD diable, Enable DLL, Reduced Drive Strength */ |
||||
writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR); |
||||
udelay(100); |
||||
|
||||
/* Update Extended Mode Register Set (EMRS) */ |
||||
writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL); |
||||
udelay(100); |
||||
|
||||
/* Refresh time control */ |
||||
writel(DDR_REFRESH_VAL, regs + AR71XX_DDR_REG_REFRESH); |
||||
udelay(100); |
||||
|
||||
/* DQS 0 Tap Control */ |
||||
writel(DDR2_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
|
||||
/* DQS 1 Tap Control */ |
||||
writel(DDR2_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
} |
||||
} |
||||
|
||||
void ddr_tap_tuning(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 val, pass, tap, cnt, tap_val, last, first; |
||||
|
||||
regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
tap_val = readl(regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
first = DDR_TAP_MAGIC_VAL; |
||||
last = 0; |
||||
cnt = 0; |
||||
tap = 0; |
||||
|
||||
do { |
||||
writel(tap, regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
writel(tap, regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
|
||||
writel(DDR_BIST_COMP_CNT(8), regs + DDR_REG_BIST_COMP_ADDR_1); |
||||
writel(DDR_BIST_MASK_ADDR_VAL, regs + DDR_REG_BIST_MASK_ADDR_0); |
||||
writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE0_1); |
||||
writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE1_0); |
||||
writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE1_1); |
||||
writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE0_0); |
||||
writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE0_1); |
||||
writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE1_0); |
||||
writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE1_1); |
||||
writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE0_0); |
||||
|
||||
/* Start BIST test */ |
||||
writel(DDR_BIST_TEST_START, regs + DDR_REG_BIST); |
||||
|
||||
do { |
||||
val = readl(regs + DDR_REG_BIST_STATUS); |
||||
} while (!(val & DDR_BIST_STATUS_DONE)); |
||||
|
||||
/* Stop BIST test */ |
||||
writel(0, regs + DDR_REG_BIST); |
||||
|
||||
pass = val & DDR_BIST_COMP_CNT_MASK; |
||||
pass ^= DDR_BIST_COMP_CNT(8); |
||||
if (!pass) { |
||||
if (first != DDR_TAP_MAGIC_VAL) { |
||||
last = tap; |
||||
} else { |
||||
first = tap; |
||||
last = tap; |
||||
} |
||||
cnt++; |
||||
} |
||||
tap++; |
||||
} while (tap < DDR_TAP_MAX_VAL); |
||||
|
||||
if (cnt) { |
||||
tap_val = (first + last) / 2; |
||||
tap_val %= DDR_TAP_MAX_VAL; |
||||
} |
||||
|
||||
writel(tap_val, regs + AR71XX_DDR_REG_TAP_CTRL0); |
||||
writel(tap_val, regs + AR71XX_DDR_REG_TAP_CTRL1); |
||||
} |
@ -0,0 +1,186 @@ |
||||
/* |
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
|
||||
* Based on Atheros LSDK/QSDK |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <config.h> |
||||
#include <asm/asm.h> |
||||
#include <asm/regdef.h> |
||||
#include <asm/mipsregs.h> |
||||
#include <asm/addrspace.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
|
||||
#define MK_PLL_CONF(divint, refdiv, range, outdiv) \ |
||||
(((0x3F & divint) << 10) | \ |
||||
((0x1F & refdiv) << 16) | \ |
||||
((0x1 & range) << 21) | \ |
||||
((0x7 & outdiv) << 23) ) |
||||
|
||||
#define MK_CLK_CNTL(cpudiv, ddrdiv, ahbdiv) \ |
||||
(((0x3 & (cpudiv - 1)) << 5) | \ |
||||
((0x3 & (ddrdiv - 1)) << 10) | \ |
||||
((0x3 & (ahbdiv - 1)) << 15) ) |
||||
|
||||
#define SET_FIELD(name, v) (((v) & QCA953X_##name##_MASK) << \ |
||||
QCA953X_##name##_SHIFT) |
||||
|
||||
#define DPLL2_KI(v) SET_FIELD(SRIF_DPLL2_KI, v) |
||||
#define DPLL2_KD(v) SET_FIELD(SRIF_DPLL2_KD, v) |
||||
#define DPLL2_PWD QCA953X_SRIF_DPLL2_PWD |
||||
#define MK_DPLL2(ki, kd) (DPLL2_KI(ki) | DPLL2_KD(kd) | DPLL2_PWD) |
||||
|
||||
#define PLL_CPU_NFRAC(v) SET_FIELD(PLL_CPU_CONFIG_NFRAC, v) |
||||
#define PLL_CPU_NINT(v) SET_FIELD(PLL_CPU_CONFIG_NINT, v) |
||||
#define PLL_CPU_REFDIV(v) SET_FIELD(PLL_CPU_CONFIG_REFDIV, v) |
||||
#define PLL_CPU_OUTDIV(v) SET_FIELD(PLL_CPU_CONFIG_OUTDIV, v) |
||||
#define MK_PLL_CPU_CONF(frac, nint, ref, outdiv) \ |
||||
(PLL_CPU_NFRAC(frac) | \ |
||||
PLL_CPU_NINT(nint) | \ |
||||
PLL_CPU_REFDIV(ref) | \ |
||||
PLL_CPU_OUTDIV(outdiv)) |
||||
|
||||
#define PLL_DDR_NFRAC(v) SET_FIELD(PLL_DDR_CONFIG_NFRAC, v) |
||||
#define PLL_DDR_NINT(v) SET_FIELD(PLL_DDR_CONFIG_NINT, v) |
||||
#define PLL_DDR_REFDIV(v) SET_FIELD(PLL_DDR_CONFIG_REFDIV, v) |
||||
#define PLL_DDR_OUTDIV(v) SET_FIELD(PLL_DDR_CONFIG_OUTDIV, v) |
||||
#define MK_PLL_DDR_CONF(frac, nint, ref, outdiv) \ |
||||
(PLL_DDR_NFRAC(frac) | \ |
||||
PLL_DDR_REFDIV(ref) | \ |
||||
PLL_DDR_NINT(nint) | \ |
||||
PLL_DDR_OUTDIV(outdiv) | \ |
||||
QCA953X_PLL_CONFIG_PWD) |
||||
|
||||
#define PLL_CPU_CONF_VAL MK_PLL_CPU_CONF(0, 26, 1, 0) |
||||
#define PLL_DDR_CONF_VAL MK_PLL_DDR_CONF(0, 15, 1, 0) |
||||
|
||||
#define PLL_CLK_CTRL_PLL_BYPASS (QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS | \ |
||||
QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS | \ |
||||
QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS) |
||||
|
||||
#define PLL_CLK_CTRL_CPU_DIV(v) SET_FIELD(PLL_CLK_CTRL_CPU_POST_DIV, v) |
||||
#define PLL_CLK_CTRL_DDR_DIV(v) SET_FIELD(PLL_CLK_CTRL_DDR_POST_DIV, v) |
||||
#define PLL_CLK_CTRL_AHB_DIV(v) SET_FIELD(PLL_CLK_CTRL_AHB_POST_DIV, v) |
||||
#define MK_PLL_CLK_CTRL(cpu, ddr, ahb) \ |
||||
(PLL_CLK_CTRL_CPU_DIV(cpu) | \ |
||||
PLL_CLK_CTRL_DDR_DIV(ddr) | \ |
||||
PLL_CLK_CTRL_AHB_DIV(ahb)) |
||||
#define PLL_CLK_CTRL_VAL (MK_PLL_CLK_CTRL(0, 0, 2) | \ |
||||
PLL_CLK_CTRL_PLL_BYPASS | \ |
||||
QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL | \ |
||||
QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL) |
||||
|
||||
#define PLL_DDR_DIT_FRAC_MAX(v) SET_FIELD(PLL_DDR_DIT_FRAC_MAX, v) |
||||
#define PLL_DDR_DIT_FRAC_MIN(v) SET_FIELD(PLL_DDR_DIT_FRAC_MIN, v) |
||||
#define PLL_DDR_DIT_FRAC_STEP(v) SET_FIELD(PLL_DDR_DIT_FRAC_STEP, v) |
||||
#define PLL_DDR_DIT_UPD_CNT(v) SET_FIELD(PLL_DDR_DIT_UPD_CNT, v) |
||||
#define PLL_CPU_DIT_FRAC_MAX(v) SET_FIELD(PLL_CPU_DIT_FRAC_MAX, v) |
||||
#define PLL_CPU_DIT_FRAC_MIN(v) SET_FIELD(PLL_CPU_DIT_FRAC_MIN, v) |
||||
#define PLL_CPU_DIT_FRAC_STEP(v) SET_FIELD(PLL_CPU_DIT_FRAC_STEP, v) |
||||
#define PLL_CPU_DIT_UPD_CNT(v) SET_FIELD(PLL_CPU_DIT_UPD_CNT, v) |
||||
#define MK_PLL_DDR_DIT_FRAC(max, min, step, cnt) \ |
||||
(QCA953X_PLL_DIT_FRAC_EN | \ |
||||
PLL_DDR_DIT_FRAC_MAX(max) | \ |
||||
PLL_DDR_DIT_FRAC_MIN(min) | \ |
||||
PLL_DDR_DIT_FRAC_STEP(step) | \ |
||||
PLL_DDR_DIT_UPD_CNT(cnt)) |
||||
#define MK_PLL_CPU_DIT_FRAC(max, min, step, cnt) \ |
||||
(QCA953X_PLL_DIT_FRAC_EN | \ |
||||
PLL_CPU_DIT_FRAC_MAX(max) | \ |
||||
PLL_CPU_DIT_FRAC_MIN(min) | \ |
||||
PLL_CPU_DIT_FRAC_STEP(step) | \ |
||||
PLL_CPU_DIT_UPD_CNT(cnt)) |
||||
#define PLL_CPU_DIT_FRAC_VAL MK_PLL_CPU_DIT_FRAC(63, 0, 1, 15) |
||||
#define PLL_DDR_DIT_FRAC_VAL MK_PLL_DDR_DIT_FRAC(763, 635, 1, 15) |
||||
|
||||
.text |
||||
.set noreorder
|
||||
|
||||
LEAF(lowlevel_init) |
||||
/* RTC Reset */ |
||||
li t0, CKSEG1ADDR(AR71XX_RESET_BASE) |
||||
lw t1, QCA953X_RESET_REG_RESET_MODULE(t0) |
||||
li t2, 0x08000000 |
||||
or t1, t1, t2 |
||||
sw t1, QCA953X_RESET_REG_RESET_MODULE(t0) |
||||
nop |
||||
lw t1, QCA953X_RESET_REG_RESET_MODULE(t0) |
||||
li t2, 0xf7ffffff |
||||
and t1, t1, t2 |
||||
sw t1, QCA953X_RESET_REG_RESET_MODULE(t0) |
||||
nop |
||||
|
||||
/* RTC Force Wake */ |
||||
li t0, CKSEG1ADDR(QCA953X_RTC_BASE) |
||||
li t1, 0x01 |
||||
sw t1, QCA953X_RTC_REG_SYNC_RESET(t0) |
||||
nop |
||||
nop |
||||
|
||||
/* Wait for RTC in on state */ |
||||
1: |
||||
lw t1, QCA953X_RTC_REG_SYNC_STATUS(t0) |
||||
andi t1, t1, 0x02 |
||||
beqz t1, 1b |
||||
nop |
||||
|
||||
li t0, CKSEG1ADDR(QCA953X_SRIF_BASE) |
||||
li t1, MK_DPLL2(2, 16) |
||||
sw t1, QCA953X_SRIF_BB_DPLL2_REG(t0) |
||||
sw t1, QCA953X_SRIF_PCIE_DPLL2_REG(t0) |
||||
sw t1, QCA953X_SRIF_DDR_DPLL2_REG(t0) |
||||
sw t1, QCA953X_SRIF_CPU_DPLL2_REG(t0) |
||||
|
||||
li t0, CKSEG1ADDR(AR71XX_PLL_BASE) |
||||
lw t1, QCA953X_PLL_CLK_CTRL_REG(t0) |
||||
ori t1, PLL_CLK_CTRL_PLL_BYPASS |
||||
sw t1, QCA953X_PLL_CLK_CTRL_REG(t0) |
||||
nop |
||||
|
||||
li t1, PLL_CPU_CONF_VAL |
||||
sw t1, QCA953X_PLL_CPU_CONFIG_REG(t0) |
||||
nop |
||||
|
||||
li t1, PLL_DDR_CONF_VAL |
||||
sw t1, QCA953X_PLL_DDR_CONFIG_REG(t0) |
||||
nop |
||||
|
||||
li t1, PLL_CLK_CTRL_VAL |
||||
sw t1, QCA953X_PLL_CLK_CTRL_REG(t0) |
||||
nop |
||||
|
||||
lw t1, QCA953X_PLL_CPU_CONFIG_REG(t0) |
||||
li t2, ~QCA953X_PLL_CONFIG_PWD |
||||
and t1, t1, t2 |
||||
sw t1, QCA953X_PLL_CPU_CONFIG_REG(t0) |
||||
nop |
||||
|
||||
lw t1, QCA953X_PLL_DDR_CONFIG_REG(t0) |
||||
li t2, ~QCA953X_PLL_CONFIG_PWD |
||||
and t1, t1, t2 |
||||
sw t1, QCA953X_PLL_DDR_CONFIG_REG(t0) |
||||
nop |
||||
|
||||
lw t1, QCA953X_PLL_CLK_CTRL_REG(t0) |
||||
li t2, ~PLL_CLK_CTRL_PLL_BYPASS |
||||
and t1, t1, t2 |
||||
sw t1, QCA953X_PLL_CLK_CTRL_REG(t0) |
||||
nop |
||||
|
||||
li t1, PLL_DDR_DIT_FRAC_VAL |
||||
sw t1, QCA953X_PLL_DDR_DIT_FRAC_REG(t0) |
||||
nop |
||||
|
||||
li t1, PLL_CPU_DIT_FRAC_VAL |
||||
sw t1, QCA953X_PLL_CPU_DIT_FRAC_REG(t0) |
||||
nop |
||||
|
||||
li t0, CKSEG1ADDR(AR71XX_RESET_BASE) |
||||
lui t1, 0x03fc |
||||
sw t1, 0xb4(t0) |
||||
|
||||
nop |
||||
jr ra |
||||
nop |
||||
END(lowlevel_init) |
@ -0,0 +1,208 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/errno.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ath79.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
|
||||
void _machine_restart(void) |
||||
{ |
||||
void __iomem *base; |
||||
u32 reg = 0; |
||||
|
||||
base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, |
||||
MAP_NOCACHE); |
||||
if (soc_is_ar71xx()) |
||||
reg = AR71XX_RESET_REG_RESET_MODULE; |
||||
else if (soc_is_ar724x()) |
||||
reg = AR724X_RESET_REG_RESET_MODULE; |
||||
else if (soc_is_ar913x()) |
||||
reg = AR913X_RESET_REG_RESET_MODULE; |
||||
else if (soc_is_ar933x()) |
||||
reg = AR933X_RESET_REG_RESET_MODULE; |
||||
else if (soc_is_ar934x()) |
||||
reg = AR934X_RESET_REG_RESET_MODULE; |
||||
else if (soc_is_qca953x()) |
||||
reg = QCA953X_RESET_REG_RESET_MODULE; |
||||
else if (soc_is_qca955x()) |
||||
reg = QCA955X_RESET_REG_RESET_MODULE; |
||||
else if (soc_is_qca956x()) |
||||
reg = QCA956X_RESET_REG_RESET_MODULE; |
||||
else |
||||
puts("Reset register not defined for this SOC\n"); |
||||
|
||||
if (reg) |
||||
setbits_be32(base + reg, AR71XX_RESET_FULL_CHIP); |
||||
|
||||
while (1) |
||||
/* NOP */; |
||||
} |
||||
|
||||
u32 get_bootstrap(void) |
||||
{ |
||||
void __iomem *base; |
||||
u32 reg = 0; |
||||
|
||||
base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, |
||||
MAP_NOCACHE); |
||||
if (soc_is_ar933x()) |
||||
reg = AR933X_RESET_REG_BOOTSTRAP; |
||||
else if (soc_is_ar934x()) |
||||
reg = AR934X_RESET_REG_BOOTSTRAP; |
||||
else if (soc_is_qca953x()) |
||||
reg = QCA953X_RESET_REG_BOOTSTRAP; |
||||
else if (soc_is_qca955x()) |
||||
reg = QCA955X_RESET_REG_BOOTSTRAP; |
||||
else if (soc_is_qca956x()) |
||||
reg = QCA956X_RESET_REG_BOOTSTRAP; |
||||
else |
||||
puts("Bootstrap register not defined for this SOC\n"); |
||||
|
||||
if (reg) |
||||
return readl(base + reg); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int eth_init_ar933x(void) |
||||
{ |
||||
void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, |
||||
MAP_NOCACHE); |
||||
void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE, |
||||
MAP_NOCACHE); |
||||
void __iomem *gregs = map_physmem(AR933X_GMAC_BASE, AR933X_GMAC_SIZE, |
||||
MAP_NOCACHE); |
||||
const u32 mask = AR933X_RESET_GE0_MAC | AR933X_RESET_GE0_MDIO | |
||||
AR933X_RESET_GE1_MAC | AR933X_RESET_GE1_MDIO | |
||||
AR933X_RESET_ETH_SWITCH; |
||||
|
||||
/* Clear MDIO slave EN bit. */ |
||||
clrbits_be32(rregs + AR933X_RESET_REG_BOOTSTRAP, BIT(17)); |
||||
mdelay(10); |
||||
|
||||
/* Get Atheros S26 PHY out of reset. */ |
||||
clrsetbits_be32(pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG, |
||||
0x1f, 0x10); |
||||
mdelay(10); |
||||
|
||||
setbits_be32(rregs + AR933X_RESET_REG_RESET_MODULE, mask); |
||||
mdelay(10); |
||||
clrbits_be32(rregs + AR933X_RESET_REG_RESET_MODULE, mask); |
||||
mdelay(10); |
||||
|
||||
/* Configure AR93xx GMAC register. */ |
||||
clrsetbits_be32(gregs + AR933X_GMAC_REG_ETH_CFG, |
||||
AR933X_ETH_CFG_MII_GE0_MASTER | |
||||
AR933X_ETH_CFG_MII_GE0_SLAVE, |
||||
AR933X_ETH_CFG_MII_GE0_SLAVE); |
||||
return 0; |
||||
} |
||||
|
||||
static int eth_init_ar934x(void) |
||||
{ |
||||
void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, |
||||
MAP_NOCACHE); |
||||
void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE, |
||||
MAP_NOCACHE); |
||||
void __iomem *gregs = map_physmem(AR934X_GMAC_BASE, AR934X_GMAC_SIZE, |
||||
MAP_NOCACHE); |
||||
const u32 mask = AR934X_RESET_GE0_MAC | AR934X_RESET_GE0_MDIO | |
||||
AR934X_RESET_GE1_MAC | AR934X_RESET_GE1_MDIO | |
||||
AR934X_RESET_ETH_SWITCH_ANALOG; |
||||
u32 reg; |
||||
|
||||
reg = readl(rregs + AR934X_RESET_REG_BOOTSTRAP); |
||||
if (reg & AR934X_BOOTSTRAP_REF_CLK_40) |
||||
writel(0x570, pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG); |
||||
else |
||||
writel(0x271, pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG); |
||||
writel(BIT(26) | BIT(25), pregs + AR934X_PLL_ETH_XMII_CONTROL_REG); |
||||
|
||||
setbits_be32(rregs + AR934X_RESET_REG_RESET_MODULE, mask); |
||||
mdelay(1); |
||||
clrbits_be32(rregs + AR934X_RESET_REG_RESET_MODULE, mask); |
||||
mdelay(1); |
||||
|
||||
/* Configure AR934x GMAC register. */ |
||||
writel(AR934X_ETH_CFG_RGMII_GMAC0, gregs + AR934X_GMAC_REG_ETH_CFG); |
||||
return 0; |
||||
} |
||||
|
||||
int ath79_eth_reset(void) |
||||
{ |
||||
/*
|
||||
* Un-reset ethernet. DM still doesn't have any notion of reset |
||||
* framework, so we do it by hand here. |
||||
*/ |
||||
if (soc_is_ar933x()) |
||||
return eth_init_ar933x(); |
||||
if (soc_is_ar934x()) |
||||
return eth_init_ar934x(); |
||||
|
||||
return -EINVAL; |
||||
} |
||||
|
||||
static int usb_reset_ar933x(void __iomem *reset_regs) |
||||
{ |
||||
/* Ungate the USB block */ |
||||
setbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE, |
||||
AR933X_RESET_USBSUS_OVERRIDE); |
||||
mdelay(1); |
||||
clrbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE, |
||||
AR933X_RESET_USB_HOST); |
||||
mdelay(1); |
||||
clrbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE, |
||||
AR933X_RESET_USB_PHY); |
||||
mdelay(1); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int usb_reset_ar934x(void __iomem *reset_regs) |
||||
{ |
||||
/* Ungate the USB block */ |
||||
setbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE, |
||||
AR934X_RESET_USBSUS_OVERRIDE); |
||||
mdelay(1); |
||||
clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE, |
||||
AR934X_RESET_USB_PHY); |
||||
mdelay(1); |
||||
clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE, |
||||
AR934X_RESET_USB_PHY_ANALOG); |
||||
mdelay(1); |
||||
clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE, |
||||
AR934X_RESET_USB_HOST); |
||||
mdelay(1); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int ath79_usb_reset(void) |
||||
{ |
||||
void __iomem *usbc_regs = map_physmem(AR71XX_USB_CTRL_BASE, |
||||
AR71XX_USB_CTRL_SIZE, |
||||
MAP_NOCACHE); |
||||
void __iomem *reset_regs = map_physmem(AR71XX_RESET_BASE, |
||||
AR71XX_RESET_SIZE, |
||||
MAP_NOCACHE); |
||||
/*
|
||||
* Turn on the Buff and Desc swap bits. |
||||
* NOTE: This write into an undocumented register in mandatory to |
||||
* get the USB controller operational in BigEndian mode. |
||||
*/ |
||||
writel(0xf0000, usbc_regs + AR71XX_USB_CTRL_REG_CONFIG); |
||||
|
||||
if (soc_is_ar933x()) |
||||
return usb_reset_ar933x(reset_regs); |
||||
if (soc_is_ar934x()) |
||||
return usb_reset_ar934x(reset_regs); |
||||
|
||||
return -EINVAL; |
||||
} |
@ -0,0 +1,12 @@ |
||||
if TARGET_AP121 |
||||
|
||||
config SYS_VENDOR |
||||
default "qca" |
||||
|
||||
config SYS_BOARD |
||||
default "ap121" |
||||
|
||||
config SYS_CONFIG_NAME |
||||
default "ap121" |
||||
|
||||
endif |
@ -0,0 +1,6 @@ |
||||
AP121 BOARD |
||||
M: Wills Wang <wills.wang@live.com> |
||||
S: Maintained |
||||
F: board/qca/ap121/ |
||||
F: include/configs/ap121.h |
||||
F: configs/ap121_defconfig |
@ -0,0 +1,5 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y = ap121.o
|
@ -0,0 +1,50 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/ddr.h> |
||||
#include <debug_uart.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
#ifdef CONFIG_DEBUG_UART_BOARD_INIT |
||||
void board_debug_uart_init(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 val; |
||||
|
||||
regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
/*
|
||||
* GPIO9 as input, GPIO10 as output |
||||
*/ |
||||
val = readl(regs + AR71XX_GPIO_REG_OE); |
||||
val &= ~AR933X_GPIO(9); |
||||
val |= AR933X_GPIO(10); |
||||
writel(val, regs + AR71XX_GPIO_REG_OE); |
||||
|
||||
/*
|
||||
* Enable UART, GPIO9 as UART_SI, GPIO10 as UART_SO |
||||
*/ |
||||
val = readl(regs + AR71XX_GPIO_REG_FUNC); |
||||
val |= AR933X_GPIO_FUNC_UART_EN | AR933X_GPIO_FUNC_RES_TRUE; |
||||
writel(val, regs + AR71XX_GPIO_REG_FUNC); |
||||
} |
||||
#endif |
||||
|
||||
int board_early_init_f(void) |
||||
{ |
||||
#ifdef CONFIG_DEBUG_UART |
||||
debug_uart_init(); |
||||
#endif |
||||
ddr_init(); |
||||
return 0; |
||||
} |
@ -0,0 +1,12 @@ |
||||
if TARGET_AP143 |
||||
|
||||
config SYS_VENDOR |
||||
default "qca" |
||||
|
||||
config SYS_BOARD |
||||
default "ap143" |
||||
|
||||
config SYS_CONFIG_NAME |
||||
default "ap143" |
||||
|
||||
endif |
@ -0,0 +1,6 @@ |
||||
AP143 BOARD |
||||
M: Wills Wang <wills.wang@live.com> |
||||
S: Maintained |
||||
F: board/qca/ap143/ |
||||
F: include/configs/ap143.h |
||||
F: configs/ap143_defconfig |
@ -0,0 +1,5 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y = ap143.o
|
@ -0,0 +1,66 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/ddr.h> |
||||
#include <debug_uart.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
#ifdef CONFIG_DEBUG_UART_BOARD_INIT |
||||
void board_debug_uart_init(void) |
||||
{ |
||||
void __iomem *regs; |
||||
u32 val; |
||||
|
||||
regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
/*
|
||||
* GPIO9 as input, GPIO10 as output |
||||
*/ |
||||
val = readl(regs + AR71XX_GPIO_REG_OE); |
||||
val |= QCA953X_GPIO(9); |
||||
val &= ~QCA953X_GPIO(10); |
||||
writel(val, regs + AR71XX_GPIO_REG_OE); |
||||
|
||||
/*
|
||||
* Enable GPIO10 as UART0_SOUT |
||||
*/ |
||||
val = readl(regs + QCA953X_GPIO_REG_OUT_FUNC2); |
||||
val &= ~QCA953X_GPIO_MUX_MASK(16); |
||||
val |= QCA953X_GPIO_OUT_MUX_UART0_SOUT << 16; |
||||
writel(val, regs + QCA953X_GPIO_REG_OUT_FUNC2); |
||||
|
||||
/*
|
||||
* Enable GPIO9 as UART0_SIN |
||||
*/ |
||||
val = readl(regs + QCA953X_GPIO_REG_IN_ENABLE0); |
||||
val &= ~QCA953X_GPIO_MUX_MASK(8); |
||||
val |= QCA953X_GPIO_IN_MUX_UART0_SIN << 8; |
||||
writel(val, regs + QCA953X_GPIO_REG_IN_ENABLE0); |
||||
|
||||
/*
|
||||
* Enable GPIO10 output |
||||
*/ |
||||
val = readl(regs + AR71XX_GPIO_REG_OUT); |
||||
val |= QCA953X_GPIO(10); |
||||
writel(val, regs + AR71XX_GPIO_REG_OUT); |
||||
} |
||||
#endif |
||||
|
||||
int board_early_init_f(void) |
||||
{ |
||||
#ifdef CONFIG_DEBUG_UART |
||||
debug_uart_init(); |
||||
#endif |
||||
ddr_init(); |
||||
return 0; |
||||
} |
@ -0,0 +1,15 @@ |
||||
if BOARD_TPLINK_WDR4300 |
||||
|
||||
config SYS_VENDOR |
||||
default "tplink" |
||||
|
||||
config SYS_SOC |
||||
default "ath79" |
||||
|
||||
config SYS_BOARD |
||||
default "wdr4300" |
||||
|
||||
config SYS_CONFIG_NAME |
||||
default "tplink_wdr4300" |
||||
|
||||
endif |
@ -0,0 +1,6 @@ |
||||
TPLINK_WDR4300 BOARD |
||||
M: Marek Vasut <marex@denx.de> |
||||
S: Maintained |
||||
F: board/tplink/wdr4300/ |
||||
F: include/configs/tplink_wdr4300.h |
||||
F: configs/tplink_wdr4300_defconfig |
@ -0,0 +1,5 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y = wdr4300.o
|
@ -0,0 +1,74 @@ |
||||
/*
|
||||
* Copyright (C) 2016 Marek Vasut <marex@denx.de> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/addrspace.h> |
||||
#include <asm/types.h> |
||||
#include <mach/ath79.h> |
||||
#include <mach/ar71xx_regs.h> |
||||
#include <mach/ddr.h> |
||||
#include <debug_uart.h> |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
#ifdef CONFIG_USB |
||||
static void wdr4300_usb_start(void) |
||||
{ |
||||
void __iomem *gpio_regs = map_physmem(AR71XX_GPIO_BASE, |
||||
AR71XX_GPIO_SIZE, MAP_NOCACHE); |
||||
if (!gpio_regs) |
||||
return; |
||||
|
||||
/* Power up the USB HUB. */ |
||||
clrbits_be32(gpio_regs + AR71XX_GPIO_REG_OE, BIT(21) | BIT(22)); |
||||
writel(BIT(21) | BIT(22), gpio_regs + AR71XX_GPIO_REG_SET); |
||||
mdelay(1); |
||||
|
||||
ath79_usb_reset(); |
||||
} |
||||
#else |
||||
static inline void wdr4300_usb_start(void) {} |
||||
#endif |
||||
|
||||
#ifdef CONFIG_BOARD_EARLY_INIT_F |
||||
int board_early_init_f(void) |
||||
{ |
||||
void __iomem *regs; |
||||
|
||||
regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE, |
||||
MAP_NOCACHE); |
||||
|
||||
/* Assure JTAG is not disconnected. */ |
||||
writel(0x40, regs + AR934X_GPIO_REG_FUNC); |
||||
|
||||
/* Configure default GPIO input/output regs. */ |
||||
writel(0x3031b, regs + AR71XX_GPIO_REG_OE); |
||||
writel(0x0f804, regs + AR71XX_GPIO_REG_OUT); |
||||
|
||||
/* Configure pin multiplexing. */ |
||||
writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC0); |
||||
writel(0x0b0a0980, regs + AR934X_GPIO_REG_OUT_FUNC1); |
||||
writel(0x00180000, regs + AR934X_GPIO_REG_OUT_FUNC2); |
||||
writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC3); |
||||
writel(0x0000004d, regs + AR934X_GPIO_REG_OUT_FUNC4); |
||||
writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC5); |
||||
|
||||
#ifdef CONFIG_DEBUG_UART |
||||
debug_uart_init(); |
||||
#endif |
||||
|
||||
#ifndef CONFIG_SKIP_LOWLEVEL_INIT |
||||
ar934x_pll_init(560, 480, 240); |
||||
ar934x_ddr_init(560, 480, 240); |
||||
#endif |
||||
|
||||
wdr4300_usb_start(); |
||||
ath79_eth_reset(); |
||||
|
||||
return 0; |
||||
} |
||||
#endif |
@ -0,0 +1,250 @@ |
||||
/*
|
||||
* (C) Copyright 2009-2016 CompuLab, Ltd. |
||||
* |
||||
* Authors: Nikita Kiryanov <nikita@compulab.co.il> |
||||
* Igor Grinberg <grinberg@compulab.co.il> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <linux/string.h> |
||||
#include <eeprom_field.h> |
||||
|
||||
static void __eeprom_field_print_bin(const struct eeprom_field *field, |
||||
char *delimiter, bool reverse) |
||||
{ |
||||
int i; |
||||
int from = reverse ? field->size - 1 : 0; |
||||
int to = reverse ? 0 : field->size - 1; |
||||
|
||||
printf(PRINT_FIELD_SEGMENT, field->name); |
||||
for (i = from; i != to; reverse ? i-- : i++) |
||||
printf("%02x%s", field->buf[i], delimiter); |
||||
|
||||
printf("%02x\n", field->buf[i]); |
||||
} |
||||
|
||||
static int __eeprom_field_update_bin(struct eeprom_field *field, |
||||
const char *value, bool reverse) |
||||
{ |
||||
int len = strlen(value); |
||||
int k, j, i = reverse ? len - 1 : 0; |
||||
unsigned char byte; |
||||
char *endptr; |
||||
|
||||
/* each two characters in the string fit in one byte */ |
||||
if (len > field->size * 2) |
||||
return -1; |
||||
|
||||
memset(field->buf, 0, field->size); |
||||
|
||||
/* i - string iterator, j - buf iterator */ |
||||
for (j = 0; j < field->size; j++) { |
||||
byte = 0; |
||||
char tmp[3] = { 0, 0, 0 }; |
||||
|
||||
if ((reverse && i < 0) || (!reverse && i >= len)) |
||||
break; |
||||
|
||||
for (k = 0; k < 2; k++) { |
||||
if (reverse && i == 0) { |
||||
tmp[k] = value[i]; |
||||
break; |
||||
} |
||||
|
||||
tmp[k] = value[reverse ? i - 1 + k : i + k]; |
||||
} |
||||
|
||||
byte = simple_strtoul(tmp, &endptr, 0); |
||||
if (*endptr != '\0' || byte < 0) |
||||
return -1; |
||||
|
||||
field->buf[j] = byte; |
||||
i = reverse ? i - 2 : i + 2; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int __eeprom_field_update_bin_delim(struct eeprom_field *field, |
||||
char *value, char *delimiter) |
||||
{ |
||||
int count = 0; |
||||
int i, val; |
||||
const char *tmp = value; |
||||
char *tok; |
||||
char *endptr; |
||||
|
||||
tmp = strstr(tmp, delimiter); |
||||
while (tmp != NULL) { |
||||
count++; |
||||
tmp++; |
||||
tmp = strstr(tmp, delimiter); |
||||
} |
||||
|
||||
if (count > field->size) |
||||
return -1; |
||||
|
||||
tok = strtok(value, delimiter); |
||||
for (i = 0; tok && i < field->size; i++) { |
||||
val = simple_strtoul(tok, &endptr, 0); |
||||
if (*endptr != '\0') |
||||
return -1; |
||||
|
||||
/* here we assume that each tok is no more than byte long */ |
||||
field->buf[i] = (unsigned char)val; |
||||
tok = strtok(NULL, delimiter); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_print_bin() - print a field which contains binary data |
||||
* |
||||
* Treat the field data as simple binary data, and print it as two digit |
||||
* hexadecimal values. |
||||
* Sample output: |
||||
* Field Name 0102030405060708090a |
||||
* |
||||
* @field: an initialized field to print |
||||
*/ |
||||
void eeprom_field_print_bin(const struct eeprom_field *field) |
||||
{ |
||||
__eeprom_field_print_bin(field, "", false); |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_update_bin() - Update field with new data in binary form |
||||
* |
||||
* @field: an initialized field |
||||
* @value: a string of values (i.e. "10b234a") |
||||
*/ |
||||
int eeprom_field_update_bin(struct eeprom_field *field, char *value) |
||||
{ |
||||
return __eeprom_field_update_bin(field, value, false); |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_update_reserved() - Update reserved field with new data in |
||||
* binary form |
||||
* |
||||
* @field: an initialized field |
||||
* @value: a space delimited string of byte values (i.e. "1 02 3 0x4") |
||||
*/ |
||||
int eeprom_field_update_reserved(struct eeprom_field *field, char *value) |
||||
{ |
||||
return __eeprom_field_update_bin_delim(field, value, " "); |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_print_bin_rev() - print a field which contains binary data in |
||||
* reverse order |
||||
* |
||||
* Treat the field data as simple binary data, and print it in reverse order |
||||
* as two digit hexadecimal values. |
||||
* |
||||
* Data in field: |
||||
* 0102030405060708090a |
||||
* Sample output: |
||||
* Field Name 0a090807060504030201 |
||||
* |
||||
* @field: an initialized field to print |
||||
*/ |
||||
void eeprom_field_print_bin_rev(const struct eeprom_field *field) |
||||
{ |
||||
__eeprom_field_print_bin(field, "", true); |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_update_bin_rev() - Update field with new data in binary form, |
||||
* storing it in reverse |
||||
* |
||||
* This function takes a string of byte values, and stores them |
||||
* in the field in the reverse order. i.e. if the input string was "1234", |
||||
* "3412" will be written to the field. |
||||
* |
||||
* @field: an initialized field |
||||
* @value: a string of byte values |
||||
*/ |
||||
int eeprom_field_update_bin_rev(struct eeprom_field *field, char *value) |
||||
{ |
||||
return __eeprom_field_update_bin(field, value, true); |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_print_mac_addr() - print a field which contains a mac address |
||||
* |
||||
* Treat the field data as simple binary data, and print it formatted as a MAC |
||||
* address. |
||||
* Sample output: |
||||
* Field Name 01:02:03:04:05:06 |
||||
* |
||||
* @field: an initialized field to print |
||||
*/ |
||||
void eeprom_field_print_mac(const struct eeprom_field *field) |
||||
{ |
||||
__eeprom_field_print_bin(field, ":", false); |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_update_mac() - Update a mac address field which contains binary |
||||
* data |
||||
* |
||||
* @field: an initialized field |
||||
* @value: a colon delimited string of byte values (i.e. "1:02:3:ff") |
||||
*/ |
||||
int eeprom_field_update_mac(struct eeprom_field *field, char *value) |
||||
{ |
||||
return __eeprom_field_update_bin_delim(field, value, ":"); |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_print_ascii() - print a field which contains ASCII data |
||||
* @field: an initialized field to print |
||||
*/ |
||||
void eeprom_field_print_ascii(const struct eeprom_field *field) |
||||
{ |
||||
char format[8]; |
||||
|
||||
sprintf(format, "%%.%ds\n", field->size); |
||||
printf(PRINT_FIELD_SEGMENT, field->name); |
||||
printf(format, field->buf); |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_update_ascii() - Update field with new data in ASCII form |
||||
* @field: an initialized field |
||||
* @value: the new string data |
||||
* |
||||
* Returns 0 on success, -1 of failure (new string too long). |
||||
*/ |
||||
int eeprom_field_update_ascii(struct eeprom_field *field, char *value) |
||||
{ |
||||
if (strlen(value) >= field->size) { |
||||
printf("%s: new data too long\n", field->name); |
||||
return -1; |
||||
} |
||||
|
||||
strncpy((char *)field->buf, value, field->size - 1); |
||||
field->buf[field->size - 1] = '\0'; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* eeprom_field_print_reserved() - print the "Reserved fields" field |
||||
* |
||||
* Print a notice that the following field_size bytes are reserved. |
||||
* |
||||
* Sample output: |
||||
* Reserved fields (64 bytes) |
||||
* |
||||
* @field: an initialized field to print |
||||
*/ |
||||
void eeprom_field_print_reserved(const struct eeprom_field *field) |
||||
{ |
||||
printf(PRINT_FIELD_SEGMENT, "Reserved fields\t"); |
||||
printf("(%d bytes)\n", field->size); |
||||
} |
@ -0,0 +1,125 @@ |
||||
/*
|
||||
* (C) Copyright 2009-2016 CompuLab, Ltd. |
||||
* |
||||
* Authors: Nikita Kiryanov <nikita@compulab.co.il> |
||||
* Igor Grinberg <grinberg@compulab.co.il> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <linux/kernel.h> |
||||
#include <eeprom_layout.h> |
||||
#include <eeprom_field.h> |
||||
|
||||
#define NO_LAYOUT_FIELDS "Unknown layout. Dumping raw data\n" |
||||
|
||||
struct eeprom_field layout_unknown[1] = { |
||||
{ NO_LAYOUT_FIELDS, 256, NULL, eeprom_field_print_bin, |
||||
eeprom_field_update_bin }, |
||||
}; |
||||
|
||||
/*
|
||||
* eeprom_layout_detect() - detect layout based on the contents of the data. |
||||
* @data: Pointer to the data to be analyzed. |
||||
* |
||||
* Returns: the detected layout version. |
||||
*/ |
||||
__weak int eeprom_layout_detect(unsigned char *data) |
||||
{ |
||||
return LAYOUT_VERSION_UNRECOGNIZED; |
||||
} |
||||
|
||||
/*
|
||||
* __eeprom_layout_assign() - set the layout fields |
||||
* @layout: A pointer to an existing struct layout. |
||||
* @layout_version: The version number of the desired layout |
||||
*/ |
||||
__weak void __eeprom_layout_assign(struct eeprom_layout *layout, |
||||
int layout_version) |
||||
{ |
||||
layout->fields = layout_unknown; |
||||
layout->num_of_fields = ARRAY_SIZE(layout_unknown); |
||||
} |
||||
void eeprom_layout_assign(struct eeprom_layout *layout, int layout_version) \
|
||||
__attribute__((weak, alias("__eeprom_layout_assign"))); |
||||
|
||||
/*
|
||||
* eeprom_layout_print() - print the layout and the data which is assigned to it |
||||
* @layout: A pointer to an existing struct layout. |
||||
*/ |
||||
static void eeprom_layout_print(const struct eeprom_layout *layout) |
||||
{ |
||||
int i; |
||||
struct eeprom_field *fields = layout->fields; |
||||
|
||||
for (i = 0; i < layout->num_of_fields; i++) |
||||
fields[i].print(&fields[i]); |
||||
} |
||||
|
||||
/*
|
||||
* eeprom_layout_update_field() - update a single field in the layout data. |
||||
* @layout: A pointer to an existing struct layout. |
||||
* @field_name: The name of the field to update. |
||||
* @new_data: The new field data (a string. Format depends on the field) |
||||
* |
||||
* Returns: 0 on success, negative error value on failure. |
||||
*/ |
||||
static int eeprom_layout_update_field(struct eeprom_layout *layout, |
||||
char *field_name, char *new_data) |
||||
{ |
||||
int i, err; |
||||
struct eeprom_field *fields = layout->fields; |
||||
|
||||
if (new_data == NULL) |
||||
return 0; |
||||
|
||||
if (field_name == NULL) |
||||
return -1; |
||||
|
||||
for (i = 0; i < layout->num_of_fields; i++) { |
||||
if (fields[i].name == RESERVED_FIELDS || |
||||
strcmp(fields[i].name, field_name)) |
||||
continue; |
||||
|
||||
err = fields[i].update(&fields[i], new_data); |
||||
if (err) |
||||
printf("Invalid data for field %s\n", field_name); |
||||
|
||||
return err; |
||||
} |
||||
|
||||
printf("No such field '%s'\n", field_name); |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
/*
|
||||
* eeprom_layout_setup() - setup layout struct with the layout data and |
||||
* metadata as dictated by layout_version |
||||
* @layout: A pointer to an existing struct layout. |
||||
* @buf: A buffer initialized with the eeprom data. |
||||
* @buf_size: Size of buf in bytes. |
||||
* @layout version: The version number of the layout. |
||||
*/ |
||||
void eeprom_layout_setup(struct eeprom_layout *layout, unsigned char *buf, |
||||
unsigned int buf_size, int layout_version) |
||||
{ |
||||
int i; |
||||
|
||||
if (layout_version == LAYOUT_VERSION_AUTODETECT) |
||||
layout->layout_version = eeprom_layout_detect(buf); |
||||
else |
||||
layout->layout_version = layout_version; |
||||
|
||||
eeprom_layout_assign(layout, layout_version); |
||||
layout->data = buf; |
||||
for (i = 0; i < layout->num_of_fields; i++) { |
||||
layout->fields[i].buf = buf; |
||||
buf += layout->fields[i].size; |
||||
} |
||||
|
||||
layout->data_size = buf_size; |
||||
layout->print = eeprom_layout_print; |
||||
layout->update = eeprom_layout_update_field; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,115 @@ |
||||
/*
|
||||
* Copyright (C) 2000-2005, DENX Software Engineering |
||||
* Wolfgang Denk <wd@denx.de> |
||||
* Copyright (C) Procsys. All rights reserved. |
||||
* Mushtaq Khan <mushtaq_k@procsys.com> |
||||
* <mushtaqk_921@yahoo.co.in> |
||||
* Copyright (C) 2008 Freescale Semiconductor, Inc. |
||||
* Dave Liu <daveliu@freescale.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <sata.h> |
||||
|
||||
struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; |
||||
|
||||
#ifdef CONFIG_PARTITIONS |
||||
struct blk_desc *sata_get_dev(int dev) |
||||
{ |
||||
return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL; |
||||
} |
||||
#endif |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static unsigned long sata_bread(struct udevice *dev, lbaint_t start, |
||||
lbaint_t blkcnt, void *dst) |
||||
{ |
||||
return -ENOSYS; |
||||
} |
||||
|
||||
static unsigned long sata_bwrite(struct udevice *dev, lbaint_t start, |
||||
lbaint_t blkcnt, const void *buffer) |
||||
{ |
||||
return -ENOSYS; |
||||
} |
||||
#else |
||||
static unsigned long sata_bread(struct blk_desc *block_dev, lbaint_t start, |
||||
lbaint_t blkcnt, void *dst) |
||||
{ |
||||
return sata_read(block_dev->devnum, start, blkcnt, dst); |
||||
} |
||||
|
||||
static unsigned long sata_bwrite(struct blk_desc *block_dev, lbaint_t start, |
||||
lbaint_t blkcnt, const void *buffer) |
||||
{ |
||||
return sata_write(block_dev->devnum, start, blkcnt, buffer); |
||||
} |
||||
#endif |
||||
|
||||
int __sata_initialize(void) |
||||
{ |
||||
int rc; |
||||
int i; |
||||
|
||||
for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) { |
||||
memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc)); |
||||
sata_dev_desc[i].if_type = IF_TYPE_SATA; |
||||
sata_dev_desc[i].devnum = i; |
||||
sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN; |
||||
sata_dev_desc[i].type = DEV_TYPE_HARDDISK; |
||||
sata_dev_desc[i].lba = 0; |
||||
sata_dev_desc[i].blksz = 512; |
||||
sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz); |
||||
#ifndef CONFIG_BLK |
||||
sata_dev_desc[i].block_read = sata_bread; |
||||
sata_dev_desc[i].block_write = sata_bwrite; |
||||
#endif |
||||
rc = init_sata(i); |
||||
if (!rc) { |
||||
rc = scan_sata(i); |
||||
if (!rc && sata_dev_desc[i].lba > 0 && |
||||
sata_dev_desc[i].blksz > 0) |
||||
part_init(&sata_dev_desc[i]); |
||||
} |
||||
} |
||||
|
||||
return rc; |
||||
} |
||||
int sata_initialize(void) __attribute__((weak, alias("__sata_initialize"))); |
||||
|
||||
__weak int __sata_stop(void) |
||||
{ |
||||
int i, err = 0; |
||||
|
||||
for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) |
||||
err |= reset_sata(i); |
||||
|
||||
if (err) |
||||
printf("Could not reset some SATA devices\n"); |
||||
|
||||
return err; |
||||
} |
||||
int sata_stop(void) __attribute__((weak, alias("__sata_stop"))); |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static const struct blk_ops sata_blk_ops = { |
||||
.read = sata_bread, |
||||
.write = sata_bwrite, |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(sata_blk) = { |
||||
.name = "sata_blk", |
||||
.id = UCLASS_BLK, |
||||
.ops = &sata_blk_ops, |
||||
}; |
||||
#else |
||||
U_BOOT_LEGACY_BLK(sata) = { |
||||
.if_typename = "sata", |
||||
.if_type = IF_TYPE_SATA, |
||||
.max_devs = CONFIG_SYS_SATA_MAX_DEVICE, |
||||
.desc = sata_dev_desc, |
||||
}; |
||||
#endif |
@ -0,0 +1,592 @@ |
||||
/*
|
||||
* (C) Copyright 2001 |
||||
* Denis Peter, MPL AG Switzerland |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <inttypes.h> |
||||
#include <pci.h> |
||||
#include <scsi.h> |
||||
|
||||
#ifdef CONFIG_SCSI_DEV_LIST |
||||
#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST |
||||
#else |
||||
#ifdef CONFIG_SCSI_SYM53C8XX |
||||
#define SCSI_VEND_ID 0x1000 |
||||
#ifndef CONFIG_SCSI_DEV_ID |
||||
#define SCSI_DEV_ID 0x0001 |
||||
#else |
||||
#define SCSI_DEV_ID CONFIG_SCSI_DEV_ID |
||||
#endif |
||||
#elif defined CONFIG_SATA_ULI5288 |
||||
|
||||
#define SCSI_VEND_ID 0x10b9 |
||||
#define SCSI_DEV_ID 0x5288 |
||||
|
||||
#elif !defined(CONFIG_SCSI_AHCI_PLAT) |
||||
#error no scsi device defined |
||||
#endif |
||||
#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} |
||||
#endif |
||||
|
||||
#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) |
||||
const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; |
||||
#endif |
||||
static ccb tempccb; /* temporary scsi command buffer */ |
||||
|
||||
static unsigned char tempbuff[512]; /* temporary data buffer */ |
||||
|
||||
static int scsi_max_devs; /* number of highest available scsi device */ |
||||
|
||||
static int scsi_curr_dev; /* current device */ |
||||
|
||||
static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; |
||||
|
||||
/* almost the maximum amount of the scsi_ext command.. */ |
||||
#define SCSI_MAX_READ_BLK 0xFFFF |
||||
#define SCSI_LBA48_READ 0xFFFFFFF |
||||
|
||||
#ifdef CONFIG_SYS_64BIT_LBA |
||||
void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks) |
||||
{ |
||||
pccb->cmd[0] = SCSI_READ16; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff; |
||||
pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff; |
||||
pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff; |
||||
pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff; |
||||
pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff; |
||||
pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff; |
||||
pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff; |
||||
pccb->cmd[9] = (unsigned char)start & 0xff; |
||||
pccb->cmd[10] = 0; |
||||
pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff; |
||||
pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff; |
||||
pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff; |
||||
pccb->cmd[14] = (unsigned char)blocks & 0xff; |
||||
pccb->cmd[15] = 0; |
||||
pccb->cmdlen = 16; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n", |
||||
pccb->cmd[0], pccb->cmd[1], |
||||
pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], |
||||
pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9], |
||||
pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]); |
||||
} |
||||
#endif |
||||
|
||||
void scsi_setup_read_ext(ccb *pccb, lbaint_t start, unsigned short blocks) |
||||
{ |
||||
pccb->cmd[0] = SCSI_READ10; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; |
||||
pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; |
||||
pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; |
||||
pccb->cmd[5] = (unsigned char)start & 0xff; |
||||
pccb->cmd[6] = 0; |
||||
pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; |
||||
pccb->cmd[8] = (unsigned char)blocks & 0xff; |
||||
pccb->cmd[6] = 0; |
||||
pccb->cmdlen = 10; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", |
||||
pccb->cmd[0], pccb->cmd[1], |
||||
pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], |
||||
pccb->cmd[7], pccb->cmd[8]); |
||||
} |
||||
|
||||
void scsi_setup_write_ext(ccb *pccb, lbaint_t start, unsigned short blocks) |
||||
{ |
||||
pccb->cmd[0] = SCSI_WRITE10; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; |
||||
pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; |
||||
pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; |
||||
pccb->cmd[5] = (unsigned char)start & 0xff; |
||||
pccb->cmd[6] = 0; |
||||
pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff; |
||||
pccb->cmd[8] = (unsigned char)blocks & 0xff; |
||||
pccb->cmd[9] = 0; |
||||
pccb->cmdlen = 10; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", |
||||
__func__, |
||||
pccb->cmd[0], pccb->cmd[1], |
||||
pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], |
||||
pccb->cmd[7], pccb->cmd[8]); |
||||
} |
||||
|
||||
void scsi_setup_read6(ccb *pccb, lbaint_t start, unsigned short blocks) |
||||
{ |
||||
pccb->cmd[0] = SCSI_READ6; |
||||
pccb->cmd[1] = pccb->lun << 5 | ((unsigned char)(start >> 16) & 0x1f); |
||||
pccb->cmd[2] = (unsigned char)(start >> 8) & 0xff; |
||||
pccb->cmd[3] = (unsigned char)start & 0xff; |
||||
pccb->cmd[4] = (unsigned char)blocks & 0xff; |
||||
pccb->cmd[5] = 0; |
||||
pccb->cmdlen = 6; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
debug("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n", |
||||
pccb->cmd[0], pccb->cmd[1], |
||||
pccb->cmd[2], pccb->cmd[3], pccb->cmd[4]); |
||||
} |
||||
|
||||
|
||||
void scsi_setup_inquiry(ccb *pccb) |
||||
{ |
||||
pccb->cmd[0] = SCSI_INQUIRY; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = 0; |
||||
pccb->cmd[3] = 0; |
||||
if (pccb->datalen > 255) |
||||
pccb->cmd[4] = 255; |
||||
else |
||||
pccb->cmd[4] = (unsigned char)pccb->datalen; |
||||
pccb->cmd[5] = 0; |
||||
pccb->cmdlen = 6; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
} |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, |
||||
void *buffer) |
||||
#else |
||||
static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr, |
||||
lbaint_t blkcnt, void *buffer) |
||||
#endif |
||||
{ |
||||
#ifdef CONFIG_BLK |
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(dev); |
||||
#endif |
||||
int device = block_dev->devnum; |
||||
lbaint_t start, blks; |
||||
uintptr_t buf_addr; |
||||
unsigned short smallblks = 0; |
||||
ccb *pccb = (ccb *)&tempccb; |
||||
device &= 0xff; |
||||
|
||||
/* Setup device */ |
||||
pccb->target = scsi_dev_desc[device].target; |
||||
pccb->lun = scsi_dev_desc[device].lun; |
||||
buf_addr = (unsigned long)buffer; |
||||
start = blknr; |
||||
blks = blkcnt; |
||||
debug("\nscsi_read: dev %d startblk " LBAF |
||||
", blccnt " LBAF " buffer %lx\n", |
||||
device, start, blks, (unsigned long)buffer); |
||||
do { |
||||
pccb->pdata = (unsigned char *)buf_addr; |
||||
#ifdef CONFIG_SYS_64BIT_LBA |
||||
if (start > SCSI_LBA48_READ) { |
||||
unsigned long blocks; |
||||
blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK); |
||||
pccb->datalen = scsi_dev_desc[device].blksz * blocks; |
||||
scsi_setup_read16(pccb, start, blocks); |
||||
start += blocks; |
||||
blks -= blocks; |
||||
} else |
||||
#endif |
||||
if (blks > SCSI_MAX_READ_BLK) { |
||||
pccb->datalen = scsi_dev_desc[device].blksz * |
||||
SCSI_MAX_READ_BLK; |
||||
smallblks = SCSI_MAX_READ_BLK; |
||||
scsi_setup_read_ext(pccb, start, smallblks); |
||||
start += SCSI_MAX_READ_BLK; |
||||
blks -= SCSI_MAX_READ_BLK; |
||||
} else { |
||||
pccb->datalen = scsi_dev_desc[device].blksz * blks; |
||||
smallblks = (unsigned short)blks; |
||||
scsi_setup_read_ext(pccb, start, smallblks); |
||||
start += blks; |
||||
blks = 0; |
||||
} |
||||
debug("scsi_read_ext: startblk " LBAF |
||||
", blccnt %x buffer %" PRIXPTR "\n", |
||||
start, smallblks, buf_addr); |
||||
if (scsi_exec(pccb) != true) { |
||||
scsi_print_error(pccb); |
||||
blkcnt -= blks; |
||||
break; |
||||
} |
||||
buf_addr += pccb->datalen; |
||||
} while (blks != 0); |
||||
debug("scsi_read_ext: end startblk " LBAF |
||||
", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr); |
||||
return blkcnt; |
||||
} |
||||
|
||||
/*******************************************************************************
|
||||
* scsi_write |
||||
*/ |
||||
|
||||
/* Almost the maximum amount of the scsi_ext command.. */ |
||||
#define SCSI_MAX_WRITE_BLK 0xFFFF |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, |
||||
const void *buffer) |
||||
#else |
||||
static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr, |
||||
lbaint_t blkcnt, const void *buffer) |
||||
#endif |
||||
{ |
||||
#ifdef CONFIG_BLK |
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(dev); |
||||
#endif |
||||
int device = block_dev->devnum; |
||||
lbaint_t start, blks; |
||||
uintptr_t buf_addr; |
||||
unsigned short smallblks; |
||||
ccb *pccb = (ccb *)&tempccb; |
||||
|
||||
device &= 0xff; |
||||
|
||||
/* Setup device */ |
||||
pccb->target = scsi_dev_desc[device].target; |
||||
pccb->lun = scsi_dev_desc[device].lun; |
||||
buf_addr = (unsigned long)buffer; |
||||
start = blknr; |
||||
blks = blkcnt; |
||||
debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n", |
||||
__func__, device, start, blks, (unsigned long)buffer); |
||||
do { |
||||
pccb->pdata = (unsigned char *)buf_addr; |
||||
if (blks > SCSI_MAX_WRITE_BLK) { |
||||
pccb->datalen = (scsi_dev_desc[device].blksz * |
||||
SCSI_MAX_WRITE_BLK); |
||||
smallblks = SCSI_MAX_WRITE_BLK; |
||||
scsi_setup_write_ext(pccb, start, smallblks); |
||||
start += SCSI_MAX_WRITE_BLK; |
||||
blks -= SCSI_MAX_WRITE_BLK; |
||||
} else { |
||||
pccb->datalen = scsi_dev_desc[device].blksz * blks; |
||||
smallblks = (unsigned short)blks; |
||||
scsi_setup_write_ext(pccb, start, smallblks); |
||||
start += blks; |
||||
blks = 0; |
||||
} |
||||
debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", |
||||
__func__, start, smallblks, buf_addr); |
||||
if (scsi_exec(pccb) != true) { |
||||
scsi_print_error(pccb); |
||||
blkcnt -= blks; |
||||
break; |
||||
} |
||||
buf_addr += pccb->datalen; |
||||
} while (blks != 0); |
||||
debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n", |
||||
__func__, start, smallblks, buf_addr); |
||||
return blkcnt; |
||||
} |
||||
|
||||
int scsi_get_disk_count(void) |
||||
{ |
||||
return scsi_max_devs; |
||||
} |
||||
|
||||
#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) |
||||
void scsi_init(void) |
||||
{ |
||||
int busdevfunc = -1; |
||||
int i; |
||||
/*
|
||||
* Find a device from the list, this driver will support a single |
||||
* controller. |
||||
*/ |
||||
for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { |
||||
/* get PCI Device ID */ |
||||
#ifdef CONFIG_DM_PCI |
||||
struct udevice *dev; |
||||
int ret; |
||||
|
||||
ret = dm_pci_find_device(scsi_device_list[i].vendor, |
||||
scsi_device_list[i].device, 0, &dev); |
||||
if (!ret) { |
||||
busdevfunc = dm_pci_get_bdf(dev); |
||||
break; |
||||
} |
||||
#else |
||||
busdevfunc = pci_find_device(scsi_device_list[i].vendor, |
||||
scsi_device_list[i].device, |
||||
0); |
||||
#endif |
||||
if (busdevfunc != -1) |
||||
break; |
||||
} |
||||
|
||||
if (busdevfunc == -1) { |
||||
printf("Error: SCSI Controller(s) "); |
||||
for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) { |
||||
printf("%04X:%04X ", |
||||
scsi_device_list[i].vendor, |
||||
scsi_device_list[i].device); |
||||
} |
||||
printf("not found\n"); |
||||
return; |
||||
} |
||||
#ifdef DEBUG |
||||
else { |
||||
printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n", |
||||
scsi_device_list[i].vendor, |
||||
scsi_device_list[i].device, |
||||
(busdevfunc >> 16) & 0xFF, |
||||
(busdevfunc >> 11) & 0x1F, |
||||
(busdevfunc >> 8) & 0x7); |
||||
} |
||||
#endif |
||||
bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci"); |
||||
scsi_low_level_init(busdevfunc); |
||||
scsi_scan(1); |
||||
bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI); |
||||
} |
||||
#endif |
||||
|
||||
/* copy src to dest, skipping leading and trailing blanks
|
||||
* and null terminate the string |
||||
*/ |
||||
void scsi_ident_cpy(unsigned char *dest, unsigned char *src, unsigned int len) |
||||
{ |
||||
int start, end; |
||||
|
||||
start = 0; |
||||
while (start < len) { |
||||
if (src[start] != ' ') |
||||
break; |
||||
start++; |
||||
} |
||||
end = len-1; |
||||
while (end > start) { |
||||
if (src[end] != ' ') |
||||
break; |
||||
end--; |
||||
} |
||||
for (; start <= end; start++) |
||||
*dest ++= src[start]; |
||||
*dest = '\0'; |
||||
} |
||||
|
||||
|
||||
/* Trim trailing blanks, and NUL-terminate string
|
||||
*/ |
||||
void scsi_trim_trail(unsigned char *str, unsigned int len) |
||||
{ |
||||
unsigned char *p = str + len - 1; |
||||
|
||||
while (len-- > 0) { |
||||
*p-- = '\0'; |
||||
if (*p != ' ') |
||||
return; |
||||
} |
||||
} |
||||
|
||||
int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz) |
||||
{ |
||||
*capacity = 0; |
||||
|
||||
memset(pccb->cmd, '\0', sizeof(pccb->cmd)); |
||||
pccb->cmd[0] = SCSI_RD_CAPAC10; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmdlen = 10; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
|
||||
pccb->datalen = 8; |
||||
if (scsi_exec(pccb) != true) |
||||
return 1; |
||||
|
||||
*capacity = ((lbaint_t)pccb->pdata[0] << 24) | |
||||
((lbaint_t)pccb->pdata[1] << 16) | |
||||
((lbaint_t)pccb->pdata[2] << 8) | |
||||
((lbaint_t)pccb->pdata[3]); |
||||
|
||||
if (*capacity != 0xffffffff) { |
||||
/* Read capacity (10) was sufficient for this drive. */ |
||||
*blksz = ((unsigned long)pccb->pdata[4] << 24) | |
||||
((unsigned long)pccb->pdata[5] << 16) | |
||||
((unsigned long)pccb->pdata[6] << 8) | |
||||
((unsigned long)pccb->pdata[7]); |
||||
return 0; |
||||
} |
||||
|
||||
/* Read capacity (10) was insufficient. Use read capacity (16). */ |
||||
memset(pccb->cmd, '\0', sizeof(pccb->cmd)); |
||||
pccb->cmd[0] = SCSI_RD_CAPAC16; |
||||
pccb->cmd[1] = 0x10; |
||||
pccb->cmdlen = 16; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
|
||||
pccb->datalen = 16; |
||||
if (scsi_exec(pccb) != true) |
||||
return 1; |
||||
|
||||
*capacity = ((uint64_t)pccb->pdata[0] << 56) | |
||||
((uint64_t)pccb->pdata[1] << 48) | |
||||
((uint64_t)pccb->pdata[2] << 40) | |
||||
((uint64_t)pccb->pdata[3] << 32) | |
||||
((uint64_t)pccb->pdata[4] << 24) | |
||||
((uint64_t)pccb->pdata[5] << 16) | |
||||
((uint64_t)pccb->pdata[6] << 8) | |
||||
((uint64_t)pccb->pdata[7]); |
||||
|
||||
*blksz = ((uint64_t)pccb->pdata[8] << 56) | |
||||
((uint64_t)pccb->pdata[9] << 48) | |
||||
((uint64_t)pccb->pdata[10] << 40) | |
||||
((uint64_t)pccb->pdata[11] << 32) | |
||||
((uint64_t)pccb->pdata[12] << 24) | |
||||
((uint64_t)pccb->pdata[13] << 16) | |
||||
((uint64_t)pccb->pdata[14] << 8) | |
||||
((uint64_t)pccb->pdata[15]); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Some setup (fill-in) routines |
||||
*/ |
||||
void scsi_setup_test_unit_ready(ccb *pccb) |
||||
{ |
||||
pccb->cmd[0] = SCSI_TST_U_RDY; |
||||
pccb->cmd[1] = pccb->lun << 5; |
||||
pccb->cmd[2] = 0; |
||||
pccb->cmd[3] = 0; |
||||
pccb->cmd[4] = 0; |
||||
pccb->cmd[5] = 0; |
||||
pccb->cmdlen = 6; |
||||
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ |
||||
} |
||||
|
||||
/*
|
||||
* (re)-scan the scsi bus and reports scsi device info |
||||
* to the user if mode = 1 |
||||
*/ |
||||
void scsi_scan(int mode) |
||||
{ |
||||
unsigned char i, perq, modi, lun; |
||||
lbaint_t capacity; |
||||
unsigned long blksz; |
||||
ccb *pccb = (ccb *)&tempccb; |
||||
|
||||
if (mode == 1) |
||||
printf("scanning bus for devices...\n"); |
||||
for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) { |
||||
scsi_dev_desc[i].target = 0xff; |
||||
scsi_dev_desc[i].lun = 0xff; |
||||
scsi_dev_desc[i].lba = 0; |
||||
scsi_dev_desc[i].blksz = 0; |
||||
scsi_dev_desc[i].log2blksz = |
||||
LOG2_INVALID(typeof(scsi_dev_desc[i].log2blksz)); |
||||
scsi_dev_desc[i].type = DEV_TYPE_UNKNOWN; |
||||
scsi_dev_desc[i].vendor[0] = 0; |
||||
scsi_dev_desc[i].product[0] = 0; |
||||
scsi_dev_desc[i].revision[0] = 0; |
||||
scsi_dev_desc[i].removable = false; |
||||
scsi_dev_desc[i].if_type = IF_TYPE_SCSI; |
||||
scsi_dev_desc[i].devnum = i; |
||||
scsi_dev_desc[i].part_type = PART_TYPE_UNKNOWN; |
||||
#ifndef CONFIG_BLK |
||||
scsi_dev_desc[i].block_read = scsi_read; |
||||
scsi_dev_desc[i].block_write = scsi_write; |
||||
#endif |
||||
} |
||||
scsi_max_devs = 0; |
||||
for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { |
||||
pccb->target = i; |
||||
for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) { |
||||
pccb->lun = lun; |
||||
pccb->pdata = (unsigned char *)&tempbuff; |
||||
pccb->datalen = 512; |
||||
scsi_setup_inquiry(pccb); |
||||
if (scsi_exec(pccb) != true) { |
||||
if (pccb->contr_stat == SCSI_SEL_TIME_OUT) { |
||||
/*
|
||||
* selection timeout => assuming no |
||||
* device present |
||||
*/ |
||||
debug("Selection timeout ID %d\n", |
||||
pccb->target); |
||||
continue; |
||||
} |
||||
scsi_print_error(pccb); |
||||
continue; |
||||
} |
||||
perq = tempbuff[0]; |
||||
modi = tempbuff[1]; |
||||
if ((perq & 0x1f) == 0x1f) |
||||
continue; /* skip unknown devices */ |
||||
if ((modi & 0x80) == 0x80) /* drive is removable */ |
||||
scsi_dev_desc[scsi_max_devs].removable = true; |
||||
/* get info for this device */ |
||||
scsi_ident_cpy((unsigned char *)&scsi_dev_desc |
||||
[scsi_max_devs].vendor[0], |
||||
&tempbuff[8], 8); |
||||
scsi_ident_cpy((unsigned char *)&scsi_dev_desc |
||||
[scsi_max_devs].product[0], |
||||
&tempbuff[16], 16); |
||||
scsi_ident_cpy((unsigned char *)&scsi_dev_desc |
||||
[scsi_max_devs].revision[0], |
||||
&tempbuff[32], 4); |
||||
scsi_dev_desc[scsi_max_devs].target = pccb->target; |
||||
scsi_dev_desc[scsi_max_devs].lun = pccb->lun; |
||||
|
||||
pccb->datalen = 0; |
||||
scsi_setup_test_unit_ready(pccb); |
||||
if (scsi_exec(pccb) != true) { |
||||
if (scsi_dev_desc[scsi_max_devs].removable) { |
||||
scsi_dev_desc[scsi_max_devs].type = |
||||
perq; |
||||
goto removable; |
||||
} |
||||
scsi_print_error(pccb); |
||||
continue; |
||||
} |
||||
if (scsi_read_capacity(pccb, &capacity, &blksz)) { |
||||
scsi_print_error(pccb); |
||||
continue; |
||||
} |
||||
scsi_dev_desc[scsi_max_devs].lba = capacity; |
||||
scsi_dev_desc[scsi_max_devs].blksz = blksz; |
||||
scsi_dev_desc[scsi_max_devs].log2blksz = |
||||
LOG2(scsi_dev_desc[scsi_max_devs].blksz); |
||||
scsi_dev_desc[scsi_max_devs].type = perq; |
||||
part_init(&scsi_dev_desc[scsi_max_devs]); |
||||
removable: |
||||
if (mode == 1) { |
||||
printf(" Device %d: ", scsi_max_devs); |
||||
dev_print(&scsi_dev_desc[scsi_max_devs]); |
||||
} /* if mode */ |
||||
scsi_max_devs++; |
||||
} /* next LUN */ |
||||
} |
||||
if (scsi_max_devs > 0) |
||||
scsi_curr_dev = 0; |
||||
else |
||||
scsi_curr_dev = -1; |
||||
|
||||
printf("Found %d device(s).\n", scsi_max_devs); |
||||
#ifndef CONFIG_SPL_BUILD |
||||
setenv_ulong("scsidevs", scsi_max_devs); |
||||
#endif |
||||
} |
||||
|
||||
#ifdef CONFIG_BLK |
||||
static const struct blk_ops scsi_blk_ops = { |
||||
.read = scsi_read, |
||||
.write = scsi_write, |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(scsi_blk) = { |
||||
.name = "scsi_blk", |
||||
.id = UCLASS_BLK, |
||||
.ops = &scsi_blk_ops, |
||||
}; |
||||
#else |
||||
U_BOOT_LEGACY_BLK(scsi) = { |
||||
.if_typename = "sata", |
||||
.if_type = IF_TYPE_SCSI, |
||||
.max_devs = CONFIG_SYS_SCSI_MAX_DEVICE, |
||||
.desc = scsi_dev_desc, |
||||
}; |
||||
#endif |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue