|
@@ -208,6 +208,7 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
|
|
|
u8 __iomem *lbc_lcs0_ba = NULL;
|
|
|
u8 __iomem *lbc_lcs1_ba = NULL;
|
|
|
phys_addr_t cs0_addr, cs1_addr;
|
|
|
+ u32 br0, or0, br1, or1;
|
|
|
const __be32 *iprop;
|
|
|
unsigned int num_laws;
|
|
|
u8 b;
|
|
@@ -256,11 +257,70 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
|
|
|
}
|
|
|
num_laws = be32_to_cpup(iprop);
|
|
|
|
|
|
- cs0_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[0].br));
|
|
|
- cs1_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[1].br));
|
|
|
+ /*
|
|
|
+ * Indirect mode requires both BR0 and BR1 to be set to "GPCM",
|
|
|
+ * otherwise writes to these addresses won't actually appear on the
|
|
|
+ * local bus, and so the PIXIS won't see them.
|
|
|
+ *
|
|
|
+ * In FCM mode, writes go to the NAND controller, which does not pass
|
|
|
+ * them to the localbus directly. So we force BR0 and BR1 into GPCM
|
|
|
+ * mode, since we don't care about what's behind the localbus any
|
|
|
+ * more.
|
|
|
+ */
|
|
|
+ br0 = in_be32(&lbc->bank[0].br);
|
|
|
+ br1 = in_be32(&lbc->bank[1].br);
|
|
|
+ or0 = in_be32(&lbc->bank[0].or);
|
|
|
+ or1 = in_be32(&lbc->bank[1].or);
|
|
|
+
|
|
|
+ /* Make sure CS0 and CS1 are programmed */
|
|
|
+ if (!(br0 & BR_V) || !(br1 & BR_V)) {
|
|
|
+ pr_err("p1022ds: CS0 and/or CS1 is not programmed\n");
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Use the existing BRx/ORx values if it's already GPCM. Otherwise,
|
|
|
+ * force the values to simple 32KB GPCM windows with the most
|
|
|
+ * conservative timing.
|
|
|
+ */
|
|
|
+ if ((br0 & BR_MSEL) != BR_MS_GPCM) {
|
|
|
+ br0 = (br0 & BR_BA) | BR_V;
|
|
|
+ or0 = 0xFFFF8000 | 0xFF7;
|
|
|
+ out_be32(&lbc->bank[0].br, br0);
|
|
|
+ out_be32(&lbc->bank[0].or, or0);
|
|
|
+ }
|
|
|
+ if ((br1 & BR_MSEL) != BR_MS_GPCM) {
|
|
|
+ br1 = (br1 & BR_BA) | BR_V;
|
|
|
+ or1 = 0xFFFF8000 | 0xFF7;
|
|
|
+ out_be32(&lbc->bank[1].br, br1);
|
|
|
+ out_be32(&lbc->bank[1].or, or1);
|
|
|
+ }
|
|
|
+
|
|
|
+ cs0_addr = lbc_br_to_phys(ecm, num_laws, br0);
|
|
|
+ if (!cs0_addr) {
|
|
|
+ pr_err("p1022ds: could not determine physical address for CS0"
|
|
|
+ " (BR0=%08x)\n", br0);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ cs1_addr = lbc_br_to_phys(ecm, num_laws, br1);
|
|
|
+ if (!cs0_addr) {
|
|
|
+ pr_err("p1022ds: could not determine physical address for CS1"
|
|
|
+ " (BR1=%08x)\n", br1);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
|
|
|
lbc_lcs0_ba = ioremap(cs0_addr, 1);
|
|
|
+ if (!lbc_lcs0_ba) {
|
|
|
+ pr_err("p1022ds: could not ioremap CS0 address %llx\n",
|
|
|
+ (unsigned long long)cs0_addr);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
lbc_lcs1_ba = ioremap(cs1_addr, 1);
|
|
|
+ if (!lbc_lcs1_ba) {
|
|
|
+ pr_err("p1022ds: could not ioremap CS1 address %llx\n",
|
|
|
+ (unsigned long long)cs1_addr);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
|
|
|
/* Make sure we're in indirect mode first. */
|
|
|
if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
|
|
@@ -419,18 +479,6 @@ void __init p1022_ds_pic_init(void)
|
|
|
|
|
|
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
|
|
|
|
|
|
-/*
|
|
|
- * Disables a node in the device tree.
|
|
|
- *
|
|
|
- * This function is called before kmalloc() is available, so the 'new' object
|
|
|
- * should be allocated in the global area. The easiest way is to do that is
|
|
|
- * to allocate one static local variable for each call to this function.
|
|
|
- */
|
|
|
-static void __init disable_one_node(struct device_node *np, struct property *new)
|
|
|
-{
|
|
|
- prom_update_property(np, new);
|
|
|
-}
|
|
|
-
|
|
|
/* TRUE if there is a "video=fslfb" command-line parameter. */
|
|
|
static bool fslfb;
|
|
|
|
|
@@ -493,28 +541,58 @@ static void __init p1022_ds_setup_arch(void)
|
|
|
diu_ops.valid_monitor_port = p1022ds_valid_monitor_port;
|
|
|
|
|
|
/*
|
|
|
- * Disable the NOR flash node if there is video=fslfb... command-line
|
|
|
- * parameter. When the DIU is active, NOR flash is unavailable, so we
|
|
|
- * have to disable the node before the MTD driver loads.
|
|
|
+ * Disable the NOR and NAND flash nodes if there is video=fslfb...
|
|
|
+ * command-line parameter. When the DIU is active, the localbus is
|
|
|
+ * unavailable, so we have to disable these nodes before the MTD
|
|
|
+ * driver loads.
|
|
|
*/
|
|
|
if (fslfb) {
|
|
|
struct device_node *np =
|
|
|
of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc");
|
|
|
|
|
|
if (np) {
|
|
|
- np = of_find_compatible_node(np, NULL, "cfi-flash");
|
|
|
- if (np) {
|
|
|
+ struct device_node *np2;
|
|
|
+
|
|
|
+ of_node_get(np);
|
|
|
+ np2 = of_find_compatible_node(np, NULL, "cfi-flash");
|
|
|
+ if (np2) {
|
|
|
static struct property nor_status = {
|
|
|
.name = "status",
|
|
|
.value = "disabled",
|
|
|
.length = sizeof("disabled"),
|
|
|
};
|
|
|
|
|
|
+ /*
|
|
|
+ * prom_update_property() is called before
|
|
|
+ * kmalloc() is available, so the 'new' object
|
|
|
+ * should be allocated in the global area.
|
|
|
+ * The easiest way is to do that is to
|
|
|
+ * allocate one static local variable for each
|
|
|
+ * call to this function.
|
|
|
+ */
|
|
|
pr_info("p1022ds: disabling %s node",
|
|
|
- np->full_name);
|
|
|
- disable_one_node(np, &nor_status);
|
|
|
- of_node_put(np);
|
|
|
+ np2->full_name);
|
|
|
+ prom_update_property(np2, &nor_status);
|
|
|
+ of_node_put(np2);
|
|
|
}
|
|
|
+
|
|
|
+ of_node_get(np);
|
|
|
+ np2 = of_find_compatible_node(np, NULL,
|
|
|
+ "fsl,elbc-fcm-nand");
|
|
|
+ if (np2) {
|
|
|
+ static struct property nand_status = {
|
|
|
+ .name = "status",
|
|
|
+ .value = "disabled",
|
|
|
+ .length = sizeof("disabled"),
|
|
|
+ };
|
|
|
+
|
|
|
+ pr_info("p1022ds: disabling %s node",
|
|
|
+ np2->full_name);
|
|
|
+ prom_update_property(np2, &nand_status);
|
|
|
+ of_node_put(np2);
|
|
|
+ }
|
|
|
+
|
|
|
+ of_node_put(np);
|
|
|
}
|
|
|
|
|
|
}
|