summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/fsl_law.c126
-rw-r--r--include/asm-ppc/fsl_law.h31
2 files changed, 146 insertions, 11 deletions
diff --git a/drivers/misc/fsl_law.c b/drivers/misc/fsl_law.c
index aa877c65f..7c59c887f 100644
--- a/drivers/misc/fsl_law.c
+++ b/drivers/misc/fsl_law.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009 Freescale Semiconductor, Inc.
*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
@@ -29,7 +29,6 @@
DECLARE_GLOBAL_DATA_PTR;
-#define LAWAR_EN 0x80000000
/* number of LAWs in the hw implementation */
#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
defined(CONFIG_MPC8560) || defined(CONFIG_MPC8555)
@@ -46,6 +45,56 @@ DECLARE_GLOBAL_DATA_PTR;
#error FSL_HW_NUM_LAWS not defined for this platform
#endif
+#ifdef CONFIG_FSL_CORENET
+void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
+{
+ volatile ccsr_local_t *ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
+
+ gd->used_laws |= (1 << idx);
+
+ out_be32(&ccm->law[idx].lawar, 0);
+ out_be32(&ccm->law[idx].lawbarh, ((u64)addr >> 32));
+ out_be32(&ccm->law[idx].lawbarl, addr & 0xffffffff);
+ out_be32(&ccm->law[idx].lawar, LAW_EN | ((u32)id << 20) | (u32)sz);
+
+ /* Read back so that we sync the writes */
+ in_be32(&ccm->law[idx].lawar);
+}
+
+void disable_law(u8 idx)
+{
+ volatile ccsr_local_t *ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
+
+ gd->used_laws &= ~(1 << idx);
+
+ out_be32(&ccm->law[idx].lawar, 0);
+ out_be32(&ccm->law[idx].lawbarh, 0);
+ out_be32(&ccm->law[idx].lawbarl, 0);
+
+ /* Read back so that we sync the writes */
+ in_be32(&ccm->law[idx].lawar);
+
+ return;
+}
+
+static int get_law_entry(u8 i, struct law_entry *e)
+{
+ volatile ccsr_local_t *ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
+ u32 lawar;
+
+ lawar = in_be32(&ccm->law[i].lawar);
+
+ if (!(lawar & LAW_EN))
+ return 0;
+
+ e->addr = ((u64)in_be32(&ccm->law[i].lawbarh) << 32) |
+ in_be32(&ccm->law[i].lawbarl);
+ e->size = lawar & 0x3f;
+ e->trgt_id = (lawar >> 20) & 0xff;
+
+ return 1;
+}
+#else
void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
{
volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
@@ -56,12 +105,49 @@ void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
out_be32(lawar, 0);
out_be32(lawbar, addr >> 12);
- out_be32(lawar, LAWAR_EN | ((u32)id << 20) | (u32)sz);
+ out_be32(lawar, LAW_EN | ((u32)id << 20) | (u32)sz);
/* Read back so that we sync the writes */
in_be32(lawar);
}
+void disable_law(u8 idx)
+{
+ volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
+ volatile u32 *lawbar = base + 8 * idx;
+ volatile u32 *lawar = base + 8 * idx + 2;
+
+ gd->used_laws &= ~(1 << idx);
+
+ out_be32(lawar, 0);
+ out_be32(lawbar, 0);
+
+ /* Read back so that we sync the writes */
+ in_be32(lawar);
+
+ return;
+}
+
+static int get_law_entry(u8 i, struct law_entry *e)
+{
+ volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
+ volatile u32 *lawbar = base + 8 * i;
+ volatile u32 *lawar = base + 8 * i + 2;
+ u32 temp;
+
+ temp = in_be32(lawar);
+
+ if (!(temp & LAW_EN))
+ return 0;
+
+ e->addr = (u64)in_be32(lawbar) << 12;
+ e->size = temp & 0x3f;
+ e->trgt_id = (temp >> 20) & 0xff;
+
+ return 1;
+}
+#endif
+
int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
{
u32 idx = ffz(gd->used_laws);
@@ -94,18 +180,30 @@ int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
return idx;
}
-void disable_law(u8 idx)
+struct law_entry find_law(phys_addr_t addr)
{
- volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
- volatile u32 *lawbar = base + 8 * idx;
- volatile u32 *lawar = base + 8 * idx + 2;
+ struct law_entry entry;
+ int i;
- gd->used_laws &= ~(1 << idx);
+ entry.index = -1;
+ entry.addr = 0;
+ entry.size = 0;
+ entry.trgt_id = 0;
- out_be32(lawar, 0);
- out_be32(lawbar, 0);
+ for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
+ u64 upper;
- return;
+ if (!get_law_entry(i, &entry))
+ continue;
+
+ upper = entry.addr + (2ull << entry.size);
+ if ((addr >= entry.addr) && (addr < upper)) {
+ entry.index = i;
+ break;
+ }
+ }
+
+ return entry;
}
void print_laws(void)
@@ -173,7 +271,13 @@ void init_laws(void)
{
int i;
+#if FSL_HW_NUM_LAWS < 32
gd->used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1);
+#elif FSL_HW_NUM_LAWS == 32
+ gd->used_laws = 0;
+#else
+#error FSL_HW_NUM_LAWS can not be greater than 32 w/o code changes
+#endif
for (i = 0; i < num_law_entries; i++) {
if (law_table[i].index == -1)
diff --git a/include/asm-ppc/fsl_law.h b/include/asm-ppc/fsl_law.h
index e06a1a6e0..31bb7545b 100644
--- a/include/asm-ppc/fsl_law.h
+++ b/include/asm-ppc/fsl_law.h
@@ -1,8 +1,18 @@
+/*
+ * Copyright 2008-2009 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
+ * Version 2 as published by the Free Software Foundation.
+ */
+
#ifndef _FSL_LAW_H_
#define _FSL_LAW_H_
#include <asm/io.h>
+#define LAW_EN 0x80000000
+
#define SET_LAW_ENTRY(idx, a, sz, trgt) \
{ .index = idx, .addr = a, .size = sz, .trgt_id = trgt }
@@ -36,6 +46,25 @@ enum law_size {
LAW_SIZE_32G,
};
+#ifdef CONFIG_FSL_CORENET
+enum law_trgt_if {
+ LAW_TRGT_IF_PCIE_1 = 0x00,
+ LAW_TRGT_IF_PCIE_2 = 0x01,
+ LAW_TRGT_IF_PCIE_3 = 0x02,
+ LAW_TRGT_IF_RIO_1 = 0x08,
+ LAW_TRGT_IF_RIO_2 = 0x09,
+
+ LAW_TRGT_IF_DDR_1 = 0x10,
+ LAW_TRGT_IF_DDR_2 = 0x11, /* 2nd controller */
+ LAW_TRGT_IF_DDR_INTRLV = 0x14,
+
+ LAW_TRGT_IF_BMAN = 0x18,
+ LAW_TRGT_IF_DCSR = 0x1d,
+ LAW_TRGT_IF_LBC = 0x1f,
+ LAW_TRGT_IF_QMAN = 0x3c,
+};
+#define LAW_TRGT_IF_DDR LAW_TRGT_IF_DDR_1
+#else
enum law_trgt_if {
LAW_TRGT_IF_PCI = 0x00,
LAW_TRGT_IF_PCI_2 = 0x01,
@@ -64,6 +93,7 @@ enum law_trgt_if {
#if defined(CONFIG_MPC8572) || defined(CONFIG_P2020)
#define LAW_TRGT_IF_PCIE_3 LAW_TRGT_IF_PCI
#endif
+#endif /* CONFIG_FSL_CORENET */
struct law_entry {
int index;
@@ -76,6 +106,7 @@ extern void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if
extern int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id);
extern int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id);
extern int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id);
+extern struct law_entry find_law(phys_addr_t addr);
extern void disable_law(u8 idx);
extern void init_laws(void);
extern void print_laws(void);