From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
To: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: linux-mips@linux-mips.org, linux-fbdev@vger.kernel.org,
ralf@linux-mips.org
Subject: Re: [PATCH v2] GIO bus support for SGI IP22/28
Date: Sun, 30 Oct 2011 15:53:25 +0000 [thread overview]
Message-ID: <4EAD72F5.9010800@gmx.de> (raw)
In-Reply-To: <20111020221928.0C2191DA27@solo.franken.de>
On 10/20/2011 10:19 PM, Thomas Bogendoerfer wrote:
> SGI IP22/IP28 machines have GIO busses for adding graphics and other
> extension cards. This patch adds support for GIO driver/device
> handling and converts the newport console driver to a GIO driver.
>
> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> ---
>
> Changes to last version:
> - use EXPORT_SYMBOL_GPL
> - ChallengeS has only 2 slots
> - use subsys_initcall for gio detection
>
> Florian, the whole patch should go through the MIPS tree, if it's ok for
> you.
No problem. I'm not even sure whether I'm responsible for it as it is not a
framebuffer but a console driver. Anyway I had a look at the console code so you
may add an
Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
if you like.
Best regards,
Florian Tobias Schandinat
> arch/mips/include/asm/gio_device.h | 56 +++++
> arch/mips/sgi-ip22/Makefile | 2 +-
> arch/mips/sgi-ip22/ip22-gio.c | 414 +++++++++++++++++++++++++++++++++++
> arch/mips/sgi-ip22/ip22-mc.c | 10 +-
> arch/mips/sgi-ip22/ip22-setup.c | 21 --
> drivers/video/console/newport_con.c | 61 ++++--
> 6 files changed, 518 insertions(+), 46 deletions(-)
>
> diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h
> new file mode 100644
> index 0000000..5437c84
> --- /dev/null
> +++ b/arch/mips/include/asm/gio_device.h
> @@ -0,0 +1,56 @@
> +#include <linux/device.h>
> +#include <linux/mod_devicetable.h>
> +
> +struct gio_device_id {
> + __u8 id;
> +};
> +
> +struct gio_device {
> + struct device dev;
> + struct resource resource;
> + unsigned int irq;
> + unsigned int slotno;
> +
> + const char *name;
> + struct gio_device_id id;
> + unsigned id32:1;
> + unsigned gio64:1;
> +};
> +#define to_gio_device(d) container_of(d, struct gio_device, dev)
> +
> +struct gio_driver {
> + const char *name;
> + struct module *owner;
> + const struct gio_device_id *id_table;
> +
> + int (*probe)(struct gio_device *, const struct gio_device_id *);
> + void (*remove)(struct gio_device *);
> + int (*suspend)(struct gio_device *, pm_message_t);
> + int (*resume)(struct gio_device *);
> + void (*shutdown)(struct gio_device *);
> +
> + struct device_driver driver;
> +};
> +#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
> +
> +extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
> + const struct gio_device *);
> +extern struct gio_device *gio_dev_get(struct gio_device *);
> +extern void gio_dev_put(struct gio_device *);
> +
> +extern int gio_device_register(struct gio_device *);
> +extern void gio_device_unregister(struct gio_device *);
> +extern void gio_release_dev(struct device *);
> +
> +static inline void gio_device_free(struct gio_device *dev)
> +{
> + gio_release_dev(&dev->dev);
> +}
> +
> +extern int gio_register_driver(struct gio_driver *);
> +extern void gio_unregister_driver(struct gio_driver *);
> +
> +#define gio_get_drvdata(_dev) drv_get_drvdata(&(_dev)->dev)
> +#define gio_set_drvdata(_dev, data) drv_set_drvdata(&(_dev)->dev, (data))
> +
> +extern void gio_set_master(struct gio_device *);
> diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
> index cc53849..411cda9 100644
> --- a/arch/mips/sgi-ip22/Makefile
> +++ b/arch/mips/sgi-ip22/Makefile
> @@ -4,7 +4,7 @@
> #
>
> obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
> - ip22-platform.o ip22-reset.o ip22-setup.o
> + ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
>
> obj-$(CONFIG_SGI_IP22) += ip22-berr.o
> obj-$(CONFIG_SGI_IP28) += ip28-berr.o
> diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
> new file mode 100644
> index 0000000..d841529
> --- /dev/null
> +++ b/arch/mips/sgi-ip22/ip22-gio.c
> @@ -0,0 +1,414 @@
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +
> +#include <asm/addrspace.h>
> +#include <asm/paccess.h>
> +#include <asm/gio_device.h>
> +#include <asm/sgi/gio.h>
> +#include <asm/sgi/hpc3.h>
> +#include <asm/sgi/mc.h>
> +#include <asm/sgi/ip22.h>
> +
> +static struct bus_type gio_bus;
> +
> +static struct {
> + const char *name;
> + __u8 id;
> +} gio_name_table[] = {
> + { .name = "SGI Impact", .id = 0x10 },
> + { .name = "Phobos G160", .id = 0x35 },
> + /* fake IDs */
> + { .name = "SGI Newport", .id = 0x7e },
> + { .name = "SGI GR2/GR3", .id = 0x7f },
> +};
> +
> +/**
> + * gio_match_device - Tell if an of_device structure has a matching
> + * gio_match structure
> + * @ids: array of of device match structures to search in
> + * @dev: the of device structure to match against
> + *
> + * Used by a driver to check whether an of_device present in the
> + * system is in its list of supported devices.
> + */
> +const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
> + const struct gio_device *dev)
> +{
> + const struct gio_device_id *ids;
> +
> + for (ids = match; ids->id != 0xff; ids++)
> + if (ids->id = dev->id.id)
> + return ids;
> +
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(gio_match_device);
> +
> +struct gio_device *gio_dev_get(struct gio_device *dev)
> +{
> + struct device *tmp;
> +
> + if (!dev)
> + return NULL;
> + tmp = get_device(&dev->dev);
> + if (tmp)
> + return to_gio_device(tmp);
> + else
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(gio_dev_get);
> +
> +void gio_dev_put(struct gio_device *dev)
> +{
> + if (dev)
> + put_device(&dev->dev);
> +}
> +EXPORT_SYMBOL_GPL(gio_dev_put);
> +
> +static ssize_t dev_show_name(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct gio_device *giodev;
> +
> + giodev = to_gio_device(dev);
> + return sprintf(buf, "%s", giodev->name);
> +}
> +
> +static DEVICE_ATTR(name, S_IRUGO, dev_show_name, NULL);
> +
> +static ssize_t dev_show_id(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct gio_device *giodev;
> +
> + giodev = to_gio_device(dev);
> + return sprintf(buf, "%x", giodev->id.id);
> +}
> +
> +static DEVICE_ATTR(id, S_IRUGO, dev_show_id, NULL);
> +
> +/**
> + * gio_release_dev - free an gio device structure when all users of it are finished.
> + * @dev: device that's been disconnected
> + *
> + * Will be called only by the device core when all users of this gio device are
> + * done.
> + */
> +void gio_release_dev(struct device *dev)
> +{
> + struct gio_device *giodev;
> +
> + giodev = to_gio_device(dev);
> + kfree(giodev);
> +}
> +EXPORT_SYMBOL_GPL(gio_release_dev);
> +
> +int gio_device_register(struct gio_device *giodev)
> +{
> + int rc;
> +
> + giodev->dev.bus = &gio_bus;
> + rc = device_register(&giodev->dev);
> + if (rc)
> + return rc;
> +
> + rc = device_create_file(&giodev->dev, &dev_attr_name);
> + if (rc)
> + goto err;
> + rc = device_create_file(&giodev->dev, &dev_attr_id);
> + if (rc)
> + goto err;
> +
> + return 0;
> +
> +err:
> + device_unregister(&giodev->dev);
> + return rc;
> +}
> +EXPORT_SYMBOL_GPL(gio_device_register);
> +
> +void gio_device_unregister(struct gio_device *giodev)
> +{
> + device_remove_file(&giodev->dev, &dev_attr_id);
> + device_remove_file(&giodev->dev, &dev_attr_name);
> + device_unregister(&giodev->dev);
> +}
> +EXPORT_SYMBOL_GPL(gio_device_unregister);
> +
> +static int gio_bus_match(struct device *dev, struct device_driver *drv)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *gio_drv = to_gio_driver(drv);
> +
> + return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
> +}
> +
> +static int gio_device_probe(struct device *dev)
> +{
> + int error = -ENODEV;
> + struct gio_driver *drv;
> + struct gio_device *gio_dev;
> + const struct gio_device_id *match;
> +
> + drv = to_gio_driver(dev->driver);
> + gio_dev = to_gio_device(dev);
> +
> + if (!drv->probe)
> + return error;
> +
> + gio_dev_get(gio_dev);
> +
> + match = gio_match_device(drv->id_table, gio_dev);
> + if (match)
> + error = drv->probe(gio_dev, match);
> + if (error)
> + gio_dev_put(gio_dev);
> +
> + return error;
> +}
> +
> +static int gio_device_remove(struct device *dev)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *drv = to_gio_driver(dev->driver);
> +
> + if (dev->driver && drv->remove)
> + drv->remove(gio_dev);
> + return 0;
> +}
> +
> +static int gio_device_suspend(struct device *dev, pm_message_t state)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *drv = to_gio_driver(dev->driver);
> + int error = 0;
> +
> + if (dev->driver && drv->suspend)
> + error = drv->suspend(gio_dev, state);
> + return error;
> +}
> +
> +static int gio_device_resume(struct device *dev)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *drv = to_gio_driver(dev->driver);
> + int error = 0;
> +
> + if (dev->driver && drv->resume)
> + error = drv->resume(gio_dev);
> + return error;
> +}
> +
> +static void gio_device_shutdown(struct device *dev)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *drv = to_gio_driver(dev->driver);
> +
> + if (dev->driver && drv->shutdown)
> + drv->shutdown(gio_dev);
> +}
> +
> +int gio_register_driver(struct gio_driver *drv)
> +{
> + /* initialize common driver fields */
> + if (!drv->driver.name)
> + drv->driver.name = drv->name;
> + if (!drv->driver.owner)
> + drv->driver.owner = drv->owner;
> + drv->driver.bus = &gio_bus;
> +
> + /* register with core */
> + return driver_register(&drv->driver);
> +}
> +EXPORT_SYMBOL_GPL(gio_register_driver);
> +
> +void gio_unregister_driver(struct gio_driver *drv)
> +{
> + driver_unregister(&drv->driver);
> +}
> +EXPORT_SYMBOL_GPL(gio_unregister_driver);
> +
> +void gio_set_master(struct gio_device *dev)
> +{
> + u32 tmp = sgimc->giopar;
> +
> + switch (dev->slotno) {
> + case 0:
> + tmp |= SGIMC_GIOPAR_MASTERGFX;
> + break;
> + case 1:
> + tmp |= SGIMC_GIOPAR_MASTEREXP0;
> + break;
> + case 2:
> + tmp |= SGIMC_GIOPAR_MASTEREXP1;
> + break;
> + }
> + sgimc->giopar = tmp;
> +}
> +EXPORT_SYMBOL_GPL(gio_set_master);
> +
> +void ip22_gio_set_64bit(int slotno)
> +{
> + u32 tmp = sgimc->giopar;
> +
> + switch (slotno) {
> + case 0:
> + tmp |= SGIMC_GIOPAR_GFX64;
> + break;
> + case 1:
> + tmp |= SGIMC_GIOPAR_EXP064;
> + break;
> + case 2:
> + tmp |= SGIMC_GIOPAR_EXP164;
> + break;
> + }
> + sgimc->giopar = tmp;
> +}
> +
> +static int ip22_gio_id(unsigned long addr, u32 *res)
> +{
> + u8 tmp8;
> + u8 tmp16;
> + u32 tmp32;
> + u8 *ptr8;
> + u16 *ptr16;
> + u32 *ptr32;
> +
> + ptr32 = (void *)CKSEG1ADDR(addr);
> + if (!get_dbe(tmp32, ptr32)) {
> + /*
> + * We got no DBE, but this doesn't mean anything.
> + * If GIO is pipelined (which can't be disabled
> + * for GFX slot) we don't get a DBE, but we see
> + * the transfer size as data. So we do an 8bit
> + * and a 16bit access and check whether the common
> + * data matches
> + */
> + ptr8 = (void *)CKSEG1ADDR(addr + 3);
> + get_dbe(tmp8, ptr8);
> + ptr16 = (void *)CKSEG1ADDR(addr + 2);
> + get_dbe(tmp16, ptr16);
> + if (tmp8 = (tmp16 & 0xff) &&
> + tmp8 = (tmp32 & 0xff) &&
> + tmp16 = (tmp32 & 0xffff)) {
> + *res = tmp32;
> + return 1;
> + }
> + }
> + return 0; /* nothing here */
> +}
> +
> +#define HQ2_MYSTERY_OFFS 0x6A07C
> +#define NEWPORT_USTATUS_OFFS 0xF133C
> +
> +static int ip22_is_gr2(unsigned long addr)
> +{
> + u32 tmp;
> + u32 *ptr;
> +
> + /* HQ2 only allows 32bit accesses */
> + ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
> + if (!get_dbe(tmp, ptr)) {
> + if (tmp = 0xdeadbeef)
> + return 1;
> + }
> + return 0;
> +}
> +
> +
> +static void ip22_check_gio(int slotno, unsigned long addr)
> +{
> + const char *name = "Unknown";
> + struct gio_device *gio_dev;
> + u32 tmp;
> + __u8 id;
> + int i;
> +
> + /* first look for GR2/GR3 by checking mystery register */
> + if (ip22_is_gr2(addr))
> + tmp = 0x7f;
> + else {
> + if (!ip22_gio_id(addr, &tmp)) {
> + /*
> + * no GIO signature at start address of slot, but
> + * Newport doesn't have one, so let's check usea
> + * status register
> + */
> + if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
> + tmp = 0x7e;
> + else
> + tmp = 0;
> + }
> + }
> + if (tmp) {
> + id = GIO_ID(tmp);
> + if (tmp & GIO_32BIT_ID) {
> + if (tmp & GIO_64BIT_IFACE)
> + ip22_gio_set_64bit(slotno);
> + }
> + for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
> + if (id = gio_name_table[i].id) {
> + name = gio_name_table[i].name;
> + break;
> + }
> + }
> + printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
> + slotno, name, id);
> + gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
> + gio_dev->name = name;
> + gio_dev->slotno = slotno;
> + gio_dev->id.id = id;
> + gio_dev->resource.start = addr;
> + gio_dev->resource.end = addr + 0x3fffff;
> + gio_dev->resource.flags = IORESOURCE_MEM;
> + dev_set_name(&gio_dev->dev, "gio%d", slotno);
> + gio_device_register(gio_dev);
> + } else
> + printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
> +}
> +
> +static struct bus_type gio_bus = {
> + .name = "gio",
> + .match = gio_bus_match,
> + .probe = gio_device_probe,
> + .remove = gio_device_remove,
> + .suspend = gio_device_suspend,
> + .resume = gio_device_resume,
> + .shutdown = gio_device_shutdown,
> +};
> +
> +static struct resource gio_bus_resource = {
> + .start = GIO_SLOT_GFX_BASE,
> + .end = GIO_SLOT_GFX_BASE + 0x9fffff,
> + .name = "GIO Bus",
> + .flags = IORESOURCE_MEM,
> +};
> +
> +int __init ip22_gio_init(void)
> +{
> + unsigned int pbdma __maybe_unused;
> + int ret;
> +
> + ret = bus_register(&gio_bus);
> + if (!ret) {
> + request_resource(&iomem_resource, &gio_bus_resource);
> + printk(KERN_INFO "GIO: Probing bus...\n");
> +
> + if (ip22_is_fullhouse() ||
> + !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) {
> + /* Indigo2 and ChallengeS */
> + ip22_check_gio(0, GIO_SLOT_GFX_BASE);
> + ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
> + } else {
> + /* Indy */
> + ip22_check_gio(0, GIO_SLOT_GFX_BASE);
> + ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
> + ip22_check_gio(2, GIO_SLOT_EXP1_BASE);
> + }
> + }
> + return ret;
> +}
> +
> +subsys_initcall(ip22_gio_init);
> +
> diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
> index d22262e..75ada8a 100644
> --- a/arch/mips/sgi-ip22/ip22-mc.c
> +++ b/arch/mips/sgi-ip22/ip22-mc.c
> @@ -139,11 +139,11 @@ void __init sgimc_init(void)
> * zero.
> */
> /* don't touch parity settings for IP28 */
> -#ifndef CONFIG_SGI_IP28
> tmp = sgimc->cpuctrl0;
> - tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
> - SGIMC_CCTRL0_R4KNOCHKPARR);
> +#ifndef CONFIG_SGI_IP28
> + tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
> #endif
> + tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
> sgimc->cpuctrl0 = tmp;
>
> /* Step 3: Setup the MC write buffer depth, this is controlled
> @@ -178,7 +178,8 @@ void __init sgimc_init(void)
> */
>
> /* First the basic invariants across all GIO64 implementations. */
> - tmp = SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */
> + tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
> + tmp |= SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */
> tmp |= SGIMC_GIOPAR_ONEBUS; /* Only one physical GIO bus exists */
>
> if (ip22_is_fullhouse()) {
> @@ -193,7 +194,6 @@ void __init sgimc_init(void)
> tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp[01] pipelined */
> tmp |= SGIMC_GIOPAR_PLINEEXP1;
> tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */
> - tmp |= SGIMC_GIOPAR_GFX64; /* GFX at 64 bits */
> }
> } else {
> /* Guiness specific settings. */
> diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
> index 5e66213..c7bdfe4 100644
> --- a/arch/mips/sgi-ip22/ip22-setup.c
> +++ b/arch/mips/sgi-ip22/ip22-setup.c
> @@ -26,9 +26,6 @@
> #include <asm/sgi/hpc3.h>
> #include <asm/sgi/ip22.h>
>
> -unsigned long sgi_gfxaddr;
> -EXPORT_SYMBOL_GPL(sgi_gfxaddr);
> -
> extern void ip22_be_init(void) __init;
>
> void __init plat_mem_setup(void)
> @@ -78,22 +75,4 @@ void __init plat_mem_setup(void)
> prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
> add_preferred_console("arc", 0, NULL);
> }
> -
> -#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE)
> - {
> - ULONG *gfxinfo;
> - ULONG * (*__vec)(void) = (void *) (long)
> - *((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20));
> -
> - gfxinfo = __vec();
> - sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
> - && gfxinfo[1] <= 0xc0000000)
> - ? gfxinfo[1] - 0xa0000000 : 0);
> -
> - /* newport addresses? */
> - if (sgi_gfxaddr = 0x1f0f0000 || sgi_gfxaddr = 0x1f4f0000) {
> - conswitchp = &newport_con;
> - }
> - }
> -#endif
> }
> diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
> index 93317b5..628b7ec 100644
> --- a/drivers/video/console/newport_con.c
> +++ b/drivers/video/console/newport_con.c
> @@ -25,14 +25,13 @@
> #include <asm/system.h>
> #include <asm/page.h>
> #include <asm/pgtable.h>
> +#include <asm/gio_device.h>
> +
> #include <video/newport.h>
>
> #include <linux/linux_logo.h>
> #include <linux/font.h>
>
> -
> -extern unsigned long sgi_gfxaddr;
> -
> #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
>
> /* borrowed from fbcon.c */
> @@ -304,12 +303,6 @@ static const char *newport_startup(void)
> {
> int i;
>
> - if (!sgi_gfxaddr)
> - return NULL;
> -
> - if (!npregs)
> - npregs = (struct newport_regs *)/* ioremap cannot fail */
> - ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
> npregs->cset.config = NPORT_CFG_GD0;
>
> if (newport_wait(npregs))
> @@ -743,26 +736,56 @@ const struct consw newport_con = {
> .con_save_screen = DUMMY
> };
>
> -#ifdef MODULE
> -static int __init newport_console_init(void)
> +static int newport_probe(struct gio_device *dev,
> + const struct gio_device_id *id)
> {
> - if (!sgi_gfxaddr)
> - return 0;
> + unsigned long newport_addr;
>
> - if (!npregs)
> - npregs = (struct newport_regs *)/* ioremap cannot fail */
> - ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
> + if (!dev->resource.start)
> + return -EINVAL;
> +
> + if (npregs)
> + return -EBUSY; /* we only support one Newport as console */
> +
> + newport_addr = dev->resource.start + 0xF0000;
> + if (!request_mem_region(newport_addr, 0x10000, "Newport"))
> + return -ENODEV;
> +
> + npregs = (struct newport_regs *)/* ioremap cannot fail */
> + ioremap(newport_addr, sizeof(struct newport_regs));
>
> return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
> }
> -module_init(newport_console_init);
>
> -static void __exit newport_console_exit(void)
> +static void newport_remove(struct gio_device *dev)
> {
> give_up_console(&newport_con);
> iounmap((void *)npregs);
> }
> +
> +static struct gio_device_id newport_ids[] = {
> + { .id = 0x7e },
> + { .id = 0xff }
> +};
> +
> +static struct gio_driver newport_driver = {
> + .name = "newport",
> + .id_table = newport_ids,
> + .probe = newport_probe,
> + .remove = newport_remove,
> +};
> +
> +int __init newport_console_init(void)
> +{
> + return gio_register_driver(&newport_driver);
> +}
> +
> +void __exit newport_console_exit(void)
> +{
> + gio_unregister_driver(&newport_driver);
> +}
> +
> +module_init(newport_console_init);
> module_exit(newport_console_exit);
> -#endif
>
> MODULE_LICENSE("GPL");
>
WARNING: multiple messages have this Message-ID (diff)
From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
To: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: linux-mips@linux-mips.org, linux-fbdev@vger.kernel.org,
ralf@linux-mips.org
Subject: Re: [PATCH v2] GIO bus support for SGI IP22/28
Date: Sun, 30 Oct 2011 15:53:25 +0000 [thread overview]
Message-ID: <4EAD72F5.9010800@gmx.de> (raw)
In-Reply-To: <20111020221928.0C2191DA27@solo.franken.de>
On 10/20/2011 10:19 PM, Thomas Bogendoerfer wrote:
> SGI IP22/IP28 machines have GIO busses for adding graphics and other
> extension cards. This patch adds support for GIO driver/device
> handling and converts the newport console driver to a GIO driver.
>
> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> ---
>
> Changes to last version:
> - use EXPORT_SYMBOL_GPL
> - ChallengeS has only 2 slots
> - use subsys_initcall for gio detection
>
> Florian, the whole patch should go through the MIPS tree, if it's ok for
> you.
No problem. I'm not even sure whether I'm responsible for it as it is not a
framebuffer but a console driver. Anyway I had a look at the console code so you
may add an
Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
if you like.
Best regards,
Florian Tobias Schandinat
> arch/mips/include/asm/gio_device.h | 56 +++++
> arch/mips/sgi-ip22/Makefile | 2 +-
> arch/mips/sgi-ip22/ip22-gio.c | 414 +++++++++++++++++++++++++++++++++++
> arch/mips/sgi-ip22/ip22-mc.c | 10 +-
> arch/mips/sgi-ip22/ip22-setup.c | 21 --
> drivers/video/console/newport_con.c | 61 ++++--
> 6 files changed, 518 insertions(+), 46 deletions(-)
>
> diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h
> new file mode 100644
> index 0000000..5437c84
> --- /dev/null
> +++ b/arch/mips/include/asm/gio_device.h
> @@ -0,0 +1,56 @@
> +#include <linux/device.h>
> +#include <linux/mod_devicetable.h>
> +
> +struct gio_device_id {
> + __u8 id;
> +};
> +
> +struct gio_device {
> + struct device dev;
> + struct resource resource;
> + unsigned int irq;
> + unsigned int slotno;
> +
> + const char *name;
> + struct gio_device_id id;
> + unsigned id32:1;
> + unsigned gio64:1;
> +};
> +#define to_gio_device(d) container_of(d, struct gio_device, dev)
> +
> +struct gio_driver {
> + const char *name;
> + struct module *owner;
> + const struct gio_device_id *id_table;
> +
> + int (*probe)(struct gio_device *, const struct gio_device_id *);
> + void (*remove)(struct gio_device *);
> + int (*suspend)(struct gio_device *, pm_message_t);
> + int (*resume)(struct gio_device *);
> + void (*shutdown)(struct gio_device *);
> +
> + struct device_driver driver;
> +};
> +#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
> +
> +extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
> + const struct gio_device *);
> +extern struct gio_device *gio_dev_get(struct gio_device *);
> +extern void gio_dev_put(struct gio_device *);
> +
> +extern int gio_device_register(struct gio_device *);
> +extern void gio_device_unregister(struct gio_device *);
> +extern void gio_release_dev(struct device *);
> +
> +static inline void gio_device_free(struct gio_device *dev)
> +{
> + gio_release_dev(&dev->dev);
> +}
> +
> +extern int gio_register_driver(struct gio_driver *);
> +extern void gio_unregister_driver(struct gio_driver *);
> +
> +#define gio_get_drvdata(_dev) drv_get_drvdata(&(_dev)->dev)
> +#define gio_set_drvdata(_dev, data) drv_set_drvdata(&(_dev)->dev, (data))
> +
> +extern void gio_set_master(struct gio_device *);
> diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
> index cc53849..411cda9 100644
> --- a/arch/mips/sgi-ip22/Makefile
> +++ b/arch/mips/sgi-ip22/Makefile
> @@ -4,7 +4,7 @@
> #
>
> obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
> - ip22-platform.o ip22-reset.o ip22-setup.o
> + ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
>
> obj-$(CONFIG_SGI_IP22) += ip22-berr.o
> obj-$(CONFIG_SGI_IP28) += ip28-berr.o
> diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
> new file mode 100644
> index 0000000..d841529
> --- /dev/null
> +++ b/arch/mips/sgi-ip22/ip22-gio.c
> @@ -0,0 +1,414 @@
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +
> +#include <asm/addrspace.h>
> +#include <asm/paccess.h>
> +#include <asm/gio_device.h>
> +#include <asm/sgi/gio.h>
> +#include <asm/sgi/hpc3.h>
> +#include <asm/sgi/mc.h>
> +#include <asm/sgi/ip22.h>
> +
> +static struct bus_type gio_bus;
> +
> +static struct {
> + const char *name;
> + __u8 id;
> +} gio_name_table[] = {
> + { .name = "SGI Impact", .id = 0x10 },
> + { .name = "Phobos G160", .id = 0x35 },
> + /* fake IDs */
> + { .name = "SGI Newport", .id = 0x7e },
> + { .name = "SGI GR2/GR3", .id = 0x7f },
> +};
> +
> +/**
> + * gio_match_device - Tell if an of_device structure has a matching
> + * gio_match structure
> + * @ids: array of of device match structures to search in
> + * @dev: the of device structure to match against
> + *
> + * Used by a driver to check whether an of_device present in the
> + * system is in its list of supported devices.
> + */
> +const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
> + const struct gio_device *dev)
> +{
> + const struct gio_device_id *ids;
> +
> + for (ids = match; ids->id != 0xff; ids++)
> + if (ids->id == dev->id.id)
> + return ids;
> +
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(gio_match_device);
> +
> +struct gio_device *gio_dev_get(struct gio_device *dev)
> +{
> + struct device *tmp;
> +
> + if (!dev)
> + return NULL;
> + tmp = get_device(&dev->dev);
> + if (tmp)
> + return to_gio_device(tmp);
> + else
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(gio_dev_get);
> +
> +void gio_dev_put(struct gio_device *dev)
> +{
> + if (dev)
> + put_device(&dev->dev);
> +}
> +EXPORT_SYMBOL_GPL(gio_dev_put);
> +
> +static ssize_t dev_show_name(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct gio_device *giodev;
> +
> + giodev = to_gio_device(dev);
> + return sprintf(buf, "%s", giodev->name);
> +}
> +
> +static DEVICE_ATTR(name, S_IRUGO, dev_show_name, NULL);
> +
> +static ssize_t dev_show_id(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct gio_device *giodev;
> +
> + giodev = to_gio_device(dev);
> + return sprintf(buf, "%x", giodev->id.id);
> +}
> +
> +static DEVICE_ATTR(id, S_IRUGO, dev_show_id, NULL);
> +
> +/**
> + * gio_release_dev - free an gio device structure when all users of it are finished.
> + * @dev: device that's been disconnected
> + *
> + * Will be called only by the device core when all users of this gio device are
> + * done.
> + */
> +void gio_release_dev(struct device *dev)
> +{
> + struct gio_device *giodev;
> +
> + giodev = to_gio_device(dev);
> + kfree(giodev);
> +}
> +EXPORT_SYMBOL_GPL(gio_release_dev);
> +
> +int gio_device_register(struct gio_device *giodev)
> +{
> + int rc;
> +
> + giodev->dev.bus = &gio_bus;
> + rc = device_register(&giodev->dev);
> + if (rc)
> + return rc;
> +
> + rc = device_create_file(&giodev->dev, &dev_attr_name);
> + if (rc)
> + goto err;
> + rc = device_create_file(&giodev->dev, &dev_attr_id);
> + if (rc)
> + goto err;
> +
> + return 0;
> +
> +err:
> + device_unregister(&giodev->dev);
> + return rc;
> +}
> +EXPORT_SYMBOL_GPL(gio_device_register);
> +
> +void gio_device_unregister(struct gio_device *giodev)
> +{
> + device_remove_file(&giodev->dev, &dev_attr_id);
> + device_remove_file(&giodev->dev, &dev_attr_name);
> + device_unregister(&giodev->dev);
> +}
> +EXPORT_SYMBOL_GPL(gio_device_unregister);
> +
> +static int gio_bus_match(struct device *dev, struct device_driver *drv)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *gio_drv = to_gio_driver(drv);
> +
> + return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
> +}
> +
> +static int gio_device_probe(struct device *dev)
> +{
> + int error = -ENODEV;
> + struct gio_driver *drv;
> + struct gio_device *gio_dev;
> + const struct gio_device_id *match;
> +
> + drv = to_gio_driver(dev->driver);
> + gio_dev = to_gio_device(dev);
> +
> + if (!drv->probe)
> + return error;
> +
> + gio_dev_get(gio_dev);
> +
> + match = gio_match_device(drv->id_table, gio_dev);
> + if (match)
> + error = drv->probe(gio_dev, match);
> + if (error)
> + gio_dev_put(gio_dev);
> +
> + return error;
> +}
> +
> +static int gio_device_remove(struct device *dev)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *drv = to_gio_driver(dev->driver);
> +
> + if (dev->driver && drv->remove)
> + drv->remove(gio_dev);
> + return 0;
> +}
> +
> +static int gio_device_suspend(struct device *dev, pm_message_t state)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *drv = to_gio_driver(dev->driver);
> + int error = 0;
> +
> + if (dev->driver && drv->suspend)
> + error = drv->suspend(gio_dev, state);
> + return error;
> +}
> +
> +static int gio_device_resume(struct device *dev)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *drv = to_gio_driver(dev->driver);
> + int error = 0;
> +
> + if (dev->driver && drv->resume)
> + error = drv->resume(gio_dev);
> + return error;
> +}
> +
> +static void gio_device_shutdown(struct device *dev)
> +{
> + struct gio_device *gio_dev = to_gio_device(dev);
> + struct gio_driver *drv = to_gio_driver(dev->driver);
> +
> + if (dev->driver && drv->shutdown)
> + drv->shutdown(gio_dev);
> +}
> +
> +int gio_register_driver(struct gio_driver *drv)
> +{
> + /* initialize common driver fields */
> + if (!drv->driver.name)
> + drv->driver.name = drv->name;
> + if (!drv->driver.owner)
> + drv->driver.owner = drv->owner;
> + drv->driver.bus = &gio_bus;
> +
> + /* register with core */
> + return driver_register(&drv->driver);
> +}
> +EXPORT_SYMBOL_GPL(gio_register_driver);
> +
> +void gio_unregister_driver(struct gio_driver *drv)
> +{
> + driver_unregister(&drv->driver);
> +}
> +EXPORT_SYMBOL_GPL(gio_unregister_driver);
> +
> +void gio_set_master(struct gio_device *dev)
> +{
> + u32 tmp = sgimc->giopar;
> +
> + switch (dev->slotno) {
> + case 0:
> + tmp |= SGIMC_GIOPAR_MASTERGFX;
> + break;
> + case 1:
> + tmp |= SGIMC_GIOPAR_MASTEREXP0;
> + break;
> + case 2:
> + tmp |= SGIMC_GIOPAR_MASTEREXP1;
> + break;
> + }
> + sgimc->giopar = tmp;
> +}
> +EXPORT_SYMBOL_GPL(gio_set_master);
> +
> +void ip22_gio_set_64bit(int slotno)
> +{
> + u32 tmp = sgimc->giopar;
> +
> + switch (slotno) {
> + case 0:
> + tmp |= SGIMC_GIOPAR_GFX64;
> + break;
> + case 1:
> + tmp |= SGIMC_GIOPAR_EXP064;
> + break;
> + case 2:
> + tmp |= SGIMC_GIOPAR_EXP164;
> + break;
> + }
> + sgimc->giopar = tmp;
> +}
> +
> +static int ip22_gio_id(unsigned long addr, u32 *res)
> +{
> + u8 tmp8;
> + u8 tmp16;
> + u32 tmp32;
> + u8 *ptr8;
> + u16 *ptr16;
> + u32 *ptr32;
> +
> + ptr32 = (void *)CKSEG1ADDR(addr);
> + if (!get_dbe(tmp32, ptr32)) {
> + /*
> + * We got no DBE, but this doesn't mean anything.
> + * If GIO is pipelined (which can't be disabled
> + * for GFX slot) we don't get a DBE, but we see
> + * the transfer size as data. So we do an 8bit
> + * and a 16bit access and check whether the common
> + * data matches
> + */
> + ptr8 = (void *)CKSEG1ADDR(addr + 3);
> + get_dbe(tmp8, ptr8);
> + ptr16 = (void *)CKSEG1ADDR(addr + 2);
> + get_dbe(tmp16, ptr16);
> + if (tmp8 == (tmp16 & 0xff) &&
> + tmp8 == (tmp32 & 0xff) &&
> + tmp16 == (tmp32 & 0xffff)) {
> + *res = tmp32;
> + return 1;
> + }
> + }
> + return 0; /* nothing here */
> +}
> +
> +#define HQ2_MYSTERY_OFFS 0x6A07C
> +#define NEWPORT_USTATUS_OFFS 0xF133C
> +
> +static int ip22_is_gr2(unsigned long addr)
> +{
> + u32 tmp;
> + u32 *ptr;
> +
> + /* HQ2 only allows 32bit accesses */
> + ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
> + if (!get_dbe(tmp, ptr)) {
> + if (tmp == 0xdeadbeef)
> + return 1;
> + }
> + return 0;
> +}
> +
> +
> +static void ip22_check_gio(int slotno, unsigned long addr)
> +{
> + const char *name = "Unknown";
> + struct gio_device *gio_dev;
> + u32 tmp;
> + __u8 id;
> + int i;
> +
> + /* first look for GR2/GR3 by checking mystery register */
> + if (ip22_is_gr2(addr))
> + tmp = 0x7f;
> + else {
> + if (!ip22_gio_id(addr, &tmp)) {
> + /*
> + * no GIO signature at start address of slot, but
> + * Newport doesn't have one, so let's check usea
> + * status register
> + */
> + if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
> + tmp = 0x7e;
> + else
> + tmp = 0;
> + }
> + }
> + if (tmp) {
> + id = GIO_ID(tmp);
> + if (tmp & GIO_32BIT_ID) {
> + if (tmp & GIO_64BIT_IFACE)
> + ip22_gio_set_64bit(slotno);
> + }
> + for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
> + if (id == gio_name_table[i].id) {
> + name = gio_name_table[i].name;
> + break;
> + }
> + }
> + printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
> + slotno, name, id);
> + gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
> + gio_dev->name = name;
> + gio_dev->slotno = slotno;
> + gio_dev->id.id = id;
> + gio_dev->resource.start = addr;
> + gio_dev->resource.end = addr + 0x3fffff;
> + gio_dev->resource.flags = IORESOURCE_MEM;
> + dev_set_name(&gio_dev->dev, "gio%d", slotno);
> + gio_device_register(gio_dev);
> + } else
> + printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
> +}
> +
> +static struct bus_type gio_bus = {
> + .name = "gio",
> + .match = gio_bus_match,
> + .probe = gio_device_probe,
> + .remove = gio_device_remove,
> + .suspend = gio_device_suspend,
> + .resume = gio_device_resume,
> + .shutdown = gio_device_shutdown,
> +};
> +
> +static struct resource gio_bus_resource = {
> + .start = GIO_SLOT_GFX_BASE,
> + .end = GIO_SLOT_GFX_BASE + 0x9fffff,
> + .name = "GIO Bus",
> + .flags = IORESOURCE_MEM,
> +};
> +
> +int __init ip22_gio_init(void)
> +{
> + unsigned int pbdma __maybe_unused;
> + int ret;
> +
> + ret = bus_register(&gio_bus);
> + if (!ret) {
> + request_resource(&iomem_resource, &gio_bus_resource);
> + printk(KERN_INFO "GIO: Probing bus...\n");
> +
> + if (ip22_is_fullhouse() ||
> + !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) {
> + /* Indigo2 and ChallengeS */
> + ip22_check_gio(0, GIO_SLOT_GFX_BASE);
> + ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
> + } else {
> + /* Indy */
> + ip22_check_gio(0, GIO_SLOT_GFX_BASE);
> + ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
> + ip22_check_gio(2, GIO_SLOT_EXP1_BASE);
> + }
> + }
> + return ret;
> +}
> +
> +subsys_initcall(ip22_gio_init);
> +
> diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
> index d22262e..75ada8a 100644
> --- a/arch/mips/sgi-ip22/ip22-mc.c
> +++ b/arch/mips/sgi-ip22/ip22-mc.c
> @@ -139,11 +139,11 @@ void __init sgimc_init(void)
> * zero.
> */
> /* don't touch parity settings for IP28 */
> -#ifndef CONFIG_SGI_IP28
> tmp = sgimc->cpuctrl0;
> - tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
> - SGIMC_CCTRL0_R4KNOCHKPARR);
> +#ifndef CONFIG_SGI_IP28
> + tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
> #endif
> + tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
> sgimc->cpuctrl0 = tmp;
>
> /* Step 3: Setup the MC write buffer depth, this is controlled
> @@ -178,7 +178,8 @@ void __init sgimc_init(void)
> */
>
> /* First the basic invariants across all GIO64 implementations. */
> - tmp = SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */
> + tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
> + tmp |= SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */
> tmp |= SGIMC_GIOPAR_ONEBUS; /* Only one physical GIO bus exists */
>
> if (ip22_is_fullhouse()) {
> @@ -193,7 +194,6 @@ void __init sgimc_init(void)
> tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp[01] pipelined */
> tmp |= SGIMC_GIOPAR_PLINEEXP1;
> tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */
> - tmp |= SGIMC_GIOPAR_GFX64; /* GFX at 64 bits */
> }
> } else {
> /* Guiness specific settings. */
> diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
> index 5e66213..c7bdfe4 100644
> --- a/arch/mips/sgi-ip22/ip22-setup.c
> +++ b/arch/mips/sgi-ip22/ip22-setup.c
> @@ -26,9 +26,6 @@
> #include <asm/sgi/hpc3.h>
> #include <asm/sgi/ip22.h>
>
> -unsigned long sgi_gfxaddr;
> -EXPORT_SYMBOL_GPL(sgi_gfxaddr);
> -
> extern void ip22_be_init(void) __init;
>
> void __init plat_mem_setup(void)
> @@ -78,22 +75,4 @@ void __init plat_mem_setup(void)
> prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
> add_preferred_console("arc", 0, NULL);
> }
> -
> -#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE)
> - {
> - ULONG *gfxinfo;
> - ULONG * (*__vec)(void) = (void *) (long)
> - *((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20));
> -
> - gfxinfo = __vec();
> - sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
> - && gfxinfo[1] <= 0xc0000000)
> - ? gfxinfo[1] - 0xa0000000 : 0);
> -
> - /* newport addresses? */
> - if (sgi_gfxaddr == 0x1f0f0000 || sgi_gfxaddr == 0x1f4f0000) {
> - conswitchp = &newport_con;
> - }
> - }
> -#endif
> }
> diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
> index 93317b5..628b7ec 100644
> --- a/drivers/video/console/newport_con.c
> +++ b/drivers/video/console/newport_con.c
> @@ -25,14 +25,13 @@
> #include <asm/system.h>
> #include <asm/page.h>
> #include <asm/pgtable.h>
> +#include <asm/gio_device.h>
> +
> #include <video/newport.h>
>
> #include <linux/linux_logo.h>
> #include <linux/font.h>
>
> -
> -extern unsigned long sgi_gfxaddr;
> -
> #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
>
> /* borrowed from fbcon.c */
> @@ -304,12 +303,6 @@ static const char *newport_startup(void)
> {
> int i;
>
> - if (!sgi_gfxaddr)
> - return NULL;
> -
> - if (!npregs)
> - npregs = (struct newport_regs *)/* ioremap cannot fail */
> - ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
> npregs->cset.config = NPORT_CFG_GD0;
>
> if (newport_wait(npregs))
> @@ -743,26 +736,56 @@ const struct consw newport_con = {
> .con_save_screen = DUMMY
> };
>
> -#ifdef MODULE
> -static int __init newport_console_init(void)
> +static int newport_probe(struct gio_device *dev,
> + const struct gio_device_id *id)
> {
> - if (!sgi_gfxaddr)
> - return 0;
> + unsigned long newport_addr;
>
> - if (!npregs)
> - npregs = (struct newport_regs *)/* ioremap cannot fail */
> - ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
> + if (!dev->resource.start)
> + return -EINVAL;
> +
> + if (npregs)
> + return -EBUSY; /* we only support one Newport as console */
> +
> + newport_addr = dev->resource.start + 0xF0000;
> + if (!request_mem_region(newport_addr, 0x10000, "Newport"))
> + return -ENODEV;
> +
> + npregs = (struct newport_regs *)/* ioremap cannot fail */
> + ioremap(newport_addr, sizeof(struct newport_regs));
>
> return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
> }
> -module_init(newport_console_init);
>
> -static void __exit newport_console_exit(void)
> +static void newport_remove(struct gio_device *dev)
> {
> give_up_console(&newport_con);
> iounmap((void *)npregs);
> }
> +
> +static struct gio_device_id newport_ids[] = {
> + { .id = 0x7e },
> + { .id = 0xff }
> +};
> +
> +static struct gio_driver newport_driver = {
> + .name = "newport",
> + .id_table = newport_ids,
> + .probe = newport_probe,
> + .remove = newport_remove,
> +};
> +
> +int __init newport_console_init(void)
> +{
> + return gio_register_driver(&newport_driver);
> +}
> +
> +void __exit newport_console_exit(void)
> +{
> + gio_unregister_driver(&newport_driver);
> +}
> +
> +module_init(newport_console_init);
> module_exit(newport_console_exit);
> -#endif
>
> MODULE_LICENSE("GPL");
>
next prev parent reply other threads:[~2011-10-30 15:53 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-20 22:19 [PATCH v2] GIO bus support for SGI IP22/28 Thomas Bogendoerfer
2011-10-20 22:19 ` Thomas Bogendoerfer
2011-10-30 15:53 ` Florian Tobias Schandinat [this message]
2011-10-30 15:53 ` Florian Tobias Schandinat
2011-10-30 20:43 ` Joshua Kinard
2011-10-30 20:43 ` Joshua Kinard
2011-10-30 22:34 ` Thomas Bogendoerfer
2011-10-30 22:34 ` Thomas Bogendoerfer
2011-10-31 8:04 ` Joshua Kinard
2011-10-31 8:04 ` Joshua Kinard
2011-11-01 10:00 ` Thomas Bogendoerfer
2011-11-01 10:00 ` Thomas Bogendoerfer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4EAD72F5.9010800@gmx.de \
--to=florianschandinat@gmx.de \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-mips@linux-mips.org \
--cc=ralf@linux-mips.org \
--cc=tsbogend@alpha.franken.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.