2007-10-23 23:14:42 +04:00
/*
2008-03-27 21:51:41 +03:00
* arch / arm / mach - orion5x / addr - map . c
2007-10-23 23:14:42 +04:00
*
2008-03-27 21:51:41 +03:00
* Address map functions for Marvell Orion 5 x SoCs
2007-10-23 23:14:42 +04:00
*
* Maintainer : Tzachi Perelstein < tzachi @ marvell . com >
*
2008-03-27 21:51:41 +03:00
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
2007-10-23 23:14:42 +04:00
* warranty of any kind , whether express or implied .
*/
# include <linux/kernel.h>
# include <linux/init.h>
2008-03-27 21:51:39 +03:00
# include <linux/mbus.h>
2007-10-23 23:14:42 +04:00
# include <asm/hardware.h>
2008-03-27 21:51:41 +03:00
# include <asm/io.h>
2007-10-23 23:14:42 +04:00
# include "common.h"
/*
* The Orion has fully programable address map . There ' s a separate address
2008-04-26 00:31:32 +04:00
* map for each of the device _master_ interfaces , e . g . CPU , PCI , PCIe , USB ,
2007-10-23 23:14:42 +04:00
* Gigabit Ethernet , DMA / XOR engines , etc . Each interface has its own
* address decode windows that allow it to access any of the Orion resources .
*
* CPU address decoding - -
* Linux assumes that it is the boot loader that already setup the access to
* DDR and internal registers .
2008-04-26 00:31:32 +04:00
* Setup access to PCI and PCIe IO / MEM space is issued by this file .
2007-10-23 23:14:42 +04:00
* Setup access to various devices located on the device bus interface ( e . g .
* flashes , RTC , etc ) should be issued by machine - setup . c according to
2008-03-27 21:51:41 +03:00
* specific board population ( by using orion5x_setup_ * _win ( ) ) .
2007-10-23 23:14:42 +04:00
*
* Non - CPU Masters address decoding - -
* Unlike the CPU , we setup the access from Orion ' s master interfaces to DDR
* banks only ( the typical use case ) .
* Setup access for each master to DDR is issued by common . c .
*
* Note : although orion_setbits ( ) and orion_clrbits ( ) are not atomic
* no locking is necessary here since code in this file is only called
* at boot time when there is no concurrency issues .
*/
/*
* Generic Address Decode Windows bit settings
*/
# define TARGET_DDR 0
2008-03-27 21:51:41 +03:00
# define TARGET_DEV_BUS 1
2007-10-23 23:14:42 +04:00
# define TARGET_PCI 3
# define TARGET_PCIE 4
# define ATTR_DDR_CS(n) (((n) ==0) ? 0xe : \
( ( n ) = = 1 ) ? 0xd : \
( ( n ) = = 2 ) ? 0xb : \
( ( n ) = = 3 ) ? 0x7 : 0xf )
# define ATTR_PCIE_MEM 0x59
# define ATTR_PCIE_IO 0x51
2008-03-27 21:51:40 +03:00
# define ATTR_PCIE_WA 0x79
2007-10-23 23:14:42 +04:00
# define ATTR_PCI_MEM 0x59
# define ATTR_PCI_IO 0x51
# define ATTR_DEV_CS0 0x1e
# define ATTR_DEV_CS1 0x1d
# define ATTR_DEV_CS2 0x1b
# define ATTR_DEV_BOOT 0xf
# define WIN_EN 1
/*
2008-03-27 21:51:41 +03:00
* Helpers to get DDR bank info
2007-10-23 23:14:42 +04:00
*/
2008-03-27 21:51:41 +03:00
# define DDR_BASE_CS(n) ORION5X_DDR_REG(0x1500 + ((n) * 8))
# define DDR_SIZE_CS(n) ORION5X_DDR_REG(0x1504 + ((n) * 8))
2007-10-23 23:14:42 +04:00
# define DDR_MAX_CS 4
# define DDR_REG_TO_SIZE(reg) (((reg) | 0xffffff) + 1)
# define DDR_REG_TO_BASE(reg) ((reg) & 0xff000000)
# define DDR_BANK_EN 1
/*
* CPU Address Decode Windows registers
*/
2008-03-27 21:51:41 +03:00
# define CPU_WIN_CTRL(n) ORION5X_BRIDGE_REG(0x000 | ((n) << 4))
# define CPU_WIN_BASE(n) ORION5X_BRIDGE_REG(0x004 | ((n) << 4))
# define CPU_WIN_REMAP_LO(n) ORION5X_BRIDGE_REG(0x008 | ((n) << 4))
# define CPU_WIN_REMAP_HI(n) ORION5X_BRIDGE_REG(0x00c | ((n) << 4))
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:39 +03:00
2008-03-27 21:51:41 +03:00
struct mbus_dram_target_info orion5x_mbus_dram_info ;
2008-03-27 21:51:39 +03:00
2008-03-27 21:51:41 +03:00
static int __init orion5x_cpu_win_can_remap ( int win )
2007-10-23 23:14:42 +04:00
{
u32 dev , rev ;
2008-03-27 21:51:41 +03:00
orion5x_pcie_id ( & dev , & rev ) ;
2007-11-11 14:05:11 +03:00
if ( ( dev = = MV88F5281_DEV_ID & & win < 4 )
| | ( dev = = MV88F5182_DEV_ID & & win < 2 )
| | ( dev = = MV88F5181_DEV_ID & & win < 2 ) )
2007-10-23 23:14:42 +04:00
return 1 ;
return 0 ;
}
2008-03-27 21:51:40 +03:00
static void __init setup_cpu_win ( int win , u32 base , u32 size ,
u8 target , u8 attr , int remap )
2007-10-23 23:14:42 +04:00
{
2008-03-27 21:51:41 +03:00
orion5x_write ( CPU_WIN_BASE ( win ) , base & 0xffff0000 ) ;
orion5x_write ( CPU_WIN_CTRL ( win ) ,
2008-03-27 21:51:40 +03:00
( ( size - 1 ) & 0xffff0000 ) | ( attr < < 8 ) | ( target < < 4 ) | 1 ) ;
2007-10-23 23:14:42 +04:00
2008-03-27 21:51:41 +03:00
if ( orion5x_cpu_win_can_remap ( win ) ) {
2008-03-27 21:51:40 +03:00
if ( remap < 0 )
remap = base ;
2008-03-27 21:51:41 +03:00
orion5x_write ( CPU_WIN_REMAP_LO ( win ) , remap & 0xffff0000 ) ;
orion5x_write ( CPU_WIN_REMAP_HI ( win ) , 0 ) ;
2007-10-23 23:14:42 +04:00
}
}
2008-03-27 21:51:41 +03:00
void __init orion5x_setup_cpu_mbus_bridge ( void )
2007-10-23 23:14:42 +04:00
{
int i ;
2008-03-27 21:51:39 +03:00
int cs ;
2007-10-23 23:14:42 +04:00
/*
2008-03-27 21:51:40 +03:00
* First , disable and clear windows .
2007-10-23 23:14:42 +04:00
*/
2008-03-27 21:51:40 +03:00
for ( i = 0 ; i < 8 ; i + + ) {
2008-03-27 21:51:41 +03:00
orion5x_write ( CPU_WIN_BASE ( i ) , 0 ) ;
orion5x_write ( CPU_WIN_CTRL ( i ) , 0 ) ;
if ( orion5x_cpu_win_can_remap ( i ) ) {
orion5x_write ( CPU_WIN_REMAP_LO ( i ) , 0 ) ;
orion5x_write ( CPU_WIN_REMAP_HI ( i ) , 0 ) ;
2007-10-23 23:14:42 +04:00
}
}
/*
2008-02-07 23:55:17 +03:00
* Setup windows for PCI + PCIe IO + MEM space .
2007-10-23 23:14:42 +04:00
*/
2008-03-27 21:51:41 +03:00
setup_cpu_win ( 0 , ORION5X_PCIE_IO_PHYS_BASE , ORION5X_PCIE_IO_SIZE ,
TARGET_PCIE , ATTR_PCIE_IO , ORION5X_PCIE_IO_BUS_BASE ) ;
setup_cpu_win ( 1 , ORION5X_PCI_IO_PHYS_BASE , ORION5X_PCI_IO_SIZE ,
TARGET_PCI , ATTR_PCI_IO , ORION5X_PCI_IO_BUS_BASE ) ;
setup_cpu_win ( 2 , ORION5X_PCIE_MEM_PHYS_BASE , ORION5X_PCIE_MEM_SIZE ,
2008-03-27 21:51:40 +03:00
TARGET_PCIE , ATTR_PCIE_MEM , - 1 ) ;
2008-03-27 21:51:41 +03:00
setup_cpu_win ( 3 , ORION5X_PCI_MEM_PHYS_BASE , ORION5X_PCI_MEM_SIZE ,
2008-03-27 21:51:40 +03:00
TARGET_PCI , ATTR_PCI_MEM , - 1 ) ;
2008-03-27 21:51:39 +03:00
/*
* Setup MBUS dram target info .
*/
2008-03-27 21:51:41 +03:00
orion5x_mbus_dram_info . mbus_dram_target_id = TARGET_DDR ;
2008-03-27 21:51:39 +03:00
for ( i = 0 , cs = 0 ; i < 4 ; i + + ) {
u32 base = readl ( DDR_BASE_CS ( i ) ) ;
u32 size = readl ( DDR_SIZE_CS ( i ) ) ;
/*
* Chip select enabled ?
*/
if ( size & 1 ) {
struct mbus_dram_window * w ;
2008-03-27 21:51:41 +03:00
w = & orion5x_mbus_dram_info . cs [ cs + + ] ;
2008-03-27 21:51:39 +03:00
w - > cs_index = i ;
w - > mbus_attr = 0xf & ~ ( 1 < < i ) ;
w - > base = base & 0xff000000 ;
w - > size = ( size | 0x00ffffff ) + 1 ;
}
}
2008-03-27 21:51:41 +03:00
orion5x_mbus_dram_info . num_cs = cs ;
2007-10-23 23:14:42 +04:00
}
2008-03-27 21:51:41 +03:00
void __init orion5x_setup_dev_boot_win ( u32 base , u32 size )
2008-03-27 21:51:40 +03:00
{
setup_cpu_win ( 4 , base , size , TARGET_DEV_BUS , ATTR_DEV_BOOT , - 1 ) ;
}
2008-03-27 21:51:41 +03:00
void __init orion5x_setup_dev0_win ( u32 base , u32 size )
2008-03-27 21:51:40 +03:00
{
setup_cpu_win ( 5 , base , size , TARGET_DEV_BUS , ATTR_DEV_CS0 , - 1 ) ;
}
2008-03-27 21:51:41 +03:00
void __init orion5x_setup_dev1_win ( u32 base , u32 size )
2008-03-27 21:51:40 +03:00
{
setup_cpu_win ( 6 , base , size , TARGET_DEV_BUS , ATTR_DEV_CS1 , - 1 ) ;
}
2008-03-27 21:51:41 +03:00
void __init orion5x_setup_dev2_win ( u32 base , u32 size )
2008-03-27 21:51:40 +03:00
{
setup_cpu_win ( 7 , base , size , TARGET_DEV_BUS , ATTR_DEV_CS2 , - 1 ) ;
}
2008-03-27 21:51:41 +03:00
void __init orion5x_setup_pcie_wa_win ( u32 base , u32 size )
2008-03-27 21:51:40 +03:00
{
setup_cpu_win ( 7 , base , size , TARGET_PCIE , ATTR_PCIE_WA , - 1 ) ;
}