u-boot/arch/powerpc/cpu/mpc8xxx/srio.c
Liu Gang b5f7c8732a powerpc/corenet_ds: Master module for boot from PCIE
For the powerpc processors with PCIE interface, boot location can be
configured from one PCIE interface by RCW. The processor booting from PCIE
can do without flash for u-boot image. The image can be fetched from another
processor's memory space by PCIE link connected between them.

The processor booting from PCIE is slave, the processor booting from normal
flash memory space is master, and it can help slave to boot from master's
memory space.

When boot from PCIE, slave's core should be in holdoff after powered on for
some specific requirements. Master will release the slave's core at the
right time by PCIE interface.

Environment and requirement:

master:
    1. NOR flash for its own u-boot image, ucode and ENV space.
    2. Slave's u-boot image is in master NOR flash.
    3. Normally boot from local NOR flash.
    4. Configure PCIE system if needed.
slave:
    1. Just has EEPROM for RCW. No flash for u-boot image, ucode and ENV.
    2. Boot location should be set to one PCIE interface by RCW.
    3. RCW should configure the SerDes, PCIE interfaces correctly.
	4. Must set all the cores in holdoff by RCW.
	5. Must be powered on before master's boot.

For the master module, need to finish these processes:
    1. Initialize the PCIE port and address space.
    2. Set inbound PCIE windows covered slave's u-boot image stored in
       master's NOR flash.
	3. Set outbound windows in order to configure slave's registers
	   for the core's releasing.
    4. Should set the environment variable "bootmaster" to "PCIE1", "PCIE2"
	   or "PCIE3" using the following command:

			setenv bootmaster PCIE1
			saveenv

Signed-off-by: Liu Gang <Gang.Liu@freescale.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
2012-08-23 10:24:15 -05:00

255 lines
8.2 KiB
C

