* [PATCH 1/2 v3] Driver for Freescale 8610 and 5121 DIU
From: York Sun @ 2008-03-25 21:27 UTC (permalink / raw)
To: linux-fbdev-devel
Cc: Timur Tabi, a.p.zijlstra, linux-kernel, linuxppc-dev, akpm,
York Sun
In-Reply-To: <120648043867-git-send-email-yorksun@freescale.com>
The following features are supported:
plane 0 works as a regular frame buffer, can be accessed by /dev/fb0
plane 1 has two AOIs (area of interest), can be accessed by /dev/fb1 and /dev/fb2
plane 2 has two AOIs, can be accessed by /dev/fb3 and /dev/fb4
Special ioctls support AOIs
All /dev/fb* can be used as regular frame buffer devices, except hardware change can
only be made through /dev/fb0. Changing pixel clock has no effect on other fbs.
Limitation of usage of AOIs:
AOIs on the same plane can not be horizonally overlapped
AOIs have horizonal order, i.e. AOI0 should be always on top of AOI1
AOIs can not beyond phisical display area. Application should check AOI geometry
before changing physical resolution on /dev/fb0
required command line parameters to preallocate memory for frame buffer
diufb=15M
optional command line parameters to set modes and monitor
video=fslfb:[resolution][,bpp][,monitor]
Syntax:
Resolution
xres x yres-bpp@refresh_rate, the -bpp and @refresh_rate are optional
eg, 1024x768, 1280x1024, 1280x1024-32, 1280x1024@60, 1280x1024-32@60, 1280x480-32@60
Bpp
bpp=32, bpp=24, or bpp=16
Monitor
monitor=0, monitor=1, monitor=2
0 is DVI
1 is Single link LVDS
2 is Double link LVDS
Note: switching monitor is a board feather, not DIU feather. MPC8610HPCD has three
monitor ports to swtich to. MPC5121ADS doesn't have additional monitor port. So switching
monirot port for MPC5121ADS has no effect.
If compiled as a module, it takes pamameters mode, bpp, monitor with the same syntax above.
Signed-off-by: York Sun <yorksun@freescale.com>
Signed-off-by: Timur Tabi <timur@freescale.com>
---
This patch addes new feature of Freescale DIU driver, targeting 2.6.26 kernel.
Documentation/powerpc/booting-without-of.txt | 34 +
arch/powerpc/boot/dts/mpc8610_hpcd.dts | 13 +
drivers/video/Kconfig | 10 +
drivers/video/Makefile | 1 +
drivers/video/fsl-diu-fb.c | 1736 ++++++++++++++++++++++++++
drivers/video/fsl-diu-fb.h | 224 ++++
6 files changed, 2018 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/fsl-diu-fb.c
create mode 100644 drivers/video/fsl-diu-fb.h
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 7b4e8a7..f7ae14a 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -2816,6 +2816,40 @@ platforms are moved over to use the flattened-device-tree model.
big-endian;
};
+ r) Freescale Display Interface Unit
+
+ The Freescale DIU is a LCD controller, with proper hardware, it can also
+ drive DVI monitors.
+
+ Required properties:
+ - compatible : should be "fsl-diu".
+ - reg : should contain at least address and length of the DIU register
+ set.
+ - Interrupts : one DIU interrupt should be describe here.
+
+ Example (MPC8610HPCD)
+ diu@2c000 {
+ device_type = "lcd";
+ compatible = "fsl-diu";
+ reg = <0x2c000 100>;
+ interrupts = <72 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ s) Freescale on board FPGA
+
+ This is the memory-mapped registers for on board FPGA.
+
+ Required properities:
+ - compatible : should be "fsl,fpga-pixis".
+ - reg : should contain the address and the lenght of the FPPGA register
+ set.
+
+ Example (MPC8610HPCD)
+ fpga {
+ compatible = "fsl,fpga-pixis";
+ reg = <0xe8000000 20>;
+ };
More devices will be defined as this spec matures.
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 16c947b..78c67ee 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -45,6 +45,11 @@
reg = <0x00000000 0x20000000>; // 512M at 0x0
};
+ fpga {
+ compatible = "fsl,fpga-pixis";
+ reg = <0xe8000000 20>; // pixis at 0xe8000000
+ };
+
soc@e0000000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -104,6 +109,14 @@
interrupt-parent = <&mpic>;
};
+ diu@2c000 {
+ device_type = "lcd";
+ compatible = "fsl-diu";
+ reg = <0x2c000 100>;
+ interrupts = <72 2>;
+ interrupt-parent = <&mpic>;
+ };
+
mpic: interrupt-controller@40000 {
clock-frequency = <0>;
interrupt-controller;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e0b0580..5e03377 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1779,6 +1779,16 @@ config FB_MBX_DEBUG
If unsure, say N.
+config FB_FSL_DIU
+ tristate "Freescale MPC8610/MPC5121 DIU framebuffer support"
+ depends on FB && (MPC8610 || MPC5121)
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select PPC_LIB_RHEAP
+ ---help---
+ Framebuffer driver for the MPC8610/MPC5121 chip from Freescale
+
config FB_W100
tristate "W100 frame buffer support"
depends on FB && PXA_SHARPSL
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 03371c7..3b9a3ce 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_FB_OMAP) += omap/
+obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
new file mode 100644
index 0000000..bec0b97
--- /dev/null
+++ b/drivers/video/fsl-diu-fb.c
@@ -0,0 +1,1736 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale DIU Frame Buffer device driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Paul Widmer <paul.widmer@freescale.com>
+ * Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ * York Sun <yorksun@freescale.com>
+ * Copyright (C) Freescale Semicondutor, Inc. 2007. All rights reserved.
+ *
+ * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+
+#include <linux/of_platform.h>
+
+#include <sysdev/fsl_soc.h>
+#include "fsl-diu-fb.h"
+
+/*
+ * These parameters give default parameters
+ * for video output 1024x768,
+ * FIXME - change timing to proper amounts
+ * hsync 31.5kHz, vsync 60Hz
+ */
+static struct fb_videomode __devinitdata fsl_diu_default_mode = {
+ .refresh = 60,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15385,
+ .left_margin = 160,
+ .right_margin = 24,
+ .upper_margin = 29,
+ .lower_margin = 3,
+ .hsync_len = 136,
+ .vsync_len = 6,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+};
+
+static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
+ {
+ .name = "1024x768-60",
+ .refresh = 60,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15385,
+ .left_margin = 160,
+ .right_margin = 24,
+ .upper_margin = 29,
+ .lower_margin = 3,
+ .hsync_len = 136,
+ .vsync_len = 6,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1024x768-70",
+ .refresh = 70,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 16886,
+ .left_margin = 3,
+ .right_margin = 3,
+ .upper_margin = 2,
+ .lower_margin = 2,
+ .hsync_len = 40,
+ .vsync_len = 18,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1024x768-75",
+ .refresh = 75,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15009,
+ .left_margin = 3,
+ .right_margin = 3,
+ .upper_margin = 2,
+ .lower_margin = 2,
+ .hsync_len = 80,
+ .vsync_len = 32,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-60",
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9375,
+ .left_margin = 38,
+ .right_margin = 128,
+ .upper_margin = 2,
+ .lower_margin = 7,
+ .hsync_len = 216,
+ .vsync_len = 37,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-70",
+ .refresh = 70,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9380,
+ .left_margin = 6,
+ .right_margin = 6,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 60,
+ .vsync_len = 94,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-75",
+ .refresh = 75,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9380,
+ .left_margin = 6,
+ .right_margin = 6,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 60,
+ .vsync_len = 15,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "320x240", /* for AOI only */
+ .refresh = 60,
+ .xres = 320,
+ .yres = 240,
+ .pixclock = 15385,
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .hsync_len = 0,
+ .vsync_len = 0,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x480-60",
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 480,
+ .pixclock = 18939,
+ .left_margin = 353,
+ .right_margin = 47,
+ .upper_margin = 39,
+ .lower_margin = 4,
+ .hsync_len = 8,
+ .vsync_len = 2,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+};
+
+static char *fb_mode = "1024x768-32@60";
+static unsigned long default_bpp = 32;
+static int monitor_port;
+
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+unsigned int *coherence_data;
+phys_addr_t *coherence_data_phy;
+#endif
+
+static DEFINE_SPINLOCK(diu_lock);
+
+struct fsl_diu_data {
+ struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];
+ /*FSL_AOI_NUM has one dummy AOI */
+ struct device_attribute dev_attr;
+ struct diu_ad *dummy_ad;
+ void *dummy_aoi_virt;
+ unsigned int irq;
+ int fb_enabled;
+ int monitor_port;
+};
+
+struct mfb_info {
+ int index;
+ int type;
+ char *id;
+ int registered;
+ int blank;
+ unsigned long pseudo_palette[16];
+ struct diu_ad *ad;
+ int cursor_reset;
+ unsigned char g_alpha;
+ unsigned int count;
+ int x_aoi_d; /* aoi display x offset to physical screen */
+ int y_aoi_d; /* aoi display y offset to physical screen */
+ struct fsl_diu_data *parent;
+};
+
+
+static struct mfb_info mfb_template[] = {
+ { /* AOI 0 for plane 0 */
+ .index = 0,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel0",
+ .registered = 0,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 0 for plane 1 */
+ .index = 1,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel1 AOI0",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 1 for plane 1 */
+ .index = 2,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel1 AOI1",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 480,
+ },
+ { /* AOI 0 for plane 2 */
+ .index = 3,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel2 AOI0",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 1 for plane 2 */
+ .index = 4,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel2 AOI1",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 480,
+ },
+};
+
+static struct diu_hw dr = {
+ .mode = MFB_MODE1,
+ .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock),
+};
+
+static struct diu_pool pool;
+
+/* To allocate memory for framebuffer. First try __get_free_pages(). If it
+ * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate
+ * very large memory (more than 4MB). We don't want to allocate all memory
+ * in rheap since small memory allocation/deallocation will fragment the
+ * rheap and make the furture large allocation fail.
+ */
+
+void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
+{
+ void *virt;
+
+ pr_debug("size=%lu\n", size);
+
+ virt = (void *)__get_free_pages(GFP_DMA | __GFP_ZERO, get_order(size));
+ if (virt) {
+ *phys = virt_to_phys(virt);
+ pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys);
+ return virt;
+ }
+ if (!diu_ops.diu_mem) {
+ printk(KERN_INFO "%s: no diu_mem."
+ " To reserve more memory, put 'diufb=15M' "
+ "in the command line\n", __func__);
+ return NULL;
+ }
+
+ virt = (void *)rh_alloc(&diu_ops.diu_rh_info, size, "DIU");
+ if (virt) {
+ *phys = virt_to_bus(virt);
+ memset(virt, 0, size);
+ }
+
+ pr_debug("rh virt=%p phys=%lx\n", virt, *phys);
+
+ return virt;
+}
+
+void fsl_diu_free(void *p, unsigned long size)
+{
+ pr_debug("p=%p size=%lu\n", p, size);
+
+ if (!p)
+ return;
+
+ if ((p >= diu_ops.diu_mem) &&
+ (p < (diu_ops.diu_mem + diu_ops.diu_size))) {
+ pr_debug("rh\n");
+ rh_free(&diu_ops.diu_rh_info, (unsigned long) p);
+ } else {
+ pr_debug("dma\n");
+ free_pages((unsigned long)p, get_order(size));
+ }
+}
+
+static int fsl_diu_enable_panel(struct fb_info *info)
+{
+ struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+ struct diu *hw = dr.diu_reg;
+ struct diu_ad *ad = mfbi->ad;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int res = 0;
+
+ pr_debug("enable_panel index %d\n", mfbi->index);
+ if (mfbi->type != MFB_TYPE_OFF) {
+ switch (mfbi->index) {
+ case 0: /* plane 0 */
+ if (hw->desc[0] != ad->paddr)
+ out_be32(&(hw->desc[0]), ad->paddr);
+ break;
+ case 1: /* plane 1 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[2]->par;
+ if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
+ if (cmfbi->count > 0) /* AOI1 open */
+ ad->next_ad =
+ cpu_to_le32(cmfbi->ad->paddr);
+ else
+ ad->next_ad = 0;
+ out_be32(&(hw->desc[1]), ad->paddr);
+ }
+ break;
+ case 3: /* plane 2 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[4]->par;
+ if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
+ if (cmfbi->count > 0) /* AOI1 open */
+ ad->next_ad =
+ cpu_to_le32(cmfbi->ad->paddr);
+ else
+ ad->next_ad = 0;
+ out_be32(&(hw->desc[2]), ad->paddr);
+ }
+ break;
+ case 2: /* plane 1 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[1]->par;
+ ad->next_ad = 0;
+ if (hw->desc[1] == machine_data->dummy_ad->paddr)
+ out_be32(&(hw->desc[1]), ad->paddr);
+ else /* AOI0 open */
+ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+ break;
+ case 4: /* plane 2 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[3]->par;
+ ad->next_ad = 0;
+ if (hw->desc[2] == machine_data->dummy_ad->paddr)
+ out_be32(&(hw->desc[2]), ad->paddr);
+ else /* AOI0 was open */
+ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+ break;
+ default:
+ res = -EINVAL;
+ break;
+ }
+ } else
+ res = -EINVAL;
+ return res;
+}
+
+static int fsl_diu_disable_panel(struct fb_info *info)
+{
+ struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+ struct diu *hw = dr.diu_reg;
+ struct diu_ad *ad = mfbi->ad;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int res = 0;
+
+ switch (mfbi->index) {
+ case 0: /* plane 0 */
+ if (hw->desc[0] != machine_data->dummy_ad->paddr)
+ out_be32(&(hw->desc[0]),
+ machine_data->dummy_ad->paddr);
+ break;
+ case 1: /* plane 1 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[2]->par;
+ if (cmfbi->count > 0) /* AOI1 is open */
+ out_be32(&(hw->desc[1]), cmfbi->ad->paddr);
+ /* move AOI1 to the first */
+ else /* AOI1 was closed */
+ out_be32(&(hw->desc[1]),
+ machine_data->dummy_ad->paddr);
+ /* close AOI 0 */
+ break;
+ case 3: /* plane 2 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[4]->par;
+ if (cmfbi->count > 0) /* AOI1 is open */
+ out_be32(&(hw->desc[2]), cmfbi->ad->paddr);
+ /* move AOI1 to the first */
+ else /* AOI1 was closed */
+ out_be32(&(hw->desc[2]),
+ machine_data->dummy_ad->paddr);
+ /* close AOI 0 */
+ break;
+ case 2: /* plane 1 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[1]->par;
+ if (hw->desc[1] != ad->paddr) {
+ /* AOI1 is not the first in the chain */
+ if (pmfbi->count > 0)
+ /* AOI0 is open, must be the first */
+ pmfbi->ad->next_ad = 0;
+ } else /* AOI1 is the first in the chain */
+ out_be32(&(hw->desc[1]), machine_data->dummy_ad->paddr);
+ /* close AOI 1 */
+ break;
+ case 4: /* plane 2 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[3]->par;
+ if (hw->desc[2] != ad->paddr) {
+ /* AOI1 is not the first in the chain */
+ if (pmfbi->count > 0)
+ /* AOI0 is open, must be the first */
+ pmfbi->ad->next_ad = 0;
+ } else /* AOI1 is the first in the chain */
+ out_be32(&(hw->desc[2]), machine_data->dummy_ad->paddr);
+ /* close AOI 1 */
+ break;
+ default:
+ res = -EINVAL;
+ break;
+ }
+
+ return res;
+}
+
+static void enable_lcdc(struct fb_info *info)
+{
+ struct diu *hw = dr.diu_reg;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+
+ if (!machine_data->fb_enabled) {
+ out_be32(&(hw->diu_mode), dr.mode);
+ machine_data->fb_enabled++;
+ }
+}
+
+static void disable_lcdc(struct fb_info *info)
+{
+ struct diu *hw = dr.diu_reg;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+
+ if (machine_data->fb_enabled) {
+ out_be32(&(hw->diu_mode), 0);
+ machine_data->fb_enabled = 0;
+ }
+}
+
+/*
+ * Checks to see if the hardware supports the state requested by var passed
+ * in. This function does not alter the hardware state! If the var passed in
+ * is slightly off by what the hardware can support then we alter the var
+ * PASSED in to what we can do. If the hardware doesn't support mode change
+ * a -EINVAL will be returned by the upper layers.
+ */
+static int fsl_diu_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ unsigned long htotal, vtotal;
+ struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int index = mfbi->index;
+
+ pr_debug("check_var xres: %d\n", var->xres);
+ pr_debug("check_var yres: %d\n", var->yres);
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if (var->xoffset < 0)
+ var->xoffset = 0;
+
+ if (var->yoffset < 0)
+ var->yoffset = 0;
+
+ if (var->xoffset + info->var.xres > info->var.xres_virtual)
+ var->xoffset = info->var.xres_virtual - info->var.xres;
+
+ if (var->yoffset + info->var.yres > info->var.yres_virtual)
+ var->yoffset = info->var.yres_virtual - info->var.yres;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+ (var->bits_per_pixel != 16))
+ var->bits_per_pixel = default_bpp;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 24:
+ var->red.length = 8;
+ var->red.offset = 0;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 16;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ var->transp.msb_right = 0;
+
+ break;
+ }
+ /* If the pixclock is below the minimum spec'd value then set to
+ * refresh rate for 60Hz since this is supported by most monitors.
+ * Refer to Documentation/fb/ for calculations.
+ */
+ if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) {
+ htotal = var->xres + var->right_margin + var->hsync_len +
+ var->left_margin;
+ vtotal = var->yres + var->lower_margin + var->vsync_len +
+ var->upper_margin;
+ var->pixclock = (vtotal * htotal * 6UL) / 100UL;
+ var->pixclock = KHZ2PICOS(var->pixclock);
+ pr_debug("pixclock set for 60Hz refresh = %u ps\n",
+ var->pixclock);
+ }
+
+ var->height = -1;
+ var->width = -1;
+ var->grayscale = 0;
+
+ /* Copy nonstd field to/from sync for fbset usage */
+ var->sync |= var->nonstd;
+ var->nonstd |= var->sync;
+
+ /* check AOI position */
+ switch (index) {
+ case 0:
+ if (mfbi->x_aoi_d != 0)
+ mfbi->x_aoi_d = 0;
+ if (mfbi->y_aoi_d != 0)
+ mfbi->y_aoi_d = 0;
+ break;
+ case 1: /* AOI 0 */
+ case 3:
+ cmfbi = machine_data->fsl_diu_info[index+1]->par;
+ if ((mfbi->x_aoi_d + var->xres) >
+ machine_data->fsl_diu_info[0]->var.xres)
+ mfbi->x_aoi_d = machine_data->fsl_diu_info[0]->var.xres
+ - var->xres;
+ if (mfbi->x_aoi_d < 0)
+ mfbi->x_aoi_d = 0;
+ if ((var->xres + mfbi->x_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.xres)
+ var->xres = machine_data->fsl_diu_info[0]->var.xres
+ - mfbi->x_aoi_d;
+
+ if (cmfbi->count > 0) { /* AOI1 is open */
+ if ((mfbi->y_aoi_d + var->yres) > cmfbi->y_aoi_d)
+ mfbi->y_aoi_d = cmfbi->y_aoi_d - var->yres;
+ if (mfbi->y_aoi_d < 0)
+ mfbi->y_aoi_d = 0;
+ if ((var->yres + mfbi->y_aoi_d) > cmfbi->y_aoi_d)
+ var->yres = cmfbi->y_aoi_d - mfbi->y_aoi_d;
+ } else { /* AOI1 is close */
+ if ((mfbi->y_aoi_d + var->yres) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ mfbi->y_aoi_d =
+ machine_data->fsl_diu_info[0]->var.yres
+ - var->yres;
+ if (mfbi->y_aoi_d < 0)
+ mfbi->y_aoi_d = 0;
+ if ((var->yres + mfbi->y_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ var->yres =
+ machine_data->fsl_diu_info[0]->var.yres
+ - mfbi->y_aoi_d;
+ }
+ break;
+ case 2: /* AOI 1 */
+ case 4:
+ pmfbi = machine_data->fsl_diu_info[index-1]->par;
+ if ((mfbi->x_aoi_d + var->xres) >
+ machine_data->fsl_diu_info[0]->var.xres)
+ mfbi->x_aoi_d = machine_data->fsl_diu_info[0]->var.xres
+ - var->xres;
+ if (mfbi->x_aoi_d < 0)
+ mfbi->x_aoi_d = 0;
+ if ((var->xres + mfbi->x_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.xres)
+ var->xres = machine_data->fsl_diu_info[0]->var.xres
+ - mfbi->x_aoi_d;
+
+ if (pmfbi->count > 0) { /* AOI0 is open */
+ if ((mfbi->y_aoi_d + var->yres) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ mfbi->y_aoi_d =
+ machine_data->fsl_diu_info[0]->var.yres
+ - var->yres;
+ if (mfbi->y_aoi_d < (pmfbi->y_aoi_d +
+ machine_data->fsl_diu_info[index-1]->var.yres))
+ mfbi->y_aoi_d = pmfbi->y_aoi_d +
+ machine_data->fsl_diu_info[index-1]->var.yres;
+ if ((var->yres + mfbi->y_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ var->yres =
+ machine_data->fsl_diu_info[0]->var.yres
+ - mfbi->y_aoi_d;
+ } else { /* AOI0 is close */
+ if ((mfbi->y_aoi_d + var->yres) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ mfbi->y_aoi_d =
+ machine_data->fsl_diu_info[0]->var.yres
+ - var->yres;
+ if (mfbi->y_aoi_d < 0)
+ mfbi->y_aoi_d = 0;
+ if ((var->yres + mfbi->y_aoi_d) >
+ machine_data->fsl_diu_info[0]->var.yres)
+ var->yres =
+ machine_data->fsl_diu_info[0]->var.yres
+ - mfbi->y_aoi_d;
+ }
+ break;
+ }
+ return 0;
+}
+
+static void set_fix(struct fb_info *info)
+{
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+
+ strncpy(fix->id, mfbi->id, strlen(mfbi->id));
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+}
+
+static void update_lcdc(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ struct diu *hw;
+ int i, j;
+ char __iomem *cursor_base, *gamma_table_base;
+
+ u32 temp;
+
+ hw = dr.diu_reg;
+
+ if (mfbi->type == MFB_TYPE_OFF) {
+ fsl_diu_disable_panel(info);
+ return;
+ }
+
+ diu_ops.set_monitor_port(machine_data->monitor_port);
+ gamma_table_base = pool.gamma.vaddr;
+ cursor_base = pool.cursor.vaddr;
+ /* Prep for DIU init - gamma table, cursor table */
+
+ for (i = 0; i <= 2; i++)
+ for (j = 0; j <= 255; j++)
+ *gamma_table_base++ = j;
+
+ diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr);
+
+ pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
+ disable_lcdc(info);
+
+ /* Program DIU registers */
+
+ out_be32(&(hw->gamma), pool.gamma.paddr);
+ out_be32(&(hw->cursor), pool.cursor.paddr);
+
+ out_be32(&(hw->bgnd), 0x007F7F7F); /* BGND */
+ out_be32(&(hw->bgnd_wb), 0); /* BGND_WB */
+ out_be32(&(hw->disp_size), (var->yres << 16 | var->xres));
+ /* DISP SIZE */
+ pr_debug("DIU xres: %d\n", var->xres);
+ pr_debug("DIU yres: %d\n", var->yres);
+
+ out_be32(&(hw->wb_size), 0); /* WB SIZE */
+ out_be32(&(hw->wb_mem_addr), 0); /* WB MEM ADDR */
+
+ /* Horizontal and vertical configuration register */
+ temp = var->left_margin << 22 | /* BP_H */
+ var->hsync_len << 11 | /* PW_H */
+ var->right_margin; /* FP_H */
+
+ out_be32(&(hw->hsyn_para), temp);
+
+ temp = var->upper_margin << 22 | /* BP_V */
+ var->vsync_len << 11 | /* PW_V */
+ var->lower_margin; /* FP_V */
+
+ out_be32(&(hw->vsyn_para), temp);
+
+ pr_debug("DIU right_margin - %d\n", var->right_margin);
+ pr_debug("DIU left_margin - %d\n", var->left_margin);
+ pr_debug("DIU hsync_len - %d\n", var->hsync_len);
+ pr_debug("DIU upper_margin - %d\n", var->upper_margin);
+ pr_debug("DIU lower_margin - %d\n", var->lower_margin);
+ pr_debug("DIU vsync_len - %d\n", var->vsync_len);
+ pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para);
+ pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para);
+
+ diu_ops.set_pixel_clock(var->pixclock);
+
+ out_be32(&(hw->syn_pol), 0); /* SYNC SIGNALS POLARITY */
+ out_be32(&(hw->thresholds), 0x00037800); /* The Thresholds */
+ out_be32(&(hw->int_status), 0); /* INTERRUPT STATUS */
+ out_be32(&(hw->plut), 0x01F5F666);
+
+ /* Enable the DIU */
+ enable_lcdc(info);
+}
+
+static int map_video_memory(struct fb_info *info)
+{
+ phys_addr_t phys;
+
+ pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
+ pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
+ pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
+
+ info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
+ pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
+ info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
+ if (info->screen_base == 0) {
+ printk(KERN_ERR "Unable to allocate fb memory\n");
+ return -ENOMEM;
+ }
+ info->fix.smem_start = (unsigned long) phys;
+ info->screen_size = info->fix.smem_len;
+
+ pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
+ info->fix.smem_start,
+ info->fix.smem_len);
+ pr_debug("screen base %p\n", info->screen_base);
+
+ return 0;
+}
+
+static void unmap_video_memory(struct fb_info *info)
+{
+ fsl_diu_free(info->screen_base, info->fix.smem_len);
+ info->screen_base = 0;
+ info->fix.smem_start = 0;
+ info->fix.smem_len = 0;
+}
+
+/*
+ * Using the fb_var_screeninfo in fb_info we set the resolution of this
+ * particular framebuffer. This function alters the fb_fix_screeninfo stored
+ * in fb_info. It does not alter var in fb_info since we are using that
+ * data. This means we depend on the data in var inside fb_info to be
+ * supported by the hardware. fsl_diu_check_var is always called before
+ * fsl_diu_set_par to ensure this.
+ */
+static int fsl_diu_set_par(struct fb_info *info)
+{
+ unsigned long len;
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ struct diu_ad *ad = mfbi->ad;
+ struct diu *hw;
+
+ hw = dr.diu_reg;
+
+ set_fix(info);
+ mfbi->cursor_reset = 1;
+
+ len = info->var.yres_virtual * info->fix.line_length;
+ /* Alloc & dealloc each time resolution/bpp change */
+ if (len != info->fix.smem_len) {
+ if (info->fix.smem_start)
+ unmap_video_memory(info);
+ pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len);
+
+ /* Memory allocation for framebuffer */
+ if (map_video_memory(info)) {
+ printk(KERN_ERR "Unable to allocate fb memory 1\n");
+ return -ENOMEM;
+ }
+ }
+
+ ad->pix_fmt =
+ diu_ops.get_pixel_format(var->bits_per_pixel,
+ machine_data->monitor_port);
+ ad->addr = cpu_to_le32(info->fix.smem_start);
+ ad->src_size_g_alpha = cpu_to_le32((var->yres << 12) |
+ var->xres) | mfbi->g_alpha;
+ /* fix me. AOI should not be greater than display size */
+ ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres);
+ ad->offset_xyi = 0;
+ ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
+
+ /* Disable chroma keying function */
+ ad->ckmax_r = 0;
+ ad->ckmax_g = 0;
+ ad->ckmax_b = 0;
+
+ ad->ckmin_r = 255;
+ ad->ckmin_g = 255;
+ ad->ckmin_b = 255;
+
+ if (mfbi->index == 0)
+ update_lcdc(info);
+ return 0;
+}
+
+/*
+ * Set a single color register. The values supplied have a 16 bit magnitude
+ * which needs to be scaled in this function for the hardware. Things to take
+ * into consideration are how many color registers, if any, are supported with
+ * the current color visual. With truecolor mode no color palettes are
+ * supported. Here a psuedo palette is created which we store the value in
+ * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
+ * color palette.
+ */
+static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+{
+ int ret = 1;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+ u32 v;
+
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+#undef CNVT_TOHW
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ pal[regno] = v;
+ ret = 0;
+ }
+ break;
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Pan (or wrap, depending on the `vmode' field) the display using the
+ * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values
+ * don't fit, return -EINVAL.
+ */
+static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ if ((info->var.xoffset == var->xoffset) &&
+ (info->var.yoffset == var->yoffset))
+ return 0; /* No change, do nothing */
+
+ if (var->xoffset < 0 || var->yoffset < 0
+ || var->xoffset + info->var.xres > info->var.xres_virtual
+ || var->yoffset + info->var.yres > info->var.yres_virtual)
+ return -EINVAL;
+
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+
+ return 0;
+}
+
+/*
+ * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
+ * succeeded, != 0 if un-/blanking failed.
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
+ */
+static int fsl_diu_blank(int blank_mode, struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ mfbi->blank = blank_mode;
+
+ switch (blank_mode) {
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ /* FIXME: fixes to enable_panel and enable lcdc needed */
+ case FB_BLANK_NORMAL:
+ /* fsl_diu_disable_panel(info);*/
+ break;
+ case FB_BLANK_POWERDOWN:
+ /* disable_lcdc(info); */
+ break;
+ case FB_BLANK_UNBLANK:
+ /* fsl_diu_enable_panel(info);*/
+ break;
+ }
+
+ return 0;
+}
+
+static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mfb_info *mfbi = info->par;
+ struct diu_ad *ad = mfbi->ad;
+ struct mfb_chroma_key ck;
+ unsigned char global_alpha;
+ struct aoi_display_offset aoi_d;
+ __u32 pix_fmt;
+
+ switch (cmd) {
+ case MFB_SET_PIXFMT:
+ if (!arg)
+ return -EINVAL;
+ if (copy_from_user((void *)&pix_fmt, (void *)arg,
+ sizeof(pix_fmt)))
+ return -EFAULT;
+ ad->pix_fmt = pix_fmt;
+ pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
+ break;
+ case MFB_GET_PIXFMT:
+ if (!arg)
+ return -EINVAL;
+ pix_fmt = ad->pix_fmt;
+ if (copy_to_user((void *)arg, (void *)&pix_fmt,
+ sizeof(pix_fmt)))
+ return -EFAULT;
+ pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
+ break;
+ case MFB_SET_AOID:
+ if (!arg)
+ return -EINVAL;
+ if (copy_from_user((void *)&aoi_d, (void *)arg, sizeof(aoi_d)))
+ return -EFAULT;
+ mfbi->x_aoi_d = aoi_d.x_aoi_d;
+ mfbi->y_aoi_d = aoi_d.y_aoi_d;
+ pr_debug("set AOI display offset of index %d to (%d,%d)\n",
+ mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
+ fsl_diu_check_var(&info->var, info);
+ fsl_diu_set_par(info);
+ break;
+ case MFB_GET_AOID:
+ if (!arg)
+ return -EINVAL;
+ aoi_d.x_aoi_d = mfbi->x_aoi_d;
+ aoi_d.y_aoi_d = mfbi->y_aoi_d;
+ if (copy_to_user((void *)arg, (void *)&aoi_d, sizeof(aoi_d)))
+ return -EFAULT;
+ pr_debug("get AOI display offset of index %d (%d,%d)\n",
+ mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
+ break;
+ case MFB_GET_ALPHA:
+ if (!arg)
+ return -EINVAL;
+ global_alpha = mfbi->g_alpha;
+ if (copy_to_user((void *)arg, (void *)&global_alpha,
+ sizeof(global_alpha)))
+ return -EFAULT;
+ pr_debug("get global alpha of index %d\n", mfbi->index);
+ break;
+ case MFB_SET_ALPHA:
+ if (!arg)
+ return -EINVAL;
+
+ /* set panel information */
+ if (copy_from_user((void *)&global_alpha, (void *)arg,
+ sizeof(global_alpha)))
+ return -EFAULT;
+ ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
+ (global_alpha & 0xff);
+ mfbi->g_alpha = global_alpha;
+ pr_debug("set global alpha for index %d\n", mfbi->index);
+ break;
+ case MFB_SET_CHROMA_KEY:
+ if (!arg)
+ return -EINVAL;
+
+ /* set panel winformation */
+ if (copy_from_user((void *)&ck, (void *)arg, sizeof(ck)))
+ return -EFAULT;
+
+ if (ck.enable &&
+ (ck.red_max < ck.red_min ||
+ ck.green_max < ck.green_min ||
+ ck.blue_max < ck.blue_min))
+ return -EINVAL;
+
+ if (!ck.enable) {
+ ad->ckmax_r = 0;
+ ad->ckmax_g = 0;
+ ad->ckmax_b = 0;
+ ad->ckmin_r = 255;
+ ad->ckmin_g = 255;
+ ad->ckmin_b = 255;
+ } else {
+ ad->ckmax_r = ck.red_max;
+ ad->ckmax_g = ck.green_max;
+ ad->ckmax_b = ck.blue_max;
+ ad->ckmin_r = ck.red_min;
+ ad->ckmin_g = ck.green_min;
+ ad->ckmin_b = ck.blue_min;
+ }
+ pr_debug("set chroma key\n");
+ break;
+ case FBIOGET_GWINFO:
+ if (mfbi->type == MFB_TYPE_OFF)
+ return -ENODEV;
+
+ if (!arg)
+ return -EINVAL;
+
+ /* get graphic window information */
+ if (copy_to_user((void *)arg, (void *)ad, sizeof(*ad)))
+ return -EFAULT;
+ break;
+ case FBIOGET_HWCINFO:
+ pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
+ break;
+ case FBIOPUT_MODEINFO:
+ pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
+ break;
+ case FBIOGET_DISPINFO:
+ pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
+ return 0;
+ }
+
+ return 0;
+}
+
+/* turn on fb if count == 1
+ */
+static int fsl_diu_open(struct fb_info *info, int user)
+{
+ struct mfb_info *mfbi = info->par;
+ int res = 0;
+
+ spin_lock(&diu_lock);
+ mfbi->count++;
+ if (mfbi->count == 1) {
+ pr_debug("open plane index %d\n", mfbi->index);
+ fsl_diu_check_var(&info->var, info);
+ res = fsl_diu_set_par(info);
+ if (res < 0)
+ mfbi->count--;
+ else {
+ res = fsl_diu_enable_panel(info);
+ if (res < 0)
+ mfbi->count--;
+ }
+ }
+
+ spin_unlock(&diu_lock);
+ return res;
+}
+
+/* turn off fb if count == 0
+ */
+static int fsl_diu_release(struct fb_info *info, int user)
+{
+ struct mfb_info *mfbi = info->par;
+ int res = 0;
+
+ spin_lock(&diu_lock);
+ mfbi->count--;
+ if (mfbi->count == 0) {
+ pr_debug("release plane index %d\n", mfbi->index);
+ res = fsl_diu_disable_panel(info);
+ if (res < 0)
+ mfbi->count++;
+ }
+ spin_unlock(&diu_lock);
+ return res;
+}
+
+static struct fb_ops fsl_diu_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = fsl_diu_check_var,
+ .fb_set_par = fsl_diu_set_par,
+ .fb_setcolreg = fsl_diu_setcolreg,
+ .fb_blank = fsl_diu_blank,
+ .fb_pan_display = fsl_diu_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_ioctl = fsl_diu_ioctl,
+ .fb_open = fsl_diu_open,
+ .fb_release = fsl_diu_release,
+};
+
+static int init_fbinfo(struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ info->device = NULL;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->fbops = &fsl_diu_ops;
+ info->flags = FBINFO_FLAG_DEFAULT;
+ info->pseudo_palette = &mfbi->pseudo_palette;
+
+ /* Allocate colormap */
+ fb_alloc_cmap(&info->cmap, 16, 0);
+ return 0;
+}
+
+static int install_fb(struct fb_info *info)
+{
+ int rc;
+ struct mfb_info *mfbi = info->par;
+ const char *aoi_mode, *init_aoi_mode = "320x240";
+
+ if (init_fbinfo(info))
+ return -EINVAL;
+
+ if (mfbi->index == 0) /* plane 0 */
+ aoi_mode = fb_mode;
+ else
+ aoi_mode = init_aoi_mode;
+ pr_debug("mode used = %s\n", aoi_mode);
+ rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
+ ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);
+
+ switch (rc) {
+ case 1:
+ pr_debug("using mode specified in @mode\n");
+ break;
+ case 2:
+ pr_debug("using mode specified in @mode "
+ "with ignored refresh rate\n");
+ break;
+ case 3:
+ pr_debug("using mode default mode\n");
+ break;
+ case 4:
+ pr_debug("using mode from list\n");
+ break;
+ default:
+ pr_debug("rc = %d\n", rc);
+ pr_debug("failed to find mode\n");
+ return -EINVAL;
+ break;
+ }
+
+ pr_debug("xres_virtual %d\n", info->var.xres_virtual);
+ pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
+
+ pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
+ pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
+
+ if (mfbi->type == MFB_TYPE_OFF)
+ mfbi->blank = FB_BLANK_NORMAL;
+ else
+ mfbi->blank = FB_BLANK_UNBLANK;
+
+ if (fsl_diu_check_var(&info->var, info)) {
+ printk(KERN_ERR "fb_check_var failed");
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ if (fsl_diu_set_par(info)) {
+ printk(KERN_ERR "fb_set_par failed");
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ if (register_framebuffer(info) < 0) {
+ printk(KERN_ERR "register_framebuffer failed");
+ unmap_video_memory(info);
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ mfbi->registered = 1;
+ printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
+ info->node, info->fix.id);
+
+ return 0;
+}
+
+static void __exit uninstall_fb(struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ if (!mfbi->registered)
+ return;
+
+ unregister_framebuffer(info);
+ unmap_video_memory(info);
+ if (&info->cmap)
+ fb_dealloc_cmap(&info->cmap);
+
+ mfbi->registered = 0;
+}
+
+static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
+{
+ struct diu *hw = dr.diu_reg;
+ unsigned int status = in_be32(&(hw->int_status));
+
+ if (status) {
+ /* This is the workaround for underrun */
+ if (status & INT_UNDRUN) {
+ out_be32(&(hw->diu_mode), 0);
+ pr_debug("Err: DIU occurs underrun!\n");
+ udelay(1);
+ out_be32(&(hw->diu_mode), 1);
+ }
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ else if (status & INT_VSYNC) {
+ int i;
+ unsigned int *ptr;
+ ptr = coherence_data;
+ for (i = 0; i < 1024*8; i++)
+ *ptr++ = 0;
+ }
+#endif
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int request_irq_local(int irq)
+{
+ unsigned long status, ints;
+ struct diu *hw;
+ int ret;
+
+ hw = dr.diu_reg;
+
+ /* Read to clear the status */
+ status = in_be32(&(hw->int_status));
+
+ ret = request_irq(irq, fsl_diu_isr, 0, "diu", 0);
+ if (ret)
+ pr_info("Request diu IRQ failed.\n");
+ else {
+ ints = INT_PARERR | INT_LS_BF_VS;
+#if !defined(CONFIG_NOT_COHERENT_CACHE)
+ ints |= INT_VSYNC;
+#endif
+ if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
+ ints |= INT_VSYNC_WB;
+
+ /* Read to clear the status */
+ status = in_be32(&(hw->int_status));
+ out_be32(&(hw->int_mask), ints);
+ }
+ return ret;
+}
+
+static void free_irq_local(int irq)
+{
+ struct diu *hw = dr.diu_reg;
+
+ /* Disable all LCDC interrupt */
+ out_be32(&(hw->int_mask), 0x1f);
+
+ free_irq(irq, 0);
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int fsl_diu_suspend(struct of_device *dev, pm_message_t state)
+{
+ struct fsl_diu_data *machine_data;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ disable_lcdc(machine_data->fsl_diu_info[0]);
+
+ return 0;
+}
+
+static int fsl_diu_resume(struct of_device *dev)
+{
+ struct fsl_diu_data *machine_data;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ enable_lcdc(machine_data->fsl_diu_info[0]);
+
+ return 0;
+}
+
+#else
+#define fsl_diu_suspend NULL
+#define fsl_diu_resume NULL
+#endif /* CONFIG_PM */
+
+/* Align to 64-bit(8-byte), 32-byte, etc. */
+static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+{
+ u32 offset, ssize;
+ u32 mask;
+ dma_addr_t paddr = 0;
+
+ ssize = size + bytes_align;
+ buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | __GFP_ZERO);
+ if (!buf->vaddr)
+ return -ENOMEM;
+
+ buf->paddr = (__u32) paddr;
+
+ mask = bytes_align - 1;
+ offset = (u32)buf->paddr & mask;
+ if (offset) {
+ buf->offset = bytes_align - offset;
+ buf->paddr = (u32)buf->paddr + offset;
+ } else
+ buf->offset = 0;
+ return 0;
+}
+
+static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+{
+ dma_free_coherent(0, size + bytes_align,
+ buf->vaddr, (buf->paddr - buf->offset));
+ return;
+}
+
+static ssize_t store_monitor(struct device *device,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int old_monitor_port;
+ unsigned long val;
+ struct fsl_diu_data *machine_data =
+ container_of(attr, struct fsl_diu_data, dev_attr);
+
+ if (strict_strtoul(buf, 10, &val))
+ return 0;
+
+ old_monitor_port = machine_data->monitor_port;
+ machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);
+
+ if (old_monitor_port != machine_data->monitor_port) {
+ /* All AOIs need adjust pixel format
+ * fsl_diu_set_par only change the pixsel format here
+ * unlikely to fail. */
+ fsl_diu_set_par(machine_data->fsl_diu_info[0]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[1]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[2]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[3]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[4]);
+ }
+ return count;
+}
+
+static ssize_t show_monitor(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct fsl_diu_data *machine_data =
+ container_of(attr, struct fsl_diu_data, dev_attr);
+ return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
+}
+
+static int fsl_diu_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct mfb_info *mfbi;
+ phys_addr_t dummy_ad_addr;
+ int ret, i, error = 0;
+ struct resource res;
+ struct fsl_diu_data *machine_data;
+
+ machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
+ if (!machine_data)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
+ machine_data->fsl_diu_info[i] =
+ framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
+ if (!machine_data->fsl_diu_info[i]) {
+ dev_err(&ofdev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto error2;
+ }
+ mfbi = machine_data->fsl_diu_info[i]->par;
+ memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
+ mfbi->parent = machine_data;
+ }
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ dev_err(&ofdev->dev, "could not obtain DIU address\n");
+ goto error;
+ }
+ if (!res.start) {
+ dev_err(&ofdev->dev, "invalid DIU address\n");
+ goto error;
+ }
+ dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
+
+ dr.diu_reg = ioremap(res.start, sizeof(struct diu));
+ if (!dr.diu_reg) {
+ dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
+ ret = -EFAULT;
+ goto error2;
+ }
+
+ out_be32(&(dr.diu_reg->diu_mode), 0); /* disable DIU anyway*/
+
+ /* Get the IRQ of the DIU */
+ machine_data->irq = irq_of_parse_and_map(np, 0);
+
+ if (!machine_data->irq) {
+ dev_err(&ofdev->dev, "could not get DIU IRQ\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ machine_data->monitor_port = monitor_port;
+
+ /* Area descriptor memory pool aligns to 64-bit boundary */
+ if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
+ return -ENOMEM;
+
+ /* Get memory for Gamma Table - 32-byte aligned memory */
+ if (allocate_buf(&pool.gamma, 768, 32)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
+ if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ i = ARRAY_SIZE(machine_data->fsl_diu_info);
+ machine_data->dummy_ad = (struct diu_ad *)
+ ((u32)pool.ad.vaddr + pool.ad.offset) + i;
+ machine_data->dummy_ad->paddr = pool.ad.paddr +
+ i * sizeof(struct diu_ad);
+ machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
+ if (!machine_data->dummy_aoi_virt) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
+ machine_data->dummy_ad->pix_fmt = 0x88882317;
+ machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
+ machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2);
+ machine_data->dummy_ad->offset_xyi = 0;
+ machine_data->dummy_ad->offset_xyd = 0;
+ machine_data->dummy_ad->next_ad = 0;
+
+ out_be32(&(dr.diu_reg->desc[0]), machine_data->dummy_ad->paddr);
+ out_be32(&(dr.diu_reg->desc[1]), machine_data->dummy_ad->paddr);
+ out_be32(&(dr.diu_reg->desc[2]), machine_data->dummy_ad->paddr);
+
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
+ machine_data->fsl_diu_info[i]->fix.smem_start = 0;
+ mfbi = machine_data->fsl_diu_info[i]->par;
+ mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
+ + pool.ad.offset) + i;
+ mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
+ ret = install_fb(machine_data->fsl_diu_info[i]);
+ if (ret) {
+ dev_err(&ofdev->dev,
+ "Failed to register framebuffer %d\n",
+ i);
+ goto error;
+ }
+ }
+
+ if (request_irq_local(machine_data->irq)) {
+ dev_err(machine_data->fsl_diu_info[0]->dev,
+ "could not request irq for diu.");
+ goto error;
+ }
+
+ machine_data->dev_attr.attr.name = "monitor";
+ machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
+ machine_data->dev_attr.show = show_monitor;
+ machine_data->dev_attr.store = store_monitor;
+ error = device_create_file(machine_data->fsl_diu_info[0]->dev,
+ &machine_data->dev_attr);
+ if (error) {
+ dev_err(machine_data->fsl_diu_info[0]->dev,
+ "could not create sysfs %s file\n",
+ machine_data->dev_attr.attr.name);
+ }
+
+ dev_set_drvdata(&ofdev->dev, machine_data);
+ return 0;
+
+error:
+ for (i = ARRAY_SIZE(machine_data->fsl_diu_info);
+ i > 0; i--)
+ uninstall_fb(machine_data->fsl_diu_info[i - 1]);
+ if (pool.ad.vaddr)
+ free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+ if (pool.gamma.vaddr)
+ free_buf(&pool.gamma, 768, 32);
+ if (pool.cursor.vaddr)
+ free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);
+ if (machine_data->dummy_aoi_virt)
+ fsl_diu_free(machine_data->dummy_aoi_virt, 64);
+ iounmap(dr.diu_reg);
+
+error2:
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+ if (machine_data->fsl_diu_info[i])
+ framebuffer_release(machine_data->fsl_diu_info[i]);
+ kfree(machine_data);
+
+ return ret;
+}
+
+
+static int fsl_diu_remove(struct of_device *ofdev)
+{
+ struct fsl_diu_data *machine_data;
+ int i;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ disable_lcdc(machine_data->fsl_diu_info[0]);
+ free_irq_local(machine_data->irq);
+ for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)
+ uninstall_fb(machine_data->fsl_diu_info[i - 1]);
+ if (pool.ad.vaddr)
+ free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+ if (pool.gamma.vaddr)
+ free_buf(&pool.gamma, 768, 32);
+ if (pool.cursor.vaddr)
+ free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);
+ if (machine_data->dummy_aoi_virt)
+ fsl_diu_free(machine_data->dummy_aoi_virt, 64);
+ iounmap(dr.diu_reg);
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+ if (machine_data->fsl_diu_info[i])
+ framebuffer_release(machine_data->fsl_diu_info[i]);
+ kfree(machine_data);
+
+ return 0;
+}
+
+#ifndef MODULE
+static int __init fsl_diu_setup(char *options)
+{
+ char *opt;
+ unsigned long val;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+ if (!strncmp(opt, "monitor=", 8)) {
+ if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2))
+ monitor_port = val;
+ } else if (!strncmp(opt, "bpp=", 4)) {
+ if (!strict_strtoul(opt + 4, 10, &val))
+ default_bpp = val;
+ } else
+ fb_mode = opt;
+ }
+
+ return 0;
+}
+#endif
+
+static struct of_device_id fsl_diu_match[] = {
+ {
+ .compatible = "fsl-diu",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_diu_match);
+
+static struct of_platform_driver fsl_diu_driver = {
+ .owner = THIS_MODULE,
+ .name = "fsl_diu",
+ .match_table = fsl_diu_match,
+ .probe = fsl_diu_probe,
+ .remove = fsl_diu_remove,
+ .suspend = fsl_diu_suspend,
+ .resume = fsl_diu_resume,
+};
+
+static int __init fsl_diu_init(void)
+{
+ int ret;
+#ifndef MODULE
+ char *option;
+ /*
+ * For kernel boot options (in 'video=xxxfb:<options>' format)
+ */
+ if (fb_get_options("fslfb", &option))
+ return -ENODEV;
+ fsl_diu_setup(option);
+#endif
+ printk(KERN_INFO "Freescale DIU driver\n");
+
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ coherence_data = fsl_diu_alloc(32*1024, &coherence_data_phy);
+ if (!coherence_data) {
+ ret = -ENOMEM;
+ goto error;
+ }
+#endif
+ ret = of_register_platform_driver(&fsl_diu_driver);
+ if (ret) {
+ printk(KERN_ERR
+ "fsl-diu: failed to register platform driver\n");
+ iounmap(dr.diu_reg);
+ }
+ return ret;
+}
+
+static void __exit fsl_diu_exit(void)
+{
+ of_unregister_platform_driver(&fsl_diu_driver);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ if (coherence_data)
+ fsl_diu_free(coherence_data, 32*1024);
+#endif
+}
+
+module_init(fsl_diu_init);
+module_exit(fsl_diu_exit);
+
+MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
+MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
+MODULE_LICENSE("GPL");
+
+module_param_named(mode, fb_mode, charp, 0);
+MODULE_PARM_DESC(mode,
+ "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+module_param_named(bpp, default_bpp, ulong, 0);
+MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
+module_param_named(monitor, monitor_port, int, 0);
+MODULE_PARM_DESC(monitor,
+ "Specify the monitor port (0, 1 or 2) if supported by the platform");
+
diff --git a/drivers/video/fsl-diu-fb.h b/drivers/video/fsl-diu-fb.h
new file mode 100644
index 0000000..f413b96
--- /dev/null
+++ b/drivers/video/fsl-diu-fb.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale DIU Frame Buffer device driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Paul Widmer <paul.widmer@freescale.com>
+ * Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ * York Sun <yorksun@freescale.com>
+ * Copyright (C) Freescale Semicondutor, Inc. 2007. All rights reserved.
+ *
+ * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ * 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.
+ *
+ */
+
+#ifndef __FSL_DIU_FB_H__
+#define __FSL_DIU_FB_H__
+
+/* Arbitrary threshold to determine the allocation method
+ * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory()
+ */
+#define MEM_ALLOC_THRESHOLD (1024*768*4+32)
+/* Minimum value that the pixel clock can be set to in pico seconds
+ * This is determined by platform clock/3 where the minimum platform
+ * clock is 533MHz. This gives 5629 pico seconds.
+ */
+#define MIN_PIX_CLK 5629
+#define MAX_PIX_CLK 96096
+
+#include <linux/types.h>
+
+struct mfb_alpha {
+ int enable;
+ int alpha;
+};
+
+struct mfb_chroma_key {
+ int enable;
+ __u8 red_max;
+ __u8 green_max;
+ __u8 blue_max;
+ __u8 red_min;
+ __u8 green_min;
+ __u8 blue_min;
+};
+
+struct aoi_display_offset {
+ int x_aoi_d;
+ int y_aoi_d;
+};
+
+#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key)
+#define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
+#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8)
+
+#define MFB_SET_ALPHA 0x80014d00
+#define MFB_GET_ALPHA 0x40014d00
+#define MFB_SET_AOID 0x80084d04
+#define MFB_GET_AOID 0x40084d04
+#define MFB_SET_PIXFMT 0x80014d08
+#define MFB_GET_PIXFMT 0x40014d08
+
+#define FBIOGET_GWINFO 0x46E0
+#define FBIOPUT_GWINFO 0x46E1
+
+#ifdef __KERNEL__
+#include <linux/spinlock.h>
+
+/*
+ * These are the fields of area descriptor(in DDR memory) for every plane
+ */
+struct diu_ad {
+ /* Word 0(32-bit) in DDR memory */
+/* __u16 comp; */
+/* __u16 pixel_s:2; */
+/* __u16 pallete:1; */
+/* __u16 red_c:2; */
+/* __u16 green_c:2; */
+/* __u16 blue_c:2; */
+/* __u16 alpha_c:3; */
+/* __u16 byte_f:1; */
+/* __u16 res0:3; */
+
+ __be32 pix_fmt; /* hard coding pixel format */
+
+ /* Word 1(32-bit) in DDR memory */
+ __le32 addr;
+
+ /* Word 2(32-bit) in DDR memory */
+/* __u32 delta_xs:11; */
+/* __u32 res1:1; */
+/* __u32 delta_ys:11; */
+/* __u32 res2:1; */
+/* __u32 g_alpha:8; */
+ __le32 src_size_g_alpha;
+
+ /* Word 3(32-bit) in DDR memory */
+/* __u32 delta_xi:11; */
+/* __u32 res3:5; */
+/* __u32 delta_yi:11; */
+/* __u32 res4:3; */
+/* __u32 flip:2; */
+ __le32 aoi_size;
+
+ /* Word 4(32-bit) in DDR memory */
+ /*__u32 offset_xi:11;
+ __u32 res5:5;
+ __u32 offset_yi:11;
+ __u32 res6:5;
+ */
+ __le32 offset_xyi;
+
+ /* Word 5(32-bit) in DDR memory */
+ /*__u32 offset_xd:11;
+ __u32 res7:5;
+ __u32 offset_yd:11;
+ __u32 res8:5; */
+ __le32 offset_xyd;
+
+
+ /* Word 6(32-bit) in DDR memory */
+ __u8 ckmax_r;
+ __u8 ckmax_g;
+ __u8 ckmax_b;
+ __u8 res9;
+
+ /* Word 7(32-bit) in DDR memory */
+ __u8 ckmin_r;
+ __u8 ckmin_g;
+ __u8 ckmin_b;
+ __u8 res10;
+/* __u32 res10:8; */
+
+ /* Word 8(32-bit) in DDR memory */
+ __le32 next_ad;
+
+ /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
+ __u32 paddr;
+} __attribute__ ((packed));
+
+/* DIU register map */
+struct diu {
+ __be32 desc[3];
+ __be32 gamma;
+ __be32 pallete;
+ __be32 cursor;
+ __be32 curs_pos;
+ __be32 diu_mode;
+ __be32 bgnd;
+ __be32 bgnd_wb;
+ __be32 disp_size;
+ __be32 wb_size;
+ __be32 wb_mem_addr;
+ __be32 hsyn_para;
+ __be32 vsyn_para;
+ __be32 syn_pol;
+ __be32 thresholds;
+ __be32 int_status;
+ __be32 int_mask;
+ __be32 colorbar[8];
+ __be32 filling;
+ __be32 plut;
+} __attribute__ ((packed));
+
+struct diu_hw {
+ struct diu *diu_reg;
+ spinlock_t reg_lock;
+
+ __u32 mode; /* DIU operation mode */
+};
+
+struct diu_addr {
+ __u8 __iomem *vaddr; /* Virtual address */
+ dma_addr_t paddr; /* Physical address */
+ __u32 offset;
+};
+
+struct diu_pool {
+ struct diu_addr ad;
+ struct diu_addr gamma;
+ struct diu_addr pallete;
+ struct diu_addr cursor;
+};
+
+#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */
+#define INT_LCDC 64 /* DIU interrupt number */
+
+#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
+ /* 1 for plane 0, 2 for plane 1&2 each */
+
+/* Minimum X and Y resolutions */
+#define MIN_XRES 64
+#define MIN_YRES 64
+
+/* HW cursor parameters */
+#define MAX_CURS 32
+
+/* Modes of operation of DIU */
+#define MFB_MODE0 0 /* DIU off */
+#define MFB_MODE1 1 /* All three planes output to display */
+#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/
+#define MFB_MODE3 3 /* All three planes written back to memory */
+#define MFB_MODE4 4 /* Color bar generation */
+
+/* INT_STATUS/INT_MASK field descriptions */
+#define INT_VSYNC 0x01 /* Vsync interrupt */
+#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */
+#define INT_UNDRUN 0x04 /* Under run exception interrupt */
+#define INT_PARERR 0x08 /* Display parameters error interrupt */
+#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
+
+/* Panels'operation modes */
+#define MFB_TYPE_OUTPUT 0 /* Panel output to display */
+#define MFB_TYPE_OFF 1 /* Panel off */
+#define MFB_TYPE_WB 2 /* Panel written back to memory */
+#define MFB_TYPE_TEST 3 /* Panel generate color bar */
+
+#endif /* __KERNEL__ */
+#endif /* __FSL_DIU_FB_H__ */
--
1.5.2.2
^ permalink raw reply related
* I Need to Reset a PPC405EP PCI Bridge From a Kernel Driver Without Reboot
From: Darcy Watkins @ 2008-03-25 21:28 UTC (permalink / raw)
To: LinuxPPC-Embedded
In-Reply-To: <47E8F836.9060603@coritel.it>
Hello,
I have a peculiar problem dealing with an mPCI wireless network card on
an AMCC405EP based system (spin-off of a Taihu). The task is to load
the FPGA firmware in the card, reset the PCI card (to reset an ASIC, get
it to reload from EEPROM but without resetting the PowerPC and of course
without clearing the firmware in the FPGA), then to rescan (using a fake
hotplug scheme) to find the PCI device, then finally upload a secondary
firmware file to a flash device on the card.
I need this for two reasons. One is to solve a chicken-and-egg type
problem to recover a failed radio card after a botched up upgrade. The
other is to avoid reboots (and wasted time per radio card) as they are
programmed and calibrated in a jig on a manufacturing production line.
I tried setting and then clearing the CPC0_SRR (software reset register)
bit to reset the PCI bridge. I think that this wipes out the PCI bus
completely. Since PCI is initialized by U-Boot, the kernel doesn't
appear to know what to do. I get a data machine check oops at the point
where the device drivers load up and start.
I tried simply saving the 16 words of PCIL0 register content before
toggling the SRR bit, and then restoring them afterwards. No
difference. Next I notice a whole bank of configuration registers and
am wondering just what needs to explicitly be preserved.
Before I go into saving and restoring more registers, or cloning the
4xx_pci.c code from u-Boot into my fake hotplug rescan driver to
reinitialize the PCI subsystem, does anyone have suggestions?
Regards,
Darcy
^ permalink raw reply
* [PATCH] Enable CONFIG_FORCE_MAX_ZONEORDER for all PowerPC, and make selectable
From: Timur Tabi @ 2008-03-25 21:35 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Timur Tabi
This patch enables the FORCE_MAX_ZONEORDER Kconfig option for all PowerPC
systems. Previously, it was enabled only for 64-bit systems. We also make
the option selectable from the menu, so that the user can specify different
values. This is useful for 32-bit systems that need to allocate more than
4MB of physically contiguous memory.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
I tested this on a Freescale 8610 32-bit PowerPC system, and when I increased
CONFIG_FORCE_MAX_ZONEORDER to 13, I was able to allocate 5MB of memory via
__get_free_pages(), so this change should be safe.
arch/powerpc/Kconfig | 23 +++++++++++++++++------
1 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index ef12db0..4e7eec8 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -211,14 +211,25 @@ source kernel/Kconfig.hz
source kernel/Kconfig.preempt
source "fs/Kconfig.binfmt"
-# We optimistically allocate largepages from the VM, so make the limit
-# large enough (16MB). This badly named config option is actually
-# max order + 1
config FORCE_MAX_ZONEORDER
- int
- depends on PPC64
+ int "Maximum zone order"
default "9" if PPC_64K_PAGES
- default "13"
+ default "13" if PPC64
+ default "11"
+ help
+ The kernel memory allocator divides physically contiguous memory
+ blocks into "zones", where each zone is a power of two number of
+ pages. This option selects the largest power of two that the kernel
+ keeps in the memory allocator. If you need to allocate very large
+ blocks of physically contiguous memory, then you may need to
+ increase this value.
+
+ This config option is actually maximum order plus one. For example,
+ a value of 11 means that the largest free memory block is 2^10 pages.
+
+ The page size is not necessarily 4KB. For example, on 64-bit
+ systems, 64KB pages can be enabled via CONFIG_PPC_64K_PAGES. Keep
+ this in mind when choosing a value for this option.
config HUGETLB_PAGE_SIZE_VARIABLE
bool
--
1.5.4
^ permalink raw reply related
* Re: dtc: Simplify error handling for unparseable input
From: Scott Wood @ 2008-03-25 22:10 UTC (permalink / raw)
To: Scott Wood, Jon Loeliger, linuxppc-dev
In-Reply-To: <20080325212127.GA8281@localhost.localdomain>
David Gibson wrote:
> On Tue, Mar 25, 2008 at 09:36:19AM -0500, Scott Wood wrote:
>> On Tue, Mar 25, 2008 at 12:28:05PM +1100, David Gibson wrote:
>>> On Mon, Mar 24, 2008 at 12:36:41PM -0500, Scott Wood wrote:
>>>> If you remove this, there'll be no way to indicate semantic errors other
>>>> than die() (the NULL approaches are no good, since they inhibit recovery),
>>>> which is suboptimal if the error is not immediately fatal.
>>> But everything is immediately fatal. When we have a *real* example of
>>> something that's not, we can restore an error code.
>> Failed binary includes are not immediately fatal.
>
> And is there any advantage to having them not immediately fatal?
It's generally nice to the user if you can report as many bugs as you
can rather than fail on the first one.
It's also nice to someone down the road trying to turn this code into a
library if it passes return status up the call chain gracefully.
-Scott
^ permalink raw reply
* Re: DTS question
From: David Gibson @ 2008-03-25 22:12 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: Scott Wood, linuxppc-dev, Sean MacLennan
In-Reply-To: <22b5aa51cfbcba3072020c4897206473@kernel.crashing.org>
On Fri, Mar 21, 2008 at 12:35:39PM +0100, Segher Boessenkool wrote:
>>>> Convention is to use the stock ticker symbol. If the company is
>>>> private and has no stock ticker symbol, then the company name should
>>>> be used.
>>>
>>> I didn't know that. ADI it is then.
>>
>> Well.. stock ticker is the new convention. IEEE1275 used IEEE
>> assigned OUI strings (Organization Unique Identifiers). Often those
>> are the same as the stock ticker, but not always.
>
> Erm, an OUI is a 24-bit number. I think you're confusing something
> here.
Yes, I think I am. I somehow had the impression that in addition to
the 24-bit OUIs used in MAC addresses, there were also string-form
OUIs assigned.
>> Stock ticker is a good choice for new things, but for anything from a
>> vendor which has existing 1275 bindings for its products, I think we
>> should keep the original assigned OUI, even if it differs from the
>> stock ticker.
>
> Yes, when there is an existing binding, obviously you should use what
> it says (unless that binding is *completely* broken). Compatibility
> is good.
>
> Note that a stock symbol needs to be written in uppercase; in lowercase,
> it is just a random name that has no collision protection.
Um.. bit too late for that. AFAIK, uppercase has been used by
*no-one* for stock ticker derived vendor IDs.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Which Kernel for Ocotea (440GX)?
From: Wolfgang Wegner @ 2008-03-25 22:07 UTC (permalink / raw)
To: linuxppc-dev
Hi List,
sorry for the blunt question...
I want to get an Ocotea dev board (AMCC 440GX) up and running.
As I saw from old posts (2004/2005) that this board should be supported,
I simply fetched a 2.6.24 kernel and - could not find a valid target...
It seems that support for 440gx in the arch/ppc tree was disabled, but
not yet ported to arch/powerpc.
As I am new to Linux/PowerPC, could anybody give me a hint either which
kernel version to use that supports 440GX/Ocotea out of the box or if
there is another repository of a more recent kernel where I could get
that?
Thank you very much!
Regards,
Wolfgang
^ permalink raw reply
* Re: [PATCH 1/2 v3] Driver for Freescale 8610 and 5121 DIU
From: Scott Wood @ 2008-03-25 22:19 UTC (permalink / raw)
To: York Sun
Cc: linux-fbdev-devel, a.p.zijlstra, linux-kernel, linuxppc-dev, akpm,
Timur Tabi
In-Reply-To: <12064804383051-git-send-email-yorksun@freescale.com>
York Sun wrote:
> + Example (MPC8610HPCD)
> + diu@2c000 {
display@2c000
> + device_type = "lcd";
No device_type.
> + compatible = "fsl-diu";
"fsl,diu".
> + s) Freescale on board FPGA
> +
> + This is the memory-mapped registers for on board FPGA.
> +
> + Required properities:
> + - compatible : should be "fsl,fpga-pixis".
> + - reg : should contain the address and the lenght of the FPPGA register
> + set.
> +
> + Example (MPC8610HPCD)
> + fpga {
board-control@e8000000 {
> +config FB_FSL_DIU
> + tristate "Freescale MPC8610/MPC5121 DIU framebuffer support"
Are these the only chips that will ever implement this?
> + depends on FB && (MPC8610 || MPC5121)
depends on FB && FSL_SOC
> + cmfbi = machine_data->fsl_diu_info[index+1]->par;
> + if ((mfbi->x_aoi_d + var->xres) >
> + machine_data->fsl_diu_info[0]->var.xres)
> + mfbi->x_aoi_d = machine_data->fsl_diu_info[0]->var.xres
> + - var->xres;
> + if (mfbi->x_aoi_d < 0)
> + mfbi->x_aoi_d = 0;
> + if ((var->xres + mfbi->x_aoi_d) >
> + machine_data->fsl_diu_info[0]->var.xres)
> + var->xres = machine_data->fsl_diu_info[0]->var.xres
> + - mfbi->x_aoi_d;
> +
> + if (cmfbi->count > 0) { /* AOI1 is open */
> + if ((mfbi->y_aoi_d + var->yres) > cmfbi->y_aoi_d)
> + mfbi->y_aoi_d = cmfbi->y_aoi_d - var->yres;
> + if (mfbi->y_aoi_d < 0)
> + mfbi->y_aoi_d = 0;
> + if ((var->yres + mfbi->y_aoi_d) > cmfbi->y_aoi_d)
> + var->yres = cmfbi->y_aoi_d - mfbi->y_aoi_d;
> + } else { /* AOI1 is close */
> + if ((mfbi->y_aoi_d + var->yres) >
> + machine_data->fsl_diu_info[0]->var.yres)
> + mfbi->y_aoi_d =
> + machine_data->fsl_diu_info[0]->var.yres
> + - var->yres;
> + if (mfbi->y_aoi_d < 0)
> + mfbi->y_aoi_d = 0;
> + if ((var->yres + mfbi->y_aoi_d) >
> + machine_data->fsl_diu_info[0]->var.yres)
> + var->yres =
> + machine_data->fsl_diu_info[0]->var.yres
> + - mfbi->y_aoi_d;
> + }
> + break;
> + case 2: /* AOI 1 */
> + case 4:
> + pmfbi = machine_data->fsl_diu_info[index-1]->par;
> + if ((mfbi->x_aoi_d + var->xres) >
> + machine_data->fsl_diu_info[0]->var.xres)
> + mfbi->x_aoi_d = machine_data->fsl_diu_info[0]->var.xres
> + - var->xres;
> + if (mfbi->x_aoi_d < 0)
> + mfbi->x_aoi_d = 0;
> + if ((var->xres + mfbi->x_aoi_d) >
> + machine_data->fsl_diu_info[0]->var.xres)
> + var->xres = machine_data->fsl_diu_info[0]->var.xres
> + - mfbi->x_aoi_d;
> +
> + if (pmfbi->count > 0) { /* AOI0 is open */
> + if ((mfbi->y_aoi_d + var->yres) >
> + machine_data->fsl_diu_info[0]->var.yres)
> + mfbi->y_aoi_d =
> + machine_data->fsl_diu_info[0]->var.yres
> + - var->yres;
> + if (mfbi->y_aoi_d < (pmfbi->y_aoi_d +
> + machine_data->fsl_diu_info[index-1]->var.yres))
> + mfbi->y_aoi_d = pmfbi->y_aoi_d +
> + machine_data->fsl_diu_info[index-1]->var.yres;
> + if ((var->yres + mfbi->y_aoi_d) >
> + machine_data->fsl_diu_info[0]->var.yres)
> + var->yres =
> + machine_data->fsl_diu_info[0]->var.yres
> + - mfbi->y_aoi_d;
> + } else { /* AOI0 is close */
> + if ((mfbi->y_aoi_d + var->yres) >
> + machine_data->fsl_diu_info[0]->var.yres)
> + mfbi->y_aoi_d =
> + machine_data->fsl_diu_info[0]->var.yres
> + - var->yres;
> + if (mfbi->y_aoi_d < 0)
> + mfbi->y_aoi_d = 0;
> + if ((var->yres + mfbi->y_aoi_d) >
> + machine_data->fsl_diu_info[0]->var.yres)
> + var->yres =
> + machine_data->fsl_diu_info[0]->var.yres
> + - mfbi->y_aoi_d;
Could you split some of this up into separate functions at lower
indentation levels to make it more readable?
> +#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
> + red = CNVT_TOHW(red, info->var.red.length);
> + green = CNVT_TOHW(green, info->var.green.length);
> + blue = CNVT_TOHW(blue, info->var.blue.length);
> + transp = CNVT_TOHW(transp, info->var.transp.length);
> +#undef CNVT_TOHW
Define a function for this.
> + switch (cmd) {
> + case MFB_SET_PIXFMT:
> + if (!arg)
> + return -EINVAL;
> + if (copy_from_user((void *)&pix_fmt, (void *)arg,
> + sizeof(pix_fmt)))
(void __user *)arg
No cast on &pix_fmt.
> +#if defined(CONFIG_NOT_COHERENT_CACHE)
> + else if (status & INT_VSYNC) {
> + int i;
> + unsigned int *ptr;
> + ptr = coherence_data;
> + for (i = 0; i < 1024*8; i++)
> + *ptr++ = 0;
As I said in an internal review, this is not enough, and it's
inefficient. Read rather than write, and do so only once per cache
line, but the size you access has to be at least 13/8 of the cache size
for an 8-way plru cache.
-Scott
^ permalink raw reply
* Re: [PATCH] ppc: Export empty_zero_page
From: Stephen Rothwell @ 2008-03-25 22:26 UTC (permalink / raw)
To: Theodore Tso; +Cc: linuxppc-dev, Christoph Hellwig
In-Reply-To: <20080325135454.GK30110@mit.edu>
[-- Attachment #1: Type: text/plain, Size: 711 bytes --]
Hi Ted,
On Tue, 25 Mar 2008 09:54:54 -0400 Theodore Tso <tytso@MIT.EDU> wrote:
>
> So I screwed this one up. Mea culpa, mea culpa, mea maxima culpa....
>
> I assume Stephen's already sent this to patch to you guys (I picked it
> up from the linux-next git tree), but just in case he didn't....
Yeah, I already sent it and paulus is probably going to put it in his
2.6.26 tree.
However, have you made any progress on Christoph's suggestion:
"The real fix is that ext4 shouldn't be using ZERO_PAGE(). Please use
the same zeroing helpers all the other filesystems and drivers use."
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Patches added to powerpc.git powerpc-next and master branches
From: Paul Mackerras @ 2008-03-25 22:35 UTC (permalink / raw)
To: linuxppc-dev
I have added the patches listed below to the master and powerpc-next
branches of the powerpc.git repository, and pulled in Linus' current
tree.
Paul.
Manish Ahuja (10):
[POWERPC] pseries: phyp dump: Documentation
[POWERPC] pseries: phyp dump: Reserve and release memory
[POWERPC] pseries: phyp dump: Use sysfs to release reserved mem
[POWERPC] pseries: phyp dump: Register dump area
[POWERPC] pseries: phyp dump: Debugging print routines
[POWERPC] pseries: phyp dump: Invalidate and print dump areas
[POWERPC] pseries: phyp dump: Tracking memory range freed
[POWERPC] pseries: phyp dump: Add Kconfig file option
[POWERPC] pseries: phyp dump: Disable phyp-dump through boot-var
[POWERPC] pseries: phyp dump: Inform kdump when phyp-dump is load=
ed
Marian Balakowicz (1):
[POWERPC] Add 'model: ...' line to common show=5Fcpuinfo()
Nathan Lynch (4):
[POWERPC] maple: Use platform name in define=5Fmachine()
[POWERPC] maple: Kill fixup=5Fmaple=5Fide
[POWERPC] maple: Enable ipr driver in defconfig
[POWERPC] scanlog=5Finit cleanup and minor fixes
Robert P. J. Day (1):
[POWERPC] Move a.out.h to header-y since it doesn't check =5F=5FK=
ERNEL=5F=5F
Roland McGrath (2):
[POWERPC] Don't touch PT=5FDTRACE in exec
[POWERPC] powerpc32: Remove asm-offsets ptrace cruft
S.=C3=87a=C4=9Flar Onur (1):
[POWERPC] arch/powerpc/platforms/iseries/pci.c: Use time=5F* macr=
os
Stephen Rothwell (1):
[POWERPC] Really export empty=5Fzero=5Fpage
Tony Breeds (1):
[POWERPC] Update wait=5Fstate=5Fcycles in the VPA
^ permalink raw reply
* Re: Which Kernel for Ocotea (440GX)?
From: Wolfgang Denk @ 2008-03-25 22:45 UTC (permalink / raw)
To: Wolfgang Wegner; +Cc: linuxppc-dev
In-Reply-To: <20080325220742.GD15725@leila.ping.de>
In message <20080325220742.GD15725@leila.ping.de> you wrote:
>
> I want to get an Ocotea dev board (AMCC 440GX) up and running.
> As I saw from old posts (2004/2005) that this board should be supported,
> I simply fetched a 2.6.24 kernel and - could not find a valid target...
>
> It seems that support for 440gx in the arch/ppc tree was disabled, but
> not yet ported to arch/powerpc.
You can find Ocotea support (still arch/ppc only) in our kenrel
repository - see git://www.denx.de/git/linux-2.6-denx.git
I think if you just followed the links on AMCC's web site they should
have taken you there, too. Please let me know if this didn't work for
some reason.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Einstein argued that there must be simplified explanations of nature,
because God is not capricious or arbitrary. No such faith comforts
the software engineer. - Fred Brooks, Jr.
^ permalink raw reply
* RE: [PATCH 2/3] [POWERPC] Xilinx: of_serial support for Xilinx uart 16550.
From: John Linn @ 2008-03-25 22:48 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <47E7DEF1.9050501@ru.mvista.com>
Thanks for all the input. I'd like to propose a solution hoping to
arrive at consensus.
We can define a "sparse16550" binding that uses reg-shift and reg-offset
properties in the device tree.=20
It seems like this is a common variable on the 16550 so that others
could also use it. I like it because it specifies the differences
clearly from a normal 16550 yet is flexible enough to handle some other
variations also.
Thanks,
John
-----Original Message-----
From: Sergei Shtylyov [mailto:sshtylyov@ru.mvista.com]=20
Sent: Monday, March 24, 2008 11:04 AM
To: Sergei Shtylyov
Cc: Grant Likely; linuxppc-dev@ozlabs.org; Paul Mackerras; John Linn
Subject: Re: [PATCH 2/3] [POWERPC] Xilinx: of_serial support for Xilinx
uart 16550.
Hi, I wrote:
> Oh, well... unfortunately, we can't use UPIO_MEM32 "register model"
> in 8250.c anyway since that makes use of readl()/writel() -- which
treat=20
> the bus as bigendian on PPC... anyway, we would need at least a=20
I was going to write "as little-endian"... :-<
> "reg-size" property, if not new "compatible"...
WBR, Sergei
^ permalink raw reply
* Re: [PATCH] ppc: Export empty_zero_page
From: Theodore Tso @ 2008-03-25 22:49 UTC (permalink / raw)
To: Stephen Rothwell; +Cc: linuxppc-dev, Christoph Hellwig
In-Reply-To: <20080326092657.8b65e5ea.sfr@canb.auug.org.au>
[-- Attachment #1: Type: text/plain, Size: 404 bytes --]
On Wed, Mar 26, 2008 at 09:26:57AM +1100, Stephen Rothwell wrote:
> However, have you made any progress on Christoph's suggestion:
>
> "The real fix is that ext4 shouldn't be using ZERO_PAGE(). Please use
> the same zeroing helpers all the other filesystems and drivers use."
When Aneesh asked for clarification about Christoph's suggestion, he
got the following response (see attached).
- Ted
[-- Attachment #2: Type: message/rfc822, Size: 1394 bytes --]
From: Christoph Hellwig <hch@infradead.org>
To: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Cc: Christoph Hellwig <hch@infradead.org>
Subject: Re: ZERO_PAGE(0) usage in ext4
Date: Thu, 20 Mar 2008 04:35:12 -0400
Message-ID: <20080320083512.GB27854@infradead.org>
On Mon, Mar 17, 2008 at 11:22:30PM +0530, Aneesh Kumar K.V wrote:
> Hi Christoph,
>
> I have changes pending for ext4 which uses ZERO_PAGE(0) to zero out
> file system blocks.
>
> http://repo.or.cz/w/ext4-patch-queue.git?a=blob;f=ext4-fallocate-full-fs-ENOSPC-handling.patch;h=e14ec2a53f008c3f4b80544a897165de4bb5d360;hb=HEAD
>
> The changes are needed to make sure we allow writing to prealloc space
> even when there are no space left in the file system to insert new
> extent details. To use ZERO_PAGE in ext4 i would need patches to export
> some of the variables. I found that you answered Ted's patch at
>
> http://ozlabs.org/pipermail/linuxppc-dev/2008-March/052956.html
>
> I have a patch that does the same thing for multiple arch. Can you help
> me understand what you meant by zeroing helpers ?
Ok, you're actually sending down the page and not copying from it.
This is probab;y okay.
^ permalink raw reply
* Re: dtc: Simplify error handling for unparseable input
From: David Gibson @ 2008-03-25 23:52 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <47E9783F.4@freescale.com>
On Tue, Mar 25, 2008 at 05:10:07PM -0500, Scott Wood wrote:
> David Gibson wrote:
>> On Tue, Mar 25, 2008 at 09:36:19AM -0500, Scott Wood wrote:
>>> On Tue, Mar 25, 2008 at 12:28:05PM +1100, David Gibson wrote:
>>>> On Mon, Mar 24, 2008 at 12:36:41PM -0500, Scott Wood wrote:
>>>>> If you remove this, there'll be no way to indicate semantic errors
>>>>> other
>>>>> than die() (the NULL approaches are no good, since they inhibit
>>>>> recovery),
>>>>> which is suboptimal if the error is not immediately fatal.
>>>> But everything is immediately fatal. When we have a *real* example of
>>>> something that's not, we can restore an error code.
>>> Failed binary includes are not immediately fatal.
>> And is there any advantage to having them not immediately fatal?
>
> It's generally nice to the user if you can report as many bugs as you can
> rather than fail on the first one.
Hrm, I guess. There's only so far it's worth going to achieve that
though.
> It's also nice to someone down the road trying to turn this code into a
> library if it passes return status up the call chain gracefully.
Can you think of any reason we'd want to do that? And that would
require fixing so many other places that the two cases which do return
an error (that's including binary includes) hardly signify.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: dtc: Simplify error handling for unparseable input
From: David Gibson @ 2008-03-25 23:59 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <47E9783F.4@freescale.com>
On Tue, Mar 25, 2008 at 05:10:07PM -0500, Scott Wood wrote:
> David Gibson wrote:
>> On Tue, Mar 25, 2008 at 09:36:19AM -0500, Scott Wood wrote:
>>> On Tue, Mar 25, 2008 at 12:28:05PM +1100, David Gibson wrote:
>>>> On Mon, Mar 24, 2008 at 12:36:41PM -0500, Scott Wood wrote:
>>>>> If you remove this, there'll be no way to indicate semantic errors
>>>>> other
>>>>> than die() (the NULL approaches are no good, since they inhibit
>>>>> recovery),
>>>>> which is suboptimal if the error is not immediately fatal.
>>>> But everything is immediately fatal. When we have a *real* example of
>>>> something that's not, we can restore an error code.
>>> Failed binary includes are not immediately fatal.
>> And is there any advantage to having them not immediately fatal?
>
> It's generally nice to the user if you can report as many bugs as you can
> rather than fail on the first one.
Oh.. and this patch doesn't actually preclude that. We still have the
treesource_error variable and can report errors that way during the
parse. The die() just comes at the end of dt_from_source(), instead
of in main().
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [PATCHv4 2.6.25] i2c: adds support for i2c bus on Freescale CPM1/CPM2 controllers
From: Stephen Rothwell @ 2008-03-26 0:41 UTC (permalink / raw)
To: Jochen Friedrich
Cc: Jean Delvare, linuxppc-dev list, linux-kernel, Scott Wood, i2c
In-Reply-To: <47E94891.6020000@scram.de>
[-- Attachment #1: Type: text/plain, Size: 1948 bytes --]
Hi Jochen,
Firstly, you should probably cc Dave Miller <davem@davemloft.net> on
anything in drivers/of as Sparc is the other user of this stuff (just in
case they are interested).
On Tue, 25 Mar 2008 19:46:41 +0100 Jochen Friedrich <jochen@scram.de> wrote:
>
> +++ b/drivers/of/i2c.c
> @@ -0,0 +1,113 @@
> +/*
> + * OF helpers for the I2C API
> + *
> + * Copyright (c) 2008 Jochen Friedrich <jochen@scram.de>
> + *
> + * Based on a previous patch from Jon Smirl <jonsmirl@gmail.com>
> + *
> + * 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.
> + */
> +
> +#include <linux/i2c.h>
> +#include <asm/prom.h>
You should really include <linux/of.h> instead.
> +struct i2c_driver_device {
> + char *of_device;
> + char *i2c_type;
> +};
> +
> +static struct i2c_driver_device i2c_devices[] = {
> + {"dallas,ds1374", "rtc-ds1374",},
^
You don't need the comma before the brace (unless you are anticipating
that struct i2c_driver_device will change. Even then, its not a big
thing.
> +void of_register_i2c_devices(struct i2c_adapter *adap,
> + struct device_node *adap_node)
> +{
> + void *result;
> + struct device_node *node = NULL;
> +
> + while ((node = of_get_next_child(adap_node, node))) {
for_each_child_of_node(adap_node, node) {
And then you don't need to initialise "node" above.
> + info.irq = irq_of_parse_and_map(node, 0);
> + if (info.irq == NO_IRQ)
> + info.irq = -1;
> +
> + if (of_find_i2c_driver(node, &info) < 0)
> + continue;
Do you need to clean up after the irq_of_parse_and_map() above?
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: Patches added to powerpc.git powerpc-next and master branches
From: Josh Boyer @ 2008-03-26 0:54 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <18409.32313.610943.187982@cargo.ozlabs.ibm.com>
On Wed, 2008-03-26 at 09:35 +1100, Paul Mackerras wrote:
> I have added the patches listed below to the master and powerpc-next
> branches of the powerpc.git repository, and pulled in Linus' current
> tree.
I have some patches floating around that I'll be gathering together in
my tree tomorrow. I'll send a pull request then.
josh
^ permalink raw reply
* Re: dtc: Simplify error handling for unparseable input
From: Scott Wood @ 2008-03-26 1:16 UTC (permalink / raw)
To: Jon Loeliger, linuxppc-dev
In-Reply-To: <20080325235202.GG8281@localhost.localdomain>
On Wed, Mar 26, 2008 at 10:52:02AM +1100, David Gibson wrote:
> On Tue, Mar 25, 2008 at 05:10:07PM -0500, Scott Wood wrote:
> > It's generally nice to the user if you can report as many bugs as you can
> > rather than fail on the first one.
>
> Hrm, I guess. There's only so far it's worth going to achieve that
> though.
>
> > It's also nice to someone down the road trying to turn this code into a
> > library if it passes return status up the call chain gracefully.
>
> Can you think of any reason we'd want to do that?
Anything that wants to do something automated with device tree source
that doesn't fit neatly into command-line execution. Nothing specific.
> And that would require fixing so many other places that the two cases
> which do return an error (that's including binary includes) hardly
> signify.
Yeah, I just wanted to avoid going further down that path if possible.
I won't protest too loudly if the general consensus is to just die(),
though.
-Scott
^ permalink raw reply
* [PATCH 0/2] Two more pasemi_mac patches for 2.6.26
From: Olof Johansson @ 2008-03-26 1:56 UTC (permalink / raw)
To: jgarzik; +Cc: linuxppc-dev, pasemi-linux, netdev
Hi Jeff,
The below two patches go on top of the previous patches that were acked
by you but applied to pasemi.git for feed up through powerpc.git.
One is a couple of fixes for various corner cases in the jumbo support
configuration. The second is addition of netpoll support, from Nate
Case.
Review/ack would be appreciated, I'll feed them up the same path as the
other changes.
-Olof
^ permalink raw reply
* [PATCH 1/2] pasemi_mac: Jumbo frame bugfixes
From: Olof Johansson @ 2008-03-26 1:57 UTC (permalink / raw)
To: jgarzik; +Cc: linuxppc-dev, pasemi-linux, netdev
In-Reply-To: <20080326015625.GA23103@lixom.net>
Fix a couple of corner cases around interface up/down when jumbo frames are
configured. Resources weren't always freed and reallocated properly.
Signed-off-by: Olof Johansson <olof@lixom.net>
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index c50f0f4..abb1dc4 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -404,6 +404,7 @@ static void pasemi_mac_free_csring(struct pasemi_mac_csring *csring)
pasemi_dma_free_flag(csring->events[1]);
pasemi_dma_free_ring(&csring->chan);
pasemi_dma_free_chan(&csring->chan);
+ pasemi_dma_free_fun(csring->fun);
}
static int pasemi_mac_setup_rx_resources(const struct net_device *dev)
@@ -1150,7 +1151,10 @@ static int pasemi_mac_open(struct net_device *dev)
if (!mac->tx)
goto out_tx_ring;
- if (dev->mtu > 1500) {
+ /* We might already have allocated rings in case mtu was changed
+ * before interface was brought up.
+ */
+ if (dev->mtu > 1500 && !mac->num_cs) {
pasemi_mac_setup_csrings(mac);
if (!mac->num_cs)
goto out_tx_ring;
@@ -1388,8 +1392,12 @@ static int pasemi_mac_close(struct net_device *dev)
free_irq(mac->tx->chan.irq, mac->tx);
free_irq(mac->rx->chan.irq, mac->rx);
- for (i = 0; i < mac->num_cs; i++)
+ for (i = 0; i < mac->num_cs; i++) {
pasemi_mac_free_csring(mac->cs[i]);
+ mac->cs[i] = NULL;
+ }
+
+ mac->num_cs = 0;
/* Free resources */
pasemi_mac_free_rx_resources(mac);
^ permalink raw reply related
* [PATCH 2/2] pasemi_mac: Netpoll support
From: Olof Johansson @ 2008-03-26 1:58 UTC (permalink / raw)
To: jgarzik; +Cc: linuxppc-dev, pasemi-linux, netdev
In-Reply-To: <20080326015625.GA23103@lixom.net>
Add netpoll support to allow use of netconsole.
Signed-off-by: Nate Case <ncase@xes-inc.com>
Signed-off-by: Olof Johansson <olof@lixom.net>
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index abb1dc4..6030ffe 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -1648,6 +1648,26 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget)
return pkts;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void pasemi_mac_netpoll(struct net_device *dev)
+{
+ const struct pasemi_mac *mac = netdev_priv(dev);
+
+ disable_irq(mac->tx->chan.irq);
+ pasemi_mac_tx_intr(mac->tx->chan.irq, mac->tx);
+ enable_irq(mac->tx->chan.irq);
+
+ disable_irq(mac->rx->chan.irq);
+ pasemi_mac_rx_intr(mac->rx->chan.irq, dev);
+ enable_irq(mac->rx->chan.irq);
+}
+#endif
+
static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu)
{
struct pasemi_mac *mac = netdev_priv(dev);
@@ -1807,6 +1827,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->mtu = PE_DEF_MTU;
/* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = pasemi_mac_netpoll;
+#endif
dev->change_mtu = pasemi_mac_change_mtu;
dev->ethtool_ops = &pasemi_mac_ethtool_ops;
^ permalink raw reply related
* Re: interrupt handlers PowerPC via GCC
From: David H. Lynch Jr. @ 2008-03-26 2:50 UTC (permalink / raw)
To: Tehn Yit Chin; +Cc: linuxppc-embedded
In-Reply-To: <bf04f99c0803241603v3151865eic80b58a04bce43e2@mail.gmail.com>
Tehn Yit Chin wrote:
> Hey Scott,
>
> Thanks for the reply, I shall investigate further.
>
> I wasn't talking about interrupt handlers in Linux as such, but using
> powerpc-eabi-gcc to write an ISR for the MPC5516. (I guess that could be
> off-topic on this mailing list, but I thought the folks on this mailing list
> would probably know the answer pretty easily). I was hoping that gcc would
> generate the prologue and epilogue code for me via the interrupt attributes.
I know nothing about GCC's interrupt attributes,
however, there is no problem writing ISR's from scratch (no OS)
for the ppc. There are several boot loaders, monitors etc. out there
with examples.
There is even one inside the Linux Kernel source - though it i
probably far more complex than you need.
Somewhere I have something for the ppc405 I can send you - but most
ppc's are similar.
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 dhlii@dlasys.net http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
^ permalink raw reply
* Re: [PATCH] ehea: Fix IPv6 support
From: Jeff Garzik @ 2008-03-26 3:20 UTC (permalink / raw)
To: Thomas Klein
Cc: Jan-Bernd Themann, netdev, Hannes Hering, linux-kernel, linux-ppc,
Christoph Raisch, Stefan Roscher
In-Reply-To: <200803191355.44266.osstklei@de.ibm.com>
Thomas Klein wrote:
> Indicate that HEA calculates IPv4 checksums only
>
> Signed-off-by: Thomas Klein <tklein@de.ibm.com>
>
> ---
> diff -Nurp -X dontdiff linux-2.6.25-rc6/drivers/net/ehea/ehea.h patched_kernel/drivers/net/ehea/ehea.h
> --- linux-2.6.25-rc6/drivers/net/ehea/ehea.h 2008-03-17 00:32:14.000000000 +0100
> +++ patched_kernel/drivers/net/ehea/ehea.h 2008-03-19 08:58:07.000000000 +0100
> @@ -40,7 +40,7 @@
> #include <asm/io.h>
>
> #define DRV_NAME "ehea"
> -#define DRV_VERSION "EHEA_0087"
> +#define DRV_VERSION "EHEA_0089"
>
> /* eHEA capability flags */
> #define DLPAR_PORT_ADD_REM 1
> diff -Nurp -X dontdiff linux-2.6.25-rc6/drivers/net/ehea/ehea_main.c patched_kernel/drivers/net/ehea/ehea_main.c
> --- linux-2.6.25-rc6/drivers/net/ehea/ehea_main.c 2008-03-17 00:32:14.000000000 +0100
> +++ patched_kernel/drivers/net/ehea/ehea_main.c 2008-03-19 08:58:07.000000000 +0100
> @@ -3108,7 +3108,7 @@ struct ehea_port *ehea_setup_single_port
> dev->vlan_rx_add_vid = ehea_vlan_rx_add_vid;
> dev->vlan_rx_kill_vid = ehea_vlan_rx_kill_vid;
> dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
> - | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX
> + | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
> | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
applied
^ permalink raw reply
* Re: [PATCH 0/2] Two more pasemi_mac patches for 2.6.26
From: Jeff Garzik @ 2008-03-26 4:12 UTC (permalink / raw)
To: Olof Johansson; +Cc: linuxppc-dev, pasemi-linux, netdev
In-Reply-To: <20080326015625.GA23103@lixom.net>
Olof Johansson wrote:
> Hi Jeff,
>
> The below two patches go on top of the previous patches that were acked
> by you but applied to pasemi.git for feed up through powerpc.git.
>
> One is a couple of fixes for various corner cases in the jumbo support
> configuration. The second is addition of netpoll support, from Nate
> Case.
>
> Review/ack would be appreciated, I'll feed them up the same path as the
> other changes.
ACK 1-2, though I would consider closely patch #2, whether you need
disable_irq() or spin_lock_irqsave() -- which is best for your specific
driver + platform?
^ permalink raw reply
* dtc: Make dt_from_blob() open its own input file, like the other input formats
From: David Gibson @ 2008-03-26 5:16 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev
Currently, main() has a variable for the input file. It used to be
that main() would open the input based on command line arguments
before passing it to the dt_from_*() function. However, only
dt_from_blob() uses this. dt_from_source() opens its own file, and
dt_from_fs() interprets the argument as as a directory and does its
own opendir() call.
Furthermore, main() opened the file with dtc_open_file() but closed it
with a direct call to fclose().
Therefore, to improve the interface consistency between the
dt_from_*() functions, make dt_from_blob() open and close its own
files like the other dt_from_*() functions.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
dtc.c | 16 +++++-----------
dtc.h | 2 +-
flattree.c | 26 ++++++++++++++++----------
3 files changed, 22 insertions(+), 22 deletions(-)
Index: dtc/dtc.c
===================================================================
--- dtc.orig/dtc.c 2008-03-26 16:08:22.000000000 +1100
+++ dtc/dtc.c 2008-03-26 16:08:37.000000000 +1100
@@ -118,7 +118,6 @@
int force = 0, check = 0;
const char *arg;
int opt;
- struct dtc_file *inf = NULL;
FILE *outf = NULL;
int outversion = DEFAULT_FDT_VERSION;
int boot_cpuid_phys = 0xfeedbeef;
@@ -187,19 +186,14 @@
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg);
- if (streq(inform, "dts")) {
+ if (streq(inform, "dts"))
bi = dt_from_source(arg);
- } else if (streq(inform, "fs")) {
+ else if (streq(inform, "fs"))
bi = dt_from_fs(arg);
- } else if(streq(inform, "dtb")) {
- inf = dtc_open_file(arg, NULL);
- bi = dt_from_blob(inf->file);
- } else {
+ else if(streq(inform, "dtb"))
+ bi = dt_from_blob(arg);
+ else
die("Unknown input format \"%s\"\n", inform);
- }
-
- if (inf && inf->file != stdin)
- fclose(inf->file);
fill_fullpaths(bi->dt, "");
process_checks(force, bi);
Index: dtc/dtc.h
===================================================================
--- dtc.orig/dtc.h 2008-03-26 16:08:22.000000000 +1100
+++ dtc/dtc.h 2008-03-26 16:08:37.000000000 +1100
@@ -248,7 +248,7 @@
void dt_to_asm(FILE *f, struct boot_info *bi, int version,
int boot_cpuid_phys);
-struct boot_info *dt_from_blob(FILE *f);
+struct boot_info *dt_from_blob(const char *fname);
/* Tree source */
Index: dtc/flattree.c
===================================================================
--- dtc.orig/flattree.c 2008-03-26 16:08:22.000000000 +1100
+++ dtc/flattree.c 2008-03-26 16:08:37.000000000 +1100
@@ -19,6 +19,7 @@
*/
#include "dtc.h"
+#include "srcpos.h"
#define FTF_FULLPATH 0x1
#define FTF_VARALIGN 0x2
@@ -780,8 +781,9 @@
}
-struct boot_info *dt_from_blob(FILE *f)
+struct boot_info *dt_from_blob(const char *fname)
{
+ struct dtc_file *dtcf;
u32 magic, totalsize, version, size_dt;
u32 off_dt, off_str, off_mem_rsvmap;
int rc;
@@ -796,12 +798,14 @@
u32 val;
int flags = 0;
- rc = fread(&magic, sizeof(magic), 1, f);
- if (ferror(f))
+ dtcf = dtc_open_file(fname, NULL);
+
+ rc = fread(&magic, sizeof(magic), 1, dtcf->file);
+ if (ferror(dtcf->file))
die("Error reading DT blob magic number: %s\n",
strerror(errno));
if (rc < 1) {
- if (feof(f))
+ if (feof(dtcf->file))
die("EOF reading DT blob magic number\n");
else
die("Mysterious short read reading magic number\n");
@@ -811,11 +815,11 @@
if (magic != FDT_MAGIC)
die("Blob has incorrect magic number\n");
- rc = fread(&totalsize, sizeof(totalsize), 1, f);
- if (ferror(f))
+ rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file);
+ if (ferror(dtcf->file))
die("Error reading DT blob size: %s\n", strerror(errno));
if (rc < 1) {
- if (feof(f))
+ if (feof(dtcf->file))
die("EOF reading DT blob size\n");
else
die("Mysterious short read reading blob size\n");
@@ -835,12 +839,12 @@
p = blob + sizeof(magic) + sizeof(totalsize);
while (sizeleft) {
- if (feof(f))
+ if (feof(dtcf->file))
die("EOF before reading %d bytes of DT blob\n",
totalsize);
- rc = fread(p, 1, sizeleft, f);
- if (ferror(f))
+ rc = fread(p, 1, sizeleft, dtcf->file);
+ if (ferror(dtcf->file))
die("Error reading DT blob: %s\n",
strerror(errno));
@@ -902,5 +906,7 @@
free(blob);
+ dtc_close_file(dtcf);
+
return build_boot_info(reservelist, tree);
}
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* dtc: Trivial formatting fixes
From: David Gibson @ 2008-03-26 5:21 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev
This patch fixes some trivial indentation and brace/bracket style
problems.
---
dtc.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
Index: dtc/dtc.c
===================================================================
--- dtc.orig/dtc.c 2008-03-26 16:18:51.000000000 +1100
+++ dtc/dtc.c 2008-03-26 16:19:12.000000000 +1100
@@ -163,8 +163,8 @@
boot_cpuid_phys = strtol(optarg, NULL, 0);
break;
case 'v':
- printf("Version: %s\n", DTC_VERSION);
- exit(0);
+ printf("Version: %s\n", DTC_VERSION);
+ exit(0);
case 'h':
default:
usage();
@@ -179,9 +179,8 @@
arg = argv[optind];
/* minsize and padsize are mutually exclusive */
- if ((minsize) && (padsize)) {
+ if (minsize && padsize)
die("Can't set both -p and -S\n");
- }
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg);
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox