commit
3e1b36bd58
@ -0,0 +1,162 @@ |
||||
/* |
||||
* Copyright (C) 2013 - ARM Ltd |
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
* |
||||
* Based on code by Carl van Schaik <carl@ok-labs.com>.
|
||||
* |
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
#include <config.h> |
||||
#include <asm/psci.h> |
||||
#include <asm/arch/cpu.h> |
||||
|
||||
/* |
||||
* Memory layout: |
||||
* |
||||
* SECURE_RAM to text_end : |
||||
* ._secure_text section
|
||||
* text_end to ALIGN_PAGE(text_end): |
||||
* nothing |
||||
* ALIGN_PAGE(text_end) to ALIGN_PAGE(text_end) + 0x1000) |
||||
* 1kB of stack per CPU (4 CPUs max). |
||||
*/ |
||||
|
||||
.pushsection ._secure.text, "ax" |
||||
|
||||
.arch_extension sec
|
||||
|
||||
#define ONE_MS (CONFIG_SYS_CLK_FREQ / 1000) |
||||
#define TEN_MS (10 * ONE_MS) |
||||
|
||||
.macro timer_wait reg, ticks |
||||
@ Program CNTP_TVAL
|
||||
movw \reg, #(\ticks & 0xffff) |
||||
movt \reg, #(\ticks >> 16) |
||||
mcr p15, 0, \reg, c14, c2, 0 |
||||
isb |
||||
@ Enable physical timer, mask interrupt
|
||||
mov \reg, #3 |
||||
mcr p15, 0, \reg, c14, c2, 1 |
||||
@ Poll physical timer until ISTATUS is on
|
||||
1: isb |
||||
mrc p15, 0, \reg, c14, c2, 1 |
||||
ands \reg, \reg, #4 |
||||
bne 1b |
||||
@ Disable timer
|
||||
mov \reg, #0 |
||||
mcr p15, 0, \reg, c14, c2, 1 |
||||
isb |
||||
.endm |
||||
|
||||
.globl psci_arch_init
|
||||
psci_arch_init: |
||||
mrc p15, 0, r5, c1, c1, 0 @ Read SCR
|
||||
bic r5, r5, #1 @ Secure mode
|
||||
mcr p15, 0, r5, c1, c1, 0 @ Write SCR
|
||||
isb |
||||
|
||||
mrc p15, 0, r4, c0, c0, 5 @ MPIDR
|
||||
and r4, r4, #3 @ cpu number in cluster
|
||||
mov r5, #400 @ 1kB of stack per CPU
|
||||
mul r4, r4, r5 |
||||
|
||||
adr r5, text_end @ end of text
|
||||
add r5, r5, #0x2000 @ Skip two pages
|
||||
lsr r5, r5, #12 @ Align to start of page
|
||||
lsl r5, r5, #12 |
||||
sub sp, r5, r4 @ here's our stack!
|
||||
|
||||
bx lr |
||||
|
||||
@ r1 = target CPU
|
||||
@ r2 = target PC
|
||||
.globl psci_cpu_on
|
||||
psci_cpu_on: |
||||
adr r0, _target_pc |
||||
str r2, [r0] |
||||
dsb |
||||
|
||||
movw r0, #(SUNXI_CPUCFG_BASE & 0xffff) |
||||
movt r0, #(SUNXI_CPUCFG_BASE >> 16) |
||||
|
||||
@ CPU mask
|
||||
and r1, r1, #3 @ only care about first cluster
|
||||
mov r4, #1 |
||||
lsl r4, r4, r1 |
||||
|
||||
adr r6, _sunxi_cpu_entry |
||||
str r6, [r0, #0x1a4] @ PRIVATE_REG (boot vector)
|
||||
|
||||
@ Assert reset on target CPU
|
||||
mov r6, #0 |
||||
lsl r5, r1, #6 @ 64 bytes per CPU
|
||||
add r5, r5, #0x40 @ Offset from base
|
||||
add r5, r5, r0 @ CPU control block
|
||||
str r6, [r5] @ Reset CPU
|
||||
|
||||
@ l1 invalidate
|
||||
ldr r6, [r0, #0x184] |
||||
bic r6, r6, r4 |
||||
str r6, [r0, #0x184] |
||||
|
||||
@ Lock CPU
|
||||
ldr r6, [r0, #0x1e4] |
||||
bic r6, r6, r4 |
||||
str r6, [r0, #0x1e4] |
||||
|
||||
@ Release power clamp
|
||||
movw r6, #0x1ff |
||||
movt r6, #0 |
||||
1: lsrs r6, r6, #1 |
||||
str r6, [r0, #0x1b0] |
||||
bne 1b |
||||
|
||||
timer_wait r1, TEN_MS |
||||
|
||||
@ Clear power gating
|
||||
ldr r6, [r0, #0x1b4] |
||||
bic r6, r6, #1 |
||||
str r6, [r0, #0x1b4] |
||||
|
||||
@ Deassert reset on target CPU
|
||||
mov r6, #3 |
||||
str r6, [r5] |
||||
|
||||
@ Unlock CPU
|
||||
ldr r6, [r0, #0x1e4] |
||||
orr r6, r6, r4 |
||||
str r6, [r0, #0x1e4] |
||||
|
||||
mov r0, #ARM_PSCI_RET_SUCCESS @ Return PSCI_RET_SUCCESS |
||||
mov pc, lr |
||||
|
||||
_target_pc: |
||||
.word 0
|
||||
|
||||
_sunxi_cpu_entry: |
||||
@ Set SMP bit
|
||||
mrc p15, 0, r0, c1, c0, 1 |
||||
orr r0, r0, #0x40 |
||||
mcr p15, 0, r0, c1, c0, 1 |
||||
isb |
||||
|
||||
bl _nonsec_init |
||||
bl psci_arch_init |
||||
|
||||
adr r0, _target_pc |
||||
ldr r0, [r0] |
||||
b _do_nonsec_entry |
||||
|
||||
text_end: |
||||
.popsection |
@ -0,0 +1,84 @@ |
||||
#include <common.h> |
||||
#include <ahci.h> |
||||
#include <scsi.h> |
||||
#include <errno.h> |
||||
#include <asm/io.h> |
||||
#include <asm/gpio.h> |
||||
|
||||
#define AHCI_PHYCS0R 0x00c0 |
||||
#define AHCI_PHYCS1R 0x00c4 |
||||
#define AHCI_PHYCS2R 0x00c8 |
||||
#define AHCI_RWCR 0x00fc |
||||
|
||||
/* This magic PHY initialisation was taken from the Allwinner releases
|
||||
* and Linux driver, but is completely undocumented. |
||||
*/ |
||||
static int sunxi_ahci_phy_init(u32 base) |
||||
{ |
||||
u8 *reg_base = (u8 *)base; |
||||
u32 reg_val; |
||||
int timeout; |
||||
|
||||
writel(0, reg_base + AHCI_RWCR); |
||||
mdelay(5); |
||||
|
||||
setbits_le32(reg_base + AHCI_PHYCS1R, 0x1 << 19); |
||||
clrsetbits_le32(reg_base + AHCI_PHYCS0R, |
||||
(0x7 << 24), |
||||
(0x5 << 24) | (0x1 << 23) | (0x1 << 18)); |
||||
clrsetbits_le32(reg_base + AHCI_PHYCS1R, |
||||
(0x3 << 16) | (0x1f << 8) | (0x3 << 6), |
||||
(0x2 << 16) | (0x6 << 8) | (0x2 << 6)); |
||||
setbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 28) | (0x1 << 15)); |
||||
clrbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 19)); |
||||
clrsetbits_le32(reg_base + AHCI_PHYCS0R, (0x7 << 20), (0x3 << 20)); |
||||
clrsetbits_le32(reg_base + AHCI_PHYCS2R, (0x1f << 5), (0x19 << 5)); |
||||
mdelay(5); |
||||
|
||||
setbits_le32(reg_base + AHCI_PHYCS0R, (0x1 << 19)); |
||||
|
||||
timeout = 250; /* Power up takes approx 50 us */ |
||||
for (;;) { |
||||
reg_val = readl(reg_base + AHCI_PHYCS0R) & (0x7 << 28); |
||||
if (reg_val == (0x2 << 28)) |
||||
break; |
||||
if (--timeout == 0) { |
||||
printf("AHCI PHY power up failed.\n"); |
||||
return -EIO; |
||||
} |
||||
udelay(1); |
||||
}; |
||||
|
||||
setbits_le32(reg_base + AHCI_PHYCS2R, (0x1 << 24)); |
||||
|
||||
timeout = 100; /* Calibration takes approx 10 us */ |
||||
for (;;) { |
||||
reg_val = readl(reg_base + AHCI_PHYCS2R) & (0x1 << 24); |
||||
if (reg_val == 0x0) |
||||
break; |
||||
if (--timeout == 0) { |
||||
printf("AHCI PHY calibration failed.\n"); |
||||
return -EIO; |
||||
} |
||||
udelay(1); |
||||
} |
||||
|
||||
mdelay(15); |
||||
|
||||
writel(0x7, reg_base + AHCI_RWCR); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void scsi_init(void) |
||||
{ |
||||
printf("SUNXI SCSI INIT\n"); |
||||
#ifdef CONFIG_SATAPWR |
||||
gpio_direction_output(CONFIG_SATAPWR, 1); |
||||
#endif |
||||
|
||||
if (sunxi_ahci_phy_init(SUNXI_SATA_BASE) < 0) |
||||
return; |
||||
|
||||
ahci_init(SUNXI_SATA_BASE); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 480, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 4096, |
||||
.io_width = 16, |
||||
.bus_width = 16, |
||||
.cas = 6, |
||||
.zq = 123, |
||||
.odt_en = 0, |
||||
.size = 512, |
||||
.tpr0 = 0x30926692, |
||||
.tpr1 = 0x1090, |
||||
.tpr2 = 0x1a0c8, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0x4, |
||||
.emr2 = 0, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 432, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 4096, |
||||
.io_width = 16, |
||||
.bus_width = 16, |
||||
.cas = 9, |
||||
.zq = 123, |
||||
.odt_en = 0, |
||||
.size = 512, |
||||
.tpr0 = 0x42d899b7, |
||||
.tpr1 = 0xa090, |
||||
.tpr2 = 0x22a00, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0x4, |
||||
.emr2 = 0x10, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 408, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 2048, |
||||
.io_width = 8, |
||||
.bus_width = 16, |
||||
.cas = 9, |
||||
.zq = 123, |
||||
.odt_en = 0, |
||||
.size = 512, |
||||
.tpr0 = 0x42d899b7, |
||||
.tpr1 = 0xa090, |
||||
.tpr2 = 0x22a00, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0, |
||||
.emr2 = 0x10, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 432, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 4096, |
||||
.io_width = 16, |
||||
.bus_width = 32, |
||||
.cas = 9, |
||||
.zq = 0x7f, |
||||
.odt_en = 0, |
||||
.size = 1024, |
||||
.tpr0 = 0x42d899b7, |
||||
.tpr1 = 0xa090, |
||||
.tpr2 = 0x22a00, |
||||
.tpr3 = 0x0, |
||||
.tpr4 = 0x1, |
||||
.tpr5 = 0x0, |
||||
.emr1 = 0x4, |
||||
.emr2 = 0x10, |
||||
.emr3 = 0x0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 480, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 4096, |
||||
.io_width = 16, |
||||
.bus_width = 32, |
||||
.cas = 9, |
||||
.zq = 0x7a, |
||||
.odt_en = 0, |
||||
.size = 1024, |
||||
.tpr0 = 0x42d899b7, |
||||
.tpr1 = 0xa090, |
||||
.tpr2 = 0x22a00, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0x4, |
||||
.emr2 = 0x10, |
||||
.emr3 = 0x0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 360, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 4096, |
||||
.io_width = 16, |
||||
.bus_width = 32, |
||||
.cas = 6, |
||||
.zq = 123, |
||||
.odt_en = 0, |
||||
.size = 1024, |
||||
.tpr0 = 0x30926692, |
||||
.tpr1 = 0x1090, |
||||
.tpr2 = 0x1a0c8, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0, |
||||
.emr2 = 0, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 360, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 2048, |
||||
.io_width = 8, |
||||
.bus_width = 32, |
||||
.cas = 6, |
||||
.zq = 123, |
||||
.odt_en = 0, |
||||
.size = 1024, |
||||
.tpr0 = 0x30926692, |
||||
.tpr1 = 0x1090, |
||||
.tpr2 = 0x1a0c8, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0, |
||||
.emr2 = 0, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 360, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 2048, |
||||
.io_width = 16, |
||||
.bus_width = 32, |
||||
.cas = 6, |
||||
.zq = 123, |
||||
.odt_en = 0, |
||||
.size = 512, |
||||
.tpr0 = 0x30926692, |
||||
.tpr1 = 0x1090, |
||||
.tpr2 = 0x1a0c8, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0, |
||||
.emr2 = 0, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include <common.h> |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 384, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 2048, |
||||
.io_width = 8, |
||||
.bus_width = 32, |
||||
.cas = 6, |
||||
.zq = 123, |
||||
.odt_en = 0, |
||||
.size = 1024, |
||||
.tpr0 = 0x30926692, |
||||
.tpr1 = 0x1090, |
||||
.tpr2 = 0x1a0c8, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0x4, |
||||
.emr2 = 0, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include "common.h" |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 384, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 4096, |
||||
.io_width = 16, |
||||
.bus_width = 32, |
||||
.cas = 9, |
||||
.zq = 0x7f, |
||||
.odt_en = 0, |
||||
.size = 1024, |
||||
.tpr0 = 0x42d899b7, |
||||
.tpr1 = 0xa090, |
||||
.tpr2 = 0x22a00, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0x4, |
||||
.emr2 = 0x10, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* this file is generated, don't edit it yourself */ |
||||
|
||||
#include "common.h" |
||||
#include <asm/arch/dram.h> |
||||
|
||||
static struct dram_para dram_para = { |
||||
.clock = 384, |
||||
.type = 3, |
||||
.rank_num = 1, |
||||
.density = 4096, |
||||
.io_width = 16, |
||||
.bus_width = 16, |
||||
.cas = 9, |
||||
.zq = 0x7f, |
||||
.odt_en = 0, |
||||
.size = 512, |
||||
.tpr0 = 0x42d899b7, |
||||
.tpr1 = 0xa090, |
||||
.tpr2 = 0x22a00, |
||||
.tpr3 = 0, |
||||
.tpr4 = 0, |
||||
.tpr5 = 0, |
||||
.emr1 = 0x4, |
||||
.emr2 = 0x10, |
||||
.emr3 = 0, |
||||
}; |
||||
|
||||
unsigned long sunxi_dram_init(void) |
||||
{ |
||||
return dramc_init(&dram_para); |
||||
} |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="A10_OLINUXINO_L,SPL,AXP209_POWER,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPC(3),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN4I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="A10S_OLINUXINO_M,SPL,AXP152_POWER,SUNXI_EMAC,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPB(10)" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN5I=y |
@ -1,4 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="A13_OLINUXINOM,SPL,CONS_INDEX=2" |
||||
CONFIG_SYS_EXTRA_OPTIONS="A13_OLINUXINOM,SPL,CONS_INDEX=2,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(11)" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN5I=y |
||||
|
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="A13_OLINUXINO,SPL,CONS_INDEX=2,AXP209_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(11)" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN5I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="A20_OLINUXINO_M,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="AUXTEK_T004,SPL,AXP152_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(13)" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN5I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="BANANAPI,SPL,AXP209_POWER,SUNXI_GMAC,RGMII,MACPWR=SUNXI_GPH(23),AHCI,USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
@ -1,4 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL_FEL,SUNXI_GMAC" |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL_FEL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
||||
|
@ -1,4 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL,SUNXI_GMAC" |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
||||
|
@ -1,4 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC" |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN4I=y |
||||
|
@ -1,4 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII" |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
||||
|
@ -1,4 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII" |
||||
CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
||||
|
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="PCDUINO3,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPH(2),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="MELE_A1000G,SPL,AXP209_POWER,SUNXI_EMAC,MACPWR=SUNXI_GPH(15),AHCI,USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN4I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="MELE_A1000,SPL,AXP209_POWER,SUNXI_EMAC,MACPWR=SUNXI_GPH(15),AHCI,USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN4I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="MINI_X_1GB,SPL,AXP209_POWER,USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN4I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="MINI_X,SPL,AXP209_POWER,USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN4I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="BA10_TV_BOX,SPL,AXP209_POWER,SUNXI_EMAC,USB_EHCI,SUNXI_USB_VBUS1_GPIO=SUNXI_GPH(12)" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN4I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="I12_TVBOX,SPL,AXP209_POWER,SUNXI_GMAC,MACPWR=SUNXI_GPH(21),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
@ -0,0 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="QT840A,SPL,AXP209_POWER,SUNXI_GMAC,MACPWR=SUNXI_GPH(21),USB_EHCI" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN7I=y |
@ -1,4 +1,4 @@ |
||||
CONFIG_SPL=y |
||||
CONFIG_SYS_EXTRA_OPTIONS="R7DONGLE,SPL,AXP152_POWER" |
||||
CONFIG_SYS_EXTRA_OPTIONS="R7DONGLE,SPL,AXP152_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(13)" |
||||
+S:CONFIG_ARM=y |
||||
+S:CONFIG_TARGET_SUN5I=y |
||||
|
@ -0,0 +1,201 @@ |
||||
/*
|
||||
* Copyright (C) 2014 Roman Byshko |
||||
* |
||||
* Roman Byshko <rbyshko@gmail.com> |
||||
* |
||||
* Based on code from |
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <asm/arch/clock.h> |
||||
#include <asm/gpio.h> |
||||
#include <asm/io.h> |
||||
#include <common.h> |
||||
#include "ehci.h" |
||||
|
||||
#define SUNXI_USB1_IO_BASE 0x01c14000 |
||||
#define SUNXI_USB2_IO_BASE 0x01c1c000 |
||||
|
||||
#define SUNXI_USB_PMU_IRQ_ENABLE 0x800 |
||||
#define SUNXI_USB_CSR 0x01c13404 |
||||
#define SUNXI_USB_PASSBY_EN 1 |
||||
|
||||
#define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10) |
||||
#define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9) |
||||
#define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8) |
||||
#define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0) |
||||
|
||||
static struct sunxi_ehci_hcd { |
||||
struct usb_hcd *hcd; |
||||
int usb_rst_mask; |
||||
int ahb_clk_mask; |
||||
int gpio_vbus; |
||||
void *csr; |
||||
int irq; |
||||
int id; |
||||
} sunxi_echi_hcd[] = { |
||||
{ |
||||
.usb_rst_mask = CCM_USB_CTRL_PHY1_RST, |
||||
.ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0, |
||||
.gpio_vbus = CONFIG_SUNXI_USB_VBUS0_GPIO, |
||||
.csr = (void *)SUNXI_USB_CSR, |
||||
.irq = 39, |
||||
.id = 1, |
||||
}, |
||||
#if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1) |
||||
{ |
||||
.usb_rst_mask = CCM_USB_CTRL_PHY2_RST, |
||||
.ahb_clk_mask = 1 << AHB_GATE_OFFSET_USB_EHCI1, |
||||
.gpio_vbus = CONFIG_SUNXI_USB_VBUS1_GPIO, |
||||
.csr = (void *)SUNXI_USB_CSR, |
||||
.irq = 40, |
||||
.id = 2, |
||||
} |
||||
#endif |
||||
}; |
||||
|
||||
static int enabled_hcd_count; |
||||
|
||||
static void *get_io_base(int hcd_id) |
||||
{ |
||||
if (hcd_id == 1) |
||||
return (void *)SUNXI_USB1_IO_BASE; |
||||
else if (hcd_id == 2) |
||||
return (void *)SUNXI_USB2_IO_BASE; |
||||
else |
||||
return NULL; |
||||
} |
||||
|
||||
static void usb_phy_write(struct sunxi_ehci_hcd *sunxi_ehci, int addr, |
||||
int data, int len) |
||||
{ |
||||
int j = 0, usbc_bit = 0; |
||||
void *dest = sunxi_ehci->csr; |
||||
|
||||
usbc_bit = 1 << (sunxi_ehci->id * 2); |
||||
for (j = 0; j < len; j++) { |
||||
/* set the bit address to be written */ |
||||
clrbits_le32(dest, 0xff << 8); |
||||
setbits_le32(dest, (addr + j) << 8); |
||||
|
||||
clrbits_le32(dest, usbc_bit); |
||||
/* set data bit */ |
||||
if (data & 0x1) |
||||
setbits_le32(dest, 1 << 7); |
||||
else |
||||
clrbits_le32(dest, 1 << 7); |
||||
|
||||
setbits_le32(dest, usbc_bit); |
||||
|
||||
clrbits_le32(dest, usbc_bit); |
||||
|
||||
data >>= 1; |
||||
} |
||||
} |
||||
|
||||
static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci) |
||||
{ |
||||
/* The following comments are machine
|
||||
* translated from Chinese, you have been warned! |
||||
*/ |
||||
|
||||
/* adjust PHY's magnitude and rate */ |
||||
usb_phy_write(sunxi_ehci, 0x20, 0x14, 5); |
||||
|
||||
/* threshold adjustment disconnect */ |
||||
#ifdef CONFIG_SUN4I |
||||
usb_phy_write(sunxi_ehci, 0x2a, 3, 2); |
||||
#else |
||||
usb_phy_write(sunxi_ehci, 0x2a, 2, 2); |
||||
#endif |
||||
|
||||
return; |
||||
} |
||||
|
||||
static void sunxi_usb_passby(struct sunxi_ehci_hcd *sunxi_ehci, int enable) |
||||
{ |
||||
unsigned long bits = 0; |
||||
void *addr = get_io_base(sunxi_ehci->id) + SUNXI_USB_PMU_IRQ_ENABLE; |
||||
|
||||
bits = SUNXI_EHCI_AHB_ICHR8_EN | |
||||
SUNXI_EHCI_AHB_INCR4_BURST_EN | |
||||
SUNXI_EHCI_AHB_INCRX_ALIGN_EN | |
||||
SUNXI_EHCI_ULPI_BYPASS_EN; |
||||
|
||||
if (enable) |
||||
setbits_le32(addr, bits); |
||||
else |
||||
clrbits_le32(addr, bits); |
||||
|
||||
return; |
||||
} |
||||
|
||||
static void sunxi_ehci_enable(struct sunxi_ehci_hcd *sunxi_ehci) |
||||
{ |
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
||||
|
||||
setbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask); |
||||
setbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask); |
||||
|
||||
sunxi_usb_phy_init(sunxi_ehci); |
||||
|
||||
sunxi_usb_passby(sunxi_ehci, SUNXI_USB_PASSBY_EN); |
||||
|
||||
gpio_direction_output(sunxi_ehci->gpio_vbus, 1); |
||||
} |
||||
|
||||
static void sunxi_ehci_disable(struct sunxi_ehci_hcd *sunxi_ehci) |
||||
{ |
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
||||
|
||||
gpio_direction_output(sunxi_ehci->gpio_vbus, 0); |
||||
|
||||
sunxi_usb_passby(sunxi_ehci, !SUNXI_USB_PASSBY_EN); |
||||
|
||||
clrbits_le32(&ccm->ahb_gate0, sunxi_ehci->ahb_clk_mask); |
||||
clrbits_le32(&ccm->usb_clk_cfg, sunxi_ehci->usb_rst_mask); |
||||
} |
||||
|
||||
int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, |
||||
struct ehci_hcor **hcor) |
||||
{ |
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
||||
struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index]; |
||||
|
||||
/* enable common PHY only once */ |
||||
if (index == 0) |
||||
setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE); |
||||
|
||||
sunxi_ehci_enable(sunxi_ehci); |
||||
|
||||
*hccr = get_io_base(sunxi_ehci->id); |
||||
|
||||
*hcor = (struct ehci_hcor *)((uint32_t) *hccr |
||||
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); |
||||
|
||||
debug("sunxi-ehci: init hccr %x and hcor %x hc_length %d\n", |
||||
(uint32_t)*hccr, (uint32_t)*hcor, |
||||
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); |
||||
|
||||
enabled_hcd_count++; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int ehci_hcd_stop(int index) |
||||
{ |
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; |
||||
struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index]; |
||||
|
||||
sunxi_ehci_disable(sunxi_ehci); |
||||
|
||||
/* disable common PHY only once, for the last enabled hcd */ |
||||
if (enabled_hcd_count == 1) |
||||
clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE); |
||||
|
||||
enabled_hcd_count--; |
||||
|
||||
return 0; |
||||
} |
Loading…
Reference in new issue