/*
* Copyright 2011 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <config.h>
#include <asm/fsl_law.h>
#include <asm/fsl_serdes.h>
#include <asm/fsl_srio.h>
#define SRIO_PORT_ACCEPT_ALL 0x10000001
#define SRIO_IB_ATMU_AR 0x80f55000
#define SRIO_OB_ATMU_AR_MAINT 0x80077000
#define SRIO_OB_ATMU_AR_RW 0x80045000
#define SRIO_LCSBA1CSR_OFFSET 0x5c
#define SRIO_MAINT_WIN_SIZE 0x1000000 /* 16M */
#define SRIO_RW_WIN_SIZE 0x100000 /* 1M */
#define SRIO_LCSBA1CSR 0x60000000
#if defined(CONFIG_FSL_CORENET)
#define _DEVDISR_SRIO1 FSL_CORENET_DEVDISR_SRIO1
#define _DEVDISR_SRIO2 FSL_CORENET_DEVDISR_SRIO2
#define _DEVDISR_RMU FSL_CORENET_DEVDISR_RMU
#define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
#elif defined(CONFIG_MPC85xx)
#define _DEVDISR_SRIO1 MPC85xx_DEVDISR_SRIO
#define _DEVDISR_SRIO2 MPC85xx_DEVDISR_SRIO
#define _DEVDISR_RMU MPC85xx_DEVDISR_RMSG
#define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
#elif defined(CONFIG_MPC86xx)
#define _DEVDISR_SRIO1 MPC86xx_DEVDISR_SRIO
#define _DEVDISR_SRIO2 MPC86xx_DEVDISR_SRIO
#define _DEVDISR_RMU MPC86xx_DEVDISR_RMSG
#define CONFIG_SYS_MPC8xxx_GUTS_ADDR \
(&((immap_t *)CONFIG_SYS_IMMR)->im_gur)
#else
#error "No defines for DEVDISR_SRIO"
#endif
void srio_init(void)
{
ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC8xxx_GUTS_ADDR;
int srio1_used = 0, srio2_used = 0;
if (is_serdes_configured(SRIO1)) {
set_next_law(CONFIG_SYS_SRIO1_MEM_PHYS,
law_size_bits(CONFIG_SYS_SRIO1_MEM_SIZE),
LAW_TRGT_IF_RIO_1);
srio1_used = 1;
printf("SRIO1: enabled\n");
} else {
printf("SRIO1: disabled\n");
}
#ifdef CONFIG_SRIO2
if (is_serdes_configured(SRIO2)) {
set_next_law(CONFIG_SYS_SRIO2_MEM_PHYS,
law_size_bits(CONFIG_SYS_SRIO2_MEM_SIZE),
LAW_TRGT_IF_RIO_2);
srio2_used = 1;
printf("SRIO2: enabled\n");
} else {
printf("SRIO2: disabled\n");
}
#endif
#ifdef CONFIG_FSL_CORENET
/* On FSL_CORENET devices we can disable individual ports */
if (!srio1_used)
setbits_be32(&gur->devdisr, FSL_CORENET_DEVDISR_SRIO1);
if (!srio2_used)
setbits_be32(&gur->devdisr, FSL_CORENET_DEVDISR_SRIO2);
#endif
/* neither port is used - disable everything */
if (!srio1_used && !srio2_used) {
setbits_be32(&gur->devdisr, _DEVDISR_SRIO1);
setbits_be32(&gur->devdisr, _DEVDISR_SRIO2);
setbits_be32(&gur->devdisr, _DEVDISR_RMU);
}
}
#ifdef CONFIG_FSL_CORENET
void srio_boot_master(int port)
{
struct ccsr_rio *srio = (void *)CONFIG_SYS_FSL_SRIO_ADDR;
/* set port accept-all */
out_be32((void *)&srio->impl.port[port - 1].ptaacr,
SRIO_PORT_ACCEPT_ALL);
debug("SRIOBOOT - MASTER: Master port [ %d ] for srio boot.\n", port);
/* configure inbound window for slave's u-boot image */
debug("SRIOBOOT - MASTER: Inbound window for slave's image; "
"Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n",
(u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
(u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwtar,
CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS >> 12);
out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwbar,
CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1 >> 12);
out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwar,
SRIO_IB_ATMU_AR
| atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE));
/* configure inbound window for slave's u-boot image */
debug("SRIOBOOT - MASTER: Inbound window for slave's image; "
"Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n",
(u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
(u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwtar,
CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS >> 12);
out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwbar,
CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2 >> 12);
out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwar,
SRIO_IB_ATMU_AR
| atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE));
/* configure inbound window for slave's ucode and ENV */
debug("SRIOBOOT - MASTER: Inbound window for slave's ucode and ENV; "
"Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n",
(u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
(u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwtar,
CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS >> 12);
out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwbar,
CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS >> 12);
out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwar,
SRIO_IB_ATMU_AR
| atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE));
}
void srio_boot_master_release_slave(int port)
{
struct ccsr_rio *srio = (void *)CONFIG_SYS_FSL_SRIO_ADDR;
u32 escsr;
debug("SRIOBOOT - MASTER: "
"Check the port status and release slave core ...\n");
escsr = in_be32((void *)&srio->lp_serial.port[port - 1].pescsr);
if (escsr & 0x2) {
if (escsr & 0x10100) {
debug("SRIOBOOT - MASTER: Port [ %d ] is error.\n",
port);
} else {
debug("SRIOBOOT - MASTER: "
"Port [ %d ] is ready, now release slave's core ...\n",
port);
/*
* configure outbound window
* with maintenance attribute to set slave's LCSBA1CSR
*/
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[1].rowtar, 0);
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[1].rowtear, 0);
if (port - 1)
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[1].rowbar,
CONFIG_SYS_SRIO2_MEM_PHYS >> 12);
else
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[1].rowbar,
CONFIG_SYS_SRIO1_MEM_PHYS >> 12);
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[1].rowar,
SRIO_OB_ATMU_AR_MAINT
| atmu_size_mask(SRIO_MAINT_WIN_SIZE));
/*
* configure outbound window
* with R/W attribute to set slave's BRR
*/
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[2].rowtar,
SRIO_LCSBA1CSR >> 9);
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[2].rowtear, 0);
if (port - 1)
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[2].rowbar,
(CONFIG_SYS_SRIO2_MEM_PHYS
+ SRIO_MAINT_WIN_SIZE) >> 12);
else
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[2].rowbar,
(CONFIG_SYS_SRIO1_MEM_PHYS
+ SRIO_MAINT_WIN_SIZE) >> 12);
out_be32((void *)&srio->atmu.port[port - 1]
.outbw[2].rowar,
SRIO_OB_ATMU_AR_RW
| atmu_size_mask(SRIO_RW_WIN_SIZE));
/*
* Set the LCSBA1CSR register in slave
* by the maint-outbound window
*/
if (port - 1) {
out_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT
+ SRIO_LCSBA1CSR_OFFSET,
SRIO_LCSBA1CSR);
while (in_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT
+ SRIO_LCSBA1CSR_OFFSET)
!= SRIO_LCSBA1CSR)
;
/*
* And then set the BRR register
* to release slave core
*/
out_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT
+ SRIO_MAINT_WIN_SIZE
+ CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET,
CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK);
} else {
out_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT
+ SRIO_LCSBA1CSR_OFFSET,
SRIO_LCSBA1CSR);
while (in_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT
+ SRIO_LCSBA1CSR_OFFSET)
!= SRIO_LCSBA1CSR)
;
/*
* And then set the BRR register
* to release slave core
*/
out_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT
+ SRIO_MAINT_WIN_SIZE
+ CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET,
CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK);
}
debug("SRIOBOOT - MASTER: "
"Release slave successfully! Now the slave should start up!\n");
}
} else
debug("SRIOBOOT - MASTER: Port [ %d ] is not ready.\n", port);
}
#endif