Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCH 08/11] misc: support for parallel slots in LP-8x4x

37 views
Skip to first unread message

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
This patch enumerates parallel modules in expansion slots and exposes
model numbers via sysfs.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
Documentation/misc-devices/lp8x4x_bus.txt | 8 ++
arch/arm/mach-pxa/include/mach/lp8x4x.h | 8 ++
arch/arm/mach-pxa/lp8x4x.c | 42 +++++++++-
drivers/misc/lp8x4x_bus.c | 127 ++++++++++++++++++++++++++++++
4 files changed, 184 insertions(+), 1 deletion(-)

diff --git a/Documentation/misc-devices/lp8x4x_bus.txt b/Documentation/misc-devices/lp8x4x_bus.txt
index d9a069d..9285fdc 100644
--- a/Documentation/misc-devices/lp8x4x_bus.txt
+++ b/Documentation/misc-devices/lp8x4x_bus.txt
@@ -28,6 +28,9 @@ into the device, they could be accessed using the 2nd PXA built-in UART port
(/dev/ttySA1). However, it seems that addresses are not processed by
the modules. So the parallel bus needs to select which slot is connected.

+Parallel modules allow much faster communication. There are accessed using
+IO memory through the FPGA. Their ports are exposed via sysfs.
+
SYSFS
-----

@@ -41,3 +44,8 @@ active_slot
is a parallel module in the selected slot, it simply ignores
incoming packets. So it is safe to activate any available
slot.
+
+/sys/bus/icpdas/devices/slot%02i:
+
+model
+ RO - shows expansion module model number
diff --git a/arch/arm/mach-pxa/include/mach/lp8x4x.h b/arch/arm/mach-pxa/include/mach/lp8x4x.h
index 9addfa8..e1005c5 100644
--- a/arch/arm/mach-pxa/include/mach/lp8x4x.h
+++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h
@@ -37,6 +37,14 @@

/* board level registers in the FPGA */

+#define LP8X4X_SLOT1_IO 0x17001000
+#define LP8X4X_SLOT2_IO 0x17002000
+#define LP8X4X_SLOT3_IO 0x17003000
+#define LP8X4X_SLOT4_IO 0x17004000
+#define LP8X4X_SLOT5_IO 0x17005000
+#define LP8X4X_SLOT6_IO 0x17006000
+#define LP8X4X_SLOT7_IO 0x17007000
+#define LP8X4X_SLOT8_IO 0x17008000
#define LP8X4X_SLOT_SWITCH 0x17009004
#define LP8X4X_EOI LP8X4X_P2V(0x17009006)
#define LP8X4X_INSINT LP8X4X_P2V(0x17009008)
diff --git a/arch/arm/mach-pxa/lp8x4x.c b/arch/arm/mach-pxa/lp8x4x.c
index b30343d..ae84d36 100644
--- a/arch/arm/mach-pxa/lp8x4x.c
+++ b/arch/arm/mach-pxa/lp8x4x.c
@@ -429,6 +429,46 @@ static struct resource lp8x4x_bus_resources[] = {
.end = LP8X4X_SLOT_SWITCH,
.flags = IORESOURCE_MEM,
},
+ [2] = {
+ .start = LP8X4X_SLOT1_IO,
+ .end = LP8X4X_SLOT1_IO + 15,
+ .flags = IORESOURCE_MEM,
+ },
+ [3] = {
+ .start = LP8X4X_SLOT2_IO,
+ .end = LP8X4X_SLOT2_IO + 15,
+ .flags = IORESOURCE_MEM,
+ },
+ [4] = {
+ .start = LP8X4X_SLOT3_IO,
+ .end = LP8X4X_SLOT3_IO + 15,
+ .flags = IORESOURCE_MEM,
+ },
+ [5] = {
+ .start = LP8X4X_SLOT4_IO,
+ .end = LP8X4X_SLOT4_IO + 15,
+ .flags = IORESOURCE_MEM,
+ },
+ [6] = {
+ .start = LP8X4X_SLOT5_IO,
+ .end = LP8X4X_SLOT5_IO + 15,
+ .flags = IORESOURCE_MEM,
+ },
+ [7] = {
+ .start = LP8X4X_SLOT6_IO,
+ .end = LP8X4X_SLOT6_IO + 15,
+ .flags = IORESOURCE_MEM,
+ },
+ [8] = {
+ .start = LP8X4X_SLOT7_IO,
+ .end = LP8X4X_SLOT7_IO + 15,
+ .flags = IORESOURCE_MEM,
+ },
+ [9] = {
+ .start = LP8X4X_SLOT8_IO,
+ .end = LP8X4X_SLOT8_IO + 15,
+ .flags = IORESOURCE_MEM,
+ },
};

static struct platform_device lp8x4x_bus_device[] = {
@@ -436,7 +476,7 @@ static struct platform_device lp8x4x_bus_device[] = {
.name = "lp8x4x-bus",
.id = 0,
.resource = &lp8x4x_bus_resources[0],
- .num_resources = 2,
+ .num_resources = 10,
},
};

diff --git a/drivers/misc/lp8x4x_bus.c b/drivers/misc/lp8x4x_bus.c
index 647fde7..b2d4a04 100644
--- a/drivers/misc/lp8x4x_bus.c
+++ b/drivers/misc/lp8x4x_bus.c
@@ -24,14 +24,57 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sergei Ianovich <ynv...@gmail.com>");
MODULE_DESCRIPTION("ICP DAS LP-8x4x parallel bus driver");

+struct lp8x4x_slot {
+ void *data_addr;
+ unsigned int model;
+ struct device dev;
+};
+
+#define LP8X4X_MAX_SLOT_COUNT 8
struct lp8x4x_master {
unsigned int slot_count;
void *count_addr;
unsigned int active_slot;
void *switch_addr;
+ struct lp8x4x_slot slot[LP8X4X_MAX_SLOT_COUNT];
struct device dev;
};

+static unsigned char lp8x4x_model[256] = {
+ 0, 0, 0, 0x11, 0, 0x18, 0x13, 0x11,
+ 0x0e, 0x11, 0, 0, 0, 0x5a, 0x5b, 0x5c,
+ 0x3c, 0x44, 0x34, 0x3a, 0x39, 0x36, 0x37, 0x33,
+ 0x35, 0x40, 0x41, 0x42, 0x38, 0x3f, 0x32, 0x45,
+ 0xac, 0x70, 0x8e, 0x8e, 0x1e, 0x72, 0x90, 0x29,
+ 0x4a, 0x22, 0xd3, 0xd2, 0x28, 0x25, 0x2a, 0x29,
+ 0x48, 0x49, 0x5d, 0x1f, 0x20, 0x23, 0x24, 0x4d,
+ 0x3d, 0x3e, 0, 0, 0, 0, 0, 0,
+ 0, 0x78, 0x72, 0x2b, 0x5e, 0x5e, 0x36, 0xae,
+ 0x30, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x5c, 0x5e, 0, 0x5e, 0, 0,
+ 0, 0x3b, 0, 0, 0, 0, 0, 0,
+ 0, 0x50, 0x2e, 0, 0x58, 0, 0, 0x43,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x54, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
static int lp8x4x_match(struct device *dev, struct device_driver *drv)
{
return 1;
@@ -42,6 +85,26 @@ static struct bus_type lp8x4x_bus_type = {
.match = lp8x4x_match,
};

+static void lp8x4x_slot_release(struct device *dev)
+{
+}
+
+static ssize_t model_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lp8x4x_slot *s = container_of(dev, struct lp8x4x_slot, dev);
+
+ return sprintf(buf, "%u\n", s->model + 8000);
+}
+
+static DEVICE_ATTR_RO(model);
+
+static struct attribute *slot_dev_attrs[] = {
+ &dev_attr_model.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(slot_dev);
+
static void lp8x4x_master_release(struct device *dev)
{
struct lp8x4x_master *m = container_of(dev, struct lp8x4x_master, dev);
@@ -107,10 +170,18 @@ ATTRIBUTE_GROUPS(master_dev);
static void devm_lp8x4x_bus_release(struct device *dev, void *res)
{
struct lp8x4x_master *m = *(struct lp8x4x_master **)res;
+ struct lp8x4x_slot *s;
void *mem = m->count_addr;
void *mem2 = m->switch_addr;
+ int i;

dev_info(dev, "releasing devices\n");
+ for (i = 0; i < LP8X4X_MAX_SLOT_COUNT; i++) {
+ s = &m->slot[i];
+ if (s->model)
+ device_unregister(&s->dev);
+ iounmap(s->data_addr);
+ }
device_unregister(&m->dev);
bus_unregister(&lp8x4x_bus_type);

@@ -120,11 +191,36 @@ static void devm_lp8x4x_bus_release(struct device *dev, void *res)
iounmap(mem);
}

+static void __init lp8x4x_bus_probe_slot(struct lp8x4x_master *m, int i,
+ unsigned char model)
+{
+ struct lp8x4x_slot *s = &m->slot[i];
+ int err;
+
+ dev_info(&m->dev, "found %u in slot %i\n", 8000 + model, i + 1);
+
+ s->dev.bus = &lp8x4x_bus_type;
+ dev_set_name(&s->dev, "slot%02i", i + 1);
+ s->dev.parent = &m->dev;
+ s->dev.release = lp8x4x_slot_release;
+ s->dev.groups = slot_dev_groups;
+ s->model = model;
+
+ err = device_register(&s->dev);
+ if (err < 0) {
+ dev_err(&s->dev, "failed to register device\n");
+ s->model = 0;
+ return;
+ }
+}
+
static int __init lp8x4x_bus_probe(struct platform_device *pdev)
{
struct lp8x4x_master *m, **p;
struct resource *res;
+ int i;
int err = 0;
+ unsigned int model;

m = kzalloc(sizeof(*m), GFP_KERNEL);
if (!m)
@@ -167,6 +263,30 @@ static int __init lp8x4x_bus_probe(struct platform_device *pdev)
goto err3;
}

+ for (i = 0; i < LP8X4X_MAX_SLOT_COUNT; i++) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i + 2);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get slot %i address\n",
+ i);
+ err = -ENODEV;
+ goto err4;
+ }
+
+ m->slot[i].data_addr = ioremap(res->start, resource_size(res));
+ if (!m->slot[i].data_addr) {
+ dev_err(&pdev->dev, "Failed to ioremap %p\n",
+ m->slot[i].data_addr);
+ err = -EFAULT;
+ goto err4;
+ }
+ continue;
+err4:
+ for (i--; i >= 0; i--)
+ iounmap(m->slot[i].data_addr);
+
+ goto err3;
+ }
+
m->slot_count = ioread8(m->count_addr);
switch (m->slot_count) {
case 1:
@@ -205,6 +325,13 @@ static int __init lp8x4x_bus_probe(struct platform_device *pdev)
}

devres_add(&pdev->dev, p);
+ for (i = 0; i < LP8X4X_MAX_SLOT_COUNT; i++) {
+ model = lp8x4x_model[ioread8(m->slot[i].data_addr)];
+ if (!model)
+ continue;
+
+ lp8x4x_bus_probe_slot(m, i, model);
+ }
return 0;

err_dev:
--
1.8.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:01 AM12/1/13
to
Serial modules (I-870xxW series) implement DCON protocol which
allows one-master-many-slaves configuration over RS-485. When
these modules are installed into the device, they could be
accessed using the 2nd PXA built-in UART port (/dev/ttySA1).
However, it seems that addresses are not processed by the modules.
So the parallel bus needs to select which slot is connected.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
Documentation/misc-devices/lp8x4x_bus.txt | 15 ++++++-
arch/arm/mach-pxa/include/mach/lp8x4x.h | 1 +
arch/arm/mach-pxa/lp8x4x.c | 7 ++-
drivers/misc/lp8x4x_bus.c | 73 +++++++++++++++++++++++++++++--
4 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/Documentation/misc-devices/lp8x4x_bus.txt b/Documentation/misc-devices/lp8x4x_bus.txt
index f5392b3..d9a069d 100644
--- a/Documentation/misc-devices/lp8x4x_bus.txt
+++ b/Documentation/misc-devices/lp8x4x_bus.txt
@@ -19,7 +19,14 @@ LP-8x4x is an ARM-based industrial computer with a custom parallel bus to
connect expansion modules with digital input/output, analog input/output,
serial, CAN and other types of ports.

-The bus is implemented by a FPGA.
+The bus is implemented by a FPGA. There are two major groups of expansion
+modules: serial and parallel.
+
+Serial modules (I-870xxW series) implement DCON protocol which allows one-
+master-many-slaves configuration over RS-485. When these modules are installed
+into the device, they could be accessed using the 2nd PXA built-in UART port
+(/dev/ttySA1). However, it seems that addresses are not processed by
+the modules. So the parallel bus needs to select which slot is connected.

SYSFS
-----
@@ -28,3 +35,9 @@ SYSFS

slot_count
RO - shows total number of expansion slots on the device
+
+active_slot
+ RW - connects the select slot for serial communications. If there
+ is a parallel module in the selected slot, it simply ignores
+ incoming packets. So it is safe to activate any available
+ slot.
diff --git a/arch/arm/mach-pxa/include/mach/lp8x4x.h b/arch/arm/mach-pxa/include/mach/lp8x4x.h
index 5d289bf..9addfa8 100644
--- a/arch/arm/mach-pxa/include/mach/lp8x4x.h
+++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h
@@ -37,6 +37,7 @@

/* board level registers in the FPGA */

+#define LP8X4X_SLOT_SWITCH 0x17009004
#define LP8X4X_EOI LP8X4X_P2V(0x17009006)
#define LP8X4X_INSINT LP8X4X_P2V(0x17009008)
#define LP8X4X_ENSYSINT LP8X4X_P2V(0x1700900A)
diff --git a/arch/arm/mach-pxa/lp8x4x.c b/arch/arm/mach-pxa/lp8x4x.c
index 38482d3..b30343d 100644
--- a/arch/arm/mach-pxa/lp8x4x.c
+++ b/arch/arm/mach-pxa/lp8x4x.c
@@ -424,6 +424,11 @@ static struct resource lp8x4x_bus_resources[] = {
.end = LP8X4X_MOD_NUM,
.flags = IORESOURCE_MEM,
},
+ [1] = {
+ .start = LP8X4X_SLOT_SWITCH,
+ .end = LP8X4X_SLOT_SWITCH,
+ .flags = IORESOURCE_MEM,
+ },
};

static struct platform_device lp8x4x_bus_device[] = {
@@ -431,7 +436,7 @@ static struct platform_device lp8x4x_bus_device[] = {
.name = "lp8x4x-bus",
.id = 0,
.resource = &lp8x4x_bus_resources[0],
- .num_resources = 1,
+ .num_resources = 2,
},
};

diff --git a/drivers/misc/lp8x4x_bus.c b/drivers/misc/lp8x4x_bus.c
index 9cd840e..647fde7 100644
--- a/drivers/misc/lp8x4x_bus.c
+++ b/drivers/misc/lp8x4x_bus.c
@@ -27,6 +27,8 @@ MODULE_DESCRIPTION("ICP DAS LP-8x4x parallel bus driver");
struct lp8x4x_master {
unsigned int slot_count;
void *count_addr;
+ unsigned int active_slot;
+ void *switch_addr;
struct device dev;
};

@@ -58,8 +60,45 @@ static ssize_t slot_count_show(struct device *dev,

static DEVICE_ATTR_RO(slot_count);

+static ssize_t active_slot_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lp8x4x_master *m = container_of(dev, struct lp8x4x_master, dev);
+
+ return sprintf(buf, "%u\n", m->active_slot);
+}
+
+static ssize_t active_slot_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lp8x4x_master *m = container_of(dev, struct lp8x4x_master, dev);
+ unsigned int active_slot = 0;
+ int err;
+
+ if (!buf)
+ return count;
+ if (0 == count)
+ return count;
+
+ err = kstrtouint(buf, 10, &active_slot);
+ if (err != 0 || !active_slot || active_slot > m->slot_count) {
+ dev_err(dev, "slot number is out of range 1..%u\n",
+ m->slot_count);
+ return count;
+ }
+
+ m->active_slot = active_slot;
+
+ iowrite8((1 << (m->active_slot - 1)) ^ 0xff, m->switch_addr);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(active_slot);
+
static struct attribute *master_dev_attrs[] = {
&dev_attr_slot_count.attr,
+ &dev_attr_active_slot.attr,
NULL,
};
ATTRIBUTE_GROUPS(master_dev);
@@ -69,10 +108,15 @@ static void devm_lp8x4x_bus_release(struct device *dev, void *res)
{
struct lp8x4x_master *m = *(struct lp8x4x_master **)res;
void *mem = m->count_addr;
+ void *mem2 = m->switch_addr;

dev_info(dev, "releasing devices\n");
device_unregister(&m->dev);
bus_unregister(&lp8x4x_bus_type);
+
+ /* Disable serial communications */
+ iowrite8(0xff, mem2);
+ iounmap(mem2);
iounmap(mem);
}

@@ -95,6 +139,7 @@ static int __init lp8x4x_bus_probe(struct platform_device *pdev)

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
+ dev_err(&pdev->dev, "Failed to get slot number address\n");
err = -ENODEV;
goto err2;
}
@@ -107,6 +152,21 @@ static int __init lp8x4x_bus_probe(struct platform_device *pdev)
goto err2;
}

+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get slot switch address\n");
+ err = -ENODEV;
+ goto err3;
+ }
+
+ m->switch_addr = ioremap(res->start, resource_size(res));
+ if (!m->switch_addr) {
+ dev_err(&pdev->dev, "Failed to ioremap %p\n",
+ m->switch_addr);
+ err = -EFAULT;
+ goto err3;
+ }
+
m->slot_count = ioread8(m->count_addr);
switch (m->slot_count) {
case 1:
@@ -118,15 +178,18 @@ static int __init lp8x4x_bus_probe(struct platform_device *pdev)
default:
dev_info(&pdev->dev, "unexpected slot number(%u)",
m->slot_count);
- goto err3;
+ goto err_bus;
};

dev_info(&pdev->dev, "found bus with up to %u slots\n", m->slot_count);

+ /* Disable serial communications until explicitly enabled */
+ iowrite8(0xff, m->switch_addr);
+
err = bus_register(&lp8x4x_bus_type);
if (err < 0) {
dev_err(&pdev->dev, "failed to register bus type\n");
- goto err3;
+ goto err_bus;
}

m->dev.bus = &lp8x4x_bus_type;
@@ -138,14 +201,16 @@ static int __init lp8x4x_bus_probe(struct platform_device *pdev)
err = device_register(&m->dev);
if (err < 0) {
dev_err(&pdev->dev, "failed to register backplane device\n");
- goto err4;
+ goto err_dev;
}

devres_add(&pdev->dev, p);
return 0;

-err4:
+err_dev:
bus_unregister(&lp8x4x_bus_type);
+err_bus:
+ iounmap(m->switch_addr);
err3:
iounmap(m->count_addr);
err2:

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
arch/arm/configs/lp8x4x_defconfig | 1 +
arch/arm/mach-pxa/include/mach/lp8x4x.h | 1 +
arch/arm/mach-pxa/lp8x4x.c | 8 ++++
drivers/rtc/Kconfig | 2 +-
drivers/rtc/rtc-ds1302.c | 85 +++++++++++++++++++++++++++++++++
5 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
index 5cd6d38..27831e4 100644
--- a/arch/arm/configs/lp8x4x_defconfig
+++ b/arch/arm/configs/lp8x4x_defconfig
@@ -1745,6 +1745,7 @@ CONFIG_RTC_INTF_DEV=y
#
# CONFIG_RTC_DRV_CMOS is not set
# CONFIG_RTC_DRV_DS1286 is not set
+CONFIG_RTC_DRV_DS1302=y
# CONFIG_RTC_DRV_DS1511 is not set
# CONFIG_RTC_DRV_DS1553 is not set
# CONFIG_RTC_DRV_DS1742 is not set
diff --git a/arch/arm/mach-pxa/include/mach/lp8x4x.h b/arch/arm/mach-pxa/include/mach/lp8x4x.h
index 8c501fd..d8a1376 100644
--- a/arch/arm/mach-pxa/include/mach/lp8x4x.h
+++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h
@@ -48,6 +48,7 @@
#define LP8X4X_CLRHILVINT LP8X4X_P2V(0x17009016)
#define LP8X4X_ENFALLINT LP8X4X_P2V(0x17009018)
#define LP8X4X_CLRFALLINT LP8X4X_P2V(0x1700901a)
+#define LP8X4X_RWRTC LP8X4X_P2V(0x1700901c)

/* board specific IRQs */

diff --git a/arch/arm/mach-pxa/lp8x4x.c b/arch/arm/mach-pxa/lp8x4x.c
index 0b77e7a..a31b556 100644
--- a/arch/arm/mach-pxa/lp8x4x.c
+++ b/arch/arm/mach-pxa/lp8x4x.c
@@ -386,11 +386,19 @@ static struct platform_device lp8x4x_dm9000_device[2] = {
},
};

+static struct platform_device lp8x4x_ds1302_device[] = {
+ {
+ .name = "rtc-ds1302",
+ .id = 0,
+ },
+};
+
static struct platform_device *lp8x4x_devices[] __initdata = {
&lp8x4x_flash_device[0],
&lp8x4x_flash_device[1],
&lp8x4x_dm9000_device[0],
&lp8x4x_dm9000_device[1],
+ &lp8x4x_ds1302_device[0],
};

static struct pxaohci_platform_data lp8x4x_ohci_platform_data = {
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 0077302..59213c0 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -676,7 +676,7 @@ config RTC_DRV_DS1286

config RTC_DRV_DS1302
tristate "Dallas DS1302"
- depends on SH_SECUREEDGE5410
+ depends on SH_SECUREEDGE5410 || MACH_LP8X4X
help
If you say yes here you get support for the Dallas DS1302 RTC chips.

diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 07e8d79..770587b 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -86,6 +86,91 @@ static inline int ds1302_rxbit(void)
return !!(get_dp() & RTC_IODATA);
}

+#elif defined(CONFIG_MACH_LP8X4X)
+
+#include <linux/sched.h>
+#include <linux/hrtimer.h>
+#include <mach/lp8x4x.h>
+
+#define RTC_CE 0x01
+#define RTC_CLK 0x02
+#define RTC_nWE 0x04
+#define RTC_IODATA 0x08
+
+static unsigned long ds1302_state;
+
+void nsleep(unsigned long nanosec)
+{
+ ktime_t t = ns_to_ktime(nanosec);
+ long state = current->state;
+
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&t, HRTIMER_MODE_REL);
+ __set_current_state(state);
+}
+
+static inline int ds1302_hw_init(void)
+{
+ return 0;
+}
+
+static inline void ds1302_reset(void)
+{
+ ds1302_state = 0;
+ iowrite8(ds1302_state, LP8X4X_RWRTC);
+ nsleep(4000);
+}
+
+static inline void ds1302_clock(void)
+{
+ nsleep(1000);
+ ds1302_state |= RTC_CLK;
+ iowrite8(ds1302_state, LP8X4X_RWRTC);
+ nsleep(1000);
+ ds1302_state &= ~RTC_CLK;
+ iowrite8(ds1302_state, LP8X4X_RWRTC);
+}
+
+static inline void ds1302_start(void)
+{
+ ds1302_state &= ~RTC_CLK;
+ ds1302_state |= RTC_CE;
+ iowrite8(ds1302_state, LP8X4X_RWRTC);
+ nsleep(3000);
+}
+
+static inline void ds1302_stop(void)
+{
+ ds1302_state &= ~RTC_CE;
+ iowrite8(ds1302_state, LP8X4X_RWRTC);
+}
+
+static inline void ds1302_set_tx(void)
+{
+ ds1302_state &= ~RTC_nWE;
+ iowrite8(ds1302_state, LP8X4X_RWRTC);
+}
+
+static inline void ds1302_set_rx(void)
+{
+ ds1302_state |= RTC_nWE;
+ iowrite8(ds1302_state, LP8X4X_RWRTC);
+}
+
+static inline void ds1302_txbit(int bit)
+{
+ if (bit)
+ ds1302_state |= RTC_IODATA;
+ else
+ ds1302_state &= ~RTC_IODATA;
+ iowrite8(ds1302_state, LP8X4X_RWRTC);
+}
+
+static inline int ds1302_rxbit(void)
+{
+ return ioread8(LP8X4X_RWRTC) & 0x1;
+}
+
#else
#error "Add support for your platform"
#endif

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
PXA serial ports have "standard" UART names (ttyS[0-3]), major
device number (4) and first minor device number (64) by default.

If the system has extra 8250 serial port hardware in addition
to onboard PXA serial ports, default settings produce a device
allocation conflict.

The patch provides a configuration option which can move onboard
ports out of the way of 8250_core by assigning a different (204)
major number and corresponding device names (ttySA[0-3]).

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
drivers/tty/serial/Kconfig | 19 +++++++++++++++++++
drivers/tty/serial/pxa.c | 22 ++++++++++++++++++----
2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index a3817ab..328b716 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -419,6 +419,25 @@ config SERIAL_PXA_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)

+config SERIAL_PXA_AS_TTYSA
+ bool "PXA serial ports with SA-1100 name and major number"
+ depends on SERIAL_PXA
+ default N
+ help
+ PXA serial ports have "standard" UART names (ttyS[0-3]), major
+ device number (4) and first minor device number (64) by default.
+
+ If the system has extra 8250 serial port hardware in addition
+ to onboard PXA serial ports, default settings produce a device
+ allocation conflict.
+
+ Selecting this option will move onboard ports out of the way of
+ 8250_core by assigning a different (204) major number and
+ corresponding device names (ttySA[0-3]).
+
+ Say Y here, if you need to support extra 8250 serial port hardware
+ on a PXA system.
+
config SERIAL_SA1100
bool "SA1100 serial port support"
depends on ARCH_SA1100
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index f9f20f3..2b5a8ad 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -593,6 +593,20 @@ serial_pxa_type(struct uart_port *port)
static struct uart_pxa_port *serial_pxa_ports[4];
static struct uart_driver serial_pxa_reg;

+#ifndef CONFIG_SERIAL_PXA_AS_TTYSA
+
+#define PXA_TTY_NAME "ttyS"
+#define PXA_TTY_MAJOR TTY_MAJOR
+#define PXA_TTY_MINOR 64
+
+#else
+
+#define PXA_TTY_NAME "ttySA"
+#define PXA_TTY_MAJOR 204
+#define PXA_TTY_MINOR 5
+
+#endif
+
#ifdef CONFIG_SERIAL_PXA_CONSOLE

#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
@@ -751,7 +765,7 @@ serial_pxa_console_setup(struct console *co, char *options)
}

static struct console serial_pxa_console = {
- .name = "ttyS",
+ .name = PXA_TTY_NAME,
.write = serial_pxa_console_write,
.device = uart_console_device,
.setup = serial_pxa_console_setup,
@@ -792,9 +806,9 @@ static struct uart_ops serial_pxa_pops = {
static struct uart_driver serial_pxa_reg = {
.owner = THIS_MODULE,
.driver_name = "PXA serial",
- .dev_name = "ttyS",
- .major = TTY_MAJOR,
- .minor = 64,
+ .dev_name = PXA_TTY_NAME,
+ .major = PXA_TTY_MAJOR,
+ .minor = PXA_TTY_MINOR,
.nr = 4,
.cons = PXA_CONSOLE,
};

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
Status of I-8041 32 digital output channels can be managed via
sysfs now.

http://www.icpdas.com/products/Remote_IO/i-8ke/i-8041w.htm

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
Documentation/misc-devices/lp8x4x_bus.txt | 4 ++
drivers/misc/lp8x4x_bus.c | 67 ++++++++++++++++++++++++++++++-
2 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/Documentation/misc-devices/lp8x4x_bus.txt b/Documentation/misc-devices/lp8x4x_bus.txt
index 9285fdc..74df10b 100644
--- a/Documentation/misc-devices/lp8x4x_bus.txt
+++ b/Documentation/misc-devices/lp8x4x_bus.txt
@@ -49,3 +49,7 @@ active_slot

model
RO - shows expansion module model number
+
+output_status
+ RW - set status of digital output channels on the module in
+ the expansion slot. Value can be read back.
diff --git a/drivers/misc/lp8x4x_bus.c b/drivers/misc/lp8x4x_bus.c
index b2d4a04..d177735 100644
--- a/drivers/misc/lp8x4x_bus.c
+++ b/drivers/misc/lp8x4x_bus.c
@@ -27,6 +27,9 @@ MODULE_DESCRIPTION("ICP DAS LP-8x4x parallel bus driver");
struct lp8x4x_slot {
void *data_addr;
unsigned int model;
+ struct mutex lock;
+ unsigned int DO_len;
+ u32 DO;
struct device dev;
};

@@ -89,6 +92,45 @@ static void lp8x4x_slot_release(struct device *dev)
{
}

+static void lp8x4x_slot_set_DO(struct lp8x4x_slot *s)
+{
+ int i;
+ mutex_lock(&s->lock);
+ for (i = 0; i < s->DO_len; i++)
+ iowrite8((s->DO >> (i * 8)) & 0xff, s->data_addr + 2 * i);
+ mutex_unlock(&s->lock);
+}
+
+static ssize_t output_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lp8x4x_slot *s = container_of(dev, struct lp8x4x_slot, dev);
+
+ return sprintf(buf, "0x%08x\n", s->DO);
+}
+
+static ssize_t output_status_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lp8x4x_slot *s = container_of(dev, struct lp8x4x_slot, dev);
+
+ if (!buf)
+ return count;
+ if (0 == count)
+ return count;
+
+ if (kstrtouint(buf, 16, &s->DO) != 0) {
+ dev_err(dev, "bad input\n");
+ return count;
+ }
+
+ lp8x4x_slot_set_DO(s);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(output_status);
+
static ssize_t model_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -105,6 +147,13 @@ static struct attribute *slot_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(slot_dev);

+static struct attribute *do_slot_dev_attrs[] = {
+ &dev_attr_model.attr,
+ &dev_attr_output_status.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(do_slot_dev);
+
static void lp8x4x_master_release(struct device *dev)
{
struct lp8x4x_master *m = container_of(dev, struct lp8x4x_master, dev);
@@ -178,8 +227,10 @@ static void devm_lp8x4x_bus_release(struct device *dev, void *res)
dev_info(dev, "releasing devices\n");
for (i = 0; i < LP8X4X_MAX_SLOT_COUNT; i++) {
s = &m->slot[i];
- if (s->model)
+ if (s->model) {
device_unregister(&s->dev);
+ mutex_destroy(&s->lock);
+ }
iounmap(s->data_addr);
}
device_unregister(&m->dev);
@@ -203,13 +254,25 @@ static void __init lp8x4x_bus_probe_slot(struct lp8x4x_master *m, int i,
dev_set_name(&s->dev, "slot%02i", i + 1);
s->dev.parent = &m->dev;
s->dev.release = lp8x4x_slot_release;
- s->dev.groups = slot_dev_groups;
s->model = model;
+ mutex_init(&s->lock);
+
+ switch (model) {
+ case 41:
+ s->DO_len = 4;
+ lp8x4x_slot_set_DO(s);
+ s->dev.groups = do_slot_dev_groups;
+ break;
+ default:
+ s->dev.groups = slot_dev_groups;
+ break;
+ };

err = device_register(&s->dev);
if (err < 0) {
dev_err(&s->dev, "failed to register device\n");
s->model = 0;
+ mutex_destroy(&s->lock);
return;

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
Status of I-8042 16 digital output channels can be managed via
sysfs.

Status of I-8042 16 digital input channels can be read via sysfs.

http://www.icpdas.com/products/Remote_IO/i-8ke/i-8042w.htm

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
Documentation/misc-devices/lp8x4x_bus.txt | 4 ++
drivers/misc/lp8x4x_bus.c | 76 ++++++++++++++++++++++++++++++-
2 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/Documentation/misc-devices/lp8x4x_bus.txt b/Documentation/misc-devices/lp8x4x_bus.txt
index 74df10b..e3a8bcf 100644
--- a/Documentation/misc-devices/lp8x4x_bus.txt
+++ b/Documentation/misc-devices/lp8x4x_bus.txt
@@ -50,6 +50,10 @@ active_slot
model
RO - shows expansion module model number

+input_status
+ RO - get status of digital input channels on the module in
+ the expansion slot.
+
output_status
RW - set status of digital output channels on the module in
the expansion slot. Value can be read back.
diff --git a/drivers/misc/lp8x4x_bus.c b/drivers/misc/lp8x4x_bus.c
index d177735..fce11c4 100644
--- a/drivers/misc/lp8x4x_bus.c
+++ b/drivers/misc/lp8x4x_bus.c
@@ -30,6 +30,8 @@ struct lp8x4x_slot {
struct mutex lock;
unsigned int DO_len;
u32 DO;
+ unsigned int DI_len;
+ u32 DI;
struct device dev;
};

@@ -92,6 +94,21 @@ static void lp8x4x_slot_release(struct device *dev)
{
}

+static void lp8x4x_slot_get_DI(struct lp8x4x_slot *s)
+{
+ int i;
+ u32 b;
+
+ mutex_lock(&s->lock);
+ s->DI = 0;
+ for (i = 0; i < s->DI_len; i++) {
+ b = ioread8(s->data_addr + 2 * (i + 1));
+ b ^= 0xff;
+ s->DI += b << (i * 8);
+ }
+ mutex_unlock(&s->lock);
+}
+
static void lp8x4x_slot_set_DO(struct lp8x4x_slot *s)
{
int i;
@@ -101,29 +118,70 @@ static void lp8x4x_slot_set_DO(struct lp8x4x_slot *s)
mutex_unlock(&s->lock);
}

+static ssize_t input_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lp8x4x_slot *s = container_of(dev, struct lp8x4x_slot, dev);
+
+ lp8x4x_slot_get_DI(s);
+ switch (s->DI_len) {
+ case 4:
+ return sprintf(buf, "0x%08x\n", s->DI);
+ case 2:
+ return sprintf(buf, "0x%04x\n", s->DI);
+ case 1:
+ return sprintf(buf, "0x%02x\n", s->DI);
+ default:
+ break;
+ }
+ return sprintf(buf, "0x%x\n", s->DI);
+}
+
+static DEVICE_ATTR_RO(input_status);
+
static ssize_t output_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lp8x4x_slot *s = container_of(dev, struct lp8x4x_slot, dev);

- return sprintf(buf, "0x%08x\n", s->DO);
+ switch (s->DO_len) {
+ case 4:
+ return sprintf(buf, "0x%08x\n", s->DO);
+ case 2:
+ return sprintf(buf, "0x%04x\n", s->DO);
+ case 1:
+ return sprintf(buf, "0x%02x\n", s->DO);
+ default:
+ break;
+ }
+ return sprintf(buf, "0x%x\n", s->DO);
}

static ssize_t output_status_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct lp8x4x_slot *s = container_of(dev, struct lp8x4x_slot, dev);
+ u32 DO;
+ u8 *b = (void *) &DO;
+ int i;

if (!buf)
return count;
if (0 == count)
return count;

- if (kstrtouint(buf, 16, &s->DO) != 0) {
+ if (kstrtouint(buf, 16, &DO) != 0) {
dev_err(dev, "bad input\n");
return count;
}

+ for (i = 4; i > s->DO_len; i--)
+ if (b[i - 1] != 0) {
+ dev_err(dev, "bad input\n");
+ return count;
+ }
+
+ s->DO = DO;
lp8x4x_slot_set_DO(s);

return count;
@@ -154,6 +212,14 @@ static struct attribute *do_slot_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(do_slot_dev);

+static struct attribute *dio_slot_dev_attrs[] = {
+ &dev_attr_model.attr,
+ &dev_attr_output_status.attr,
+ &dev_attr_input_status.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(dio_slot_dev);
+
static void lp8x4x_master_release(struct device *dev)
{
struct lp8x4x_master *m = container_of(dev, struct lp8x4x_master, dev);
@@ -263,6 +329,12 @@ static void __init lp8x4x_bus_probe_slot(struct lp8x4x_master *m, int i,
lp8x4x_slot_set_DO(s);
s->dev.groups = do_slot_dev_groups;
break;
+ case 42:
+ s->DI_len = 2;
+ s->DO_len = 2;
+ lp8x4x_slot_set_DO(s);
+ s->dev.groups = dio_slot_dev_groups;
+ break;
default:
s->dev.groups = slot_dev_groups;
break;

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
The patch adds support for 3 additional LP-8x4x built-in serial
ports.

The device can also host up to 8 extension cards with 4 serial ports
on each card for a total of 35 ports. However, I don't have
the hardware to test extension cards, so they are not supported, yet.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
arch/arm/configs/lp8x4x_defconfig | 1 +
arch/arm/mach-pxa/include/mach/lp8x4x.h | 6 ++
drivers/tty/serial/8250/8250_lp8x4x.c | 181 ++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 11 ++
drivers/tty/serial/8250/Makefile | 1 +
5 files changed, 200 insertions(+)
create mode 100644 drivers/tty/serial/8250/8250_lp8x4x.c

diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
index 03c85bc..d297a67 100644
--- a/arch/arm/configs/lp8x4x_defconfig
+++ b/arch/arm/configs/lp8x4x_defconfig
@@ -1141,6 +1141,7 @@ CONFIG_SERIAL_8250_NR_UARTS=36
CONFIG_SERIAL_8250_RUNTIME_UARTS=36
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_LP8X4X=m
CONFIG_SERIAL_8250_SHARE_IRQ=y
# CONFIG_SERIAL_8250_DETECT_IRQ is not set
# CONFIG_SERIAL_8250_RSA is not set
diff --git a/arch/arm/mach-pxa/include/mach/lp8x4x.h b/arch/arm/mach-pxa/include/mach/lp8x4x.h
index a49df22..4d5474e 100644
--- a/arch/arm/mach-pxa/include/mach/lp8x4x.h
+++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h
@@ -50,6 +50,12 @@
#define LP8X4X_CLRFALLINT LP8X4X_P2V(0x1700901a)
#define LP8X4X_RWRTC LP8X4X_P2V(0x1700901c)
#define LP8X4X_SRAMBANK 0x1700901e
+#define LP8X4X_TTYS0_QUIRK 0x17009030
+#define LP8X4X_TTYS1_QUIRK 0x17009032
+#define LP8X4X_TTYS2_QUIRK 0x17009034
+#define LP8X4X_TTYS0_IOMEM 0x17009050
+#define LP8X4X_TTYS1_IOMEM 0x17009060
+#define LP8X4X_TTYS2_IOMEM 0x17009070
#define LP8X4X_SRAM 0x1700a000

/* board specific IRQs */
diff --git a/drivers/tty/serial/8250/8250_lp8x4x.c b/drivers/tty/serial/8250/8250_lp8x4x.c
new file mode 100644
index 0000000..27b01f0b
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_lp8x4x.c
@@ -0,0 +1,181 @@
+/* linux/drivers/tty/serial/8250/8250_lp8x4x.c
+ *
+ * Support for 16550 serial ports on ICP DAS LP-8x4x
+ *
+ * Copyright (C) 2013 Sergei Ianovich <ynv...@gmail.com>
+ * Framework taken from linux/drivers/tty/serial/8250/8250_accent.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/serial_8250.h>
+#include <mach/lp8x4x.h>
+#include <linux/io.h>
+
+#define QUIRK_PORT(_base, _irq) \
+ { \
+ .iobase = _base, \
+ .membase = (void *) _base, \
+ .mapbase = _base, \
+ .irq = _irq, \
+ .uartclk = 14745600, \
+ .regshift = 1, \
+ .iotype = UPIO_MEM, \
+ .flags = UPF_IOREMAP, \
+ .set_termios = lp8x4x_set_termios, \
+ .serial_in = lp8x4x_serial_in, \
+ .serial_out = lp8x4x_serial_out, \
+ }
+
+static void lp8x4x_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ unsigned int len;
+ unsigned int baud;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ len = 7;
+ break;
+ case CS6:
+ len = 8;
+ break;
+ case CS7:
+ len = 9;
+ break;
+ default:
+ case CS8:
+ len = 10;
+ break;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ len++;
+ if (termios->c_cflag & PARENB)
+ len++;
+ if (!(termios->c_cflag & PARODD))
+ len++;
+#ifdef CMSPAR
+ if (termios->c_cflag & CMSPAR)
+ len++;
+#endif
+
+ len -= 9;
+ len &= 3;
+ len <<= 3;
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old,
+ port->uartclk / 16 / 0xffff,
+ port->uartclk / 16);
+ switch (baud) {
+ case 2400:
+ len |= 1;
+ case 4800:
+ len |= 2;
+ case 19200:
+ len |= 4;
+ case 38400:
+ len |= 5;
+ case 57600:
+ len |= 6;
+ case 115200:
+ len |= 7;
+ case 9600:
+ default:
+ len |= 3;
+ };
+ iowrite8(len, port->private_data);
+
+ serial8250_do_set_termios(port, termios, old);
+}
+
+static unsigned int lp8x4x_serial_in(struct uart_port *p, int offset)
+{
+ unsigned int b;
+ udelay(30);
+ offset = offset << p->regshift;
+ b = readb(p->membase + offset);
+ return b;
+}
+
+static void lp8x4x_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = offset << p->regshift;
+ writeb(value, p->membase + offset);
+}
+
+static struct plat_serial8250_port lp8x4x_data[] = {
+ QUIRK_PORT(LP8X4X_TTYS0_IOMEM, LP8X4X_TTYS0_IRQ),
+ QUIRK_PORT(LP8X4X_TTYS1_IOMEM, LP8X4X_TTYS1_IRQ),
+ QUIRK_PORT(LP8X4X_TTYS2_IOMEM, LP8X4X_TTYS2_IRQ),
+ { },
+};
+
+/* Total number of ports can be 35. The first 3 ports are on
+ * the device, the rest are on extension slots. Only the first 3
+ * require termios quirk */
+#define LP8X4X_QUIRK_PORTS 3
+
+static unsigned int extra_mem[LP8X4X_QUIRK_PORTS] = {
+ LP8X4X_TTYS0_QUIRK,
+ LP8X4X_TTYS1_QUIRK,
+ LP8X4X_TTYS2_QUIRK
+};
+
+static int request_and_remap(int i)
+{
+ if (!request_mem_region(extra_mem[i], 1, "serial"))
+ return -EBUSY;
+
+ lp8x4x_data[i].private_data = ioremap(extra_mem[i], 1);
+ if (lp8x4x_data[i].private_data)
+ return 0;
+
+ release_mem_region(extra_mem[i], 1);
+ return -ENODEV;
+}
+
+static void release_and_unmap(int i)
+{
+ iounmap((void *) lp8x4x_data[i].private_data);
+ release_mem_region(extra_mem[i], 1);
+}
+
+static struct platform_device lp8x4x_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_ACCENT,
+ .dev = {
+ .platform_data = lp8x4x_data,
+ },
+};
+
+static int __init lp8x4x_init(void)
+{
+ int i = 0;
+ int err = 0;
+
+ for (i = 0; i < LP8X4X_QUIRK_PORTS; i++) {
+ err = request_and_remap(i);
+ if (err == 0)
+ continue;
+
+ for (; i >= 0; i--)
+ release_and_unmap(i);
+ lp8x4x_device.dev.platform_data = NULL;
+ return err;
+ }
+ return platform_device_register(&lp8x4x_device);
+}
+
+module_init(lp8x4x_init);
+
+MODULE_AUTHOR("Sergei Ianovich");
+MODULE_DESCRIPTION("8250 serial port module for LP-8x4x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index f3b306e..30b9af4 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -237,6 +237,17 @@ config SERIAL_8250_HUB6
To compile this driver as a module, choose M here: the module
will be called 8250_hub6.

+config SERIAL_8250_LP8X4X
+ tristate "Support 8250 ports on ICP DAS LP-8x4x"
+ depends on SERIAL_8250 != n && SERIAL_8250_MANY_PORTS && MACH_LP8X4X
+ help
+ In addition on serial ports on PXA270 SoC, LP-8x4x has 1 dual
+ RS232/RS485 port, 1 RS485 port and 1 RS232 port serial ports.
+
+ Say N here, unless you plan to run this kernel on a LP-8x4x system.
+
+ If you choose M, the module will be called 8250_lp8x4x.
+
#
# Misc. options/drivers.
#
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 36d68d0..451c558 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
+obj-$(CONFIG_SERIAL_8250_LP8X4X) += 8250_lp8x4x.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
This provides an MTD device driver for 512kB of battery backed up SRAM
on ICPDAS LP-8X4X programmable automation controllers.

SRAM chip is connected via FPGA and is not accessible without a driver,
unlike flash memory which is wired to CPU MMU.

This SRAM becomes an excellent persisent storage of volatile process
data like counter values and sensor statuses. Storing those data in
flash or mmc card is not a viable solution.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
arch/arm/configs/lp8x4x_defconfig | 1 +
arch/arm/mach-pxa/include/mach/lp8x4x.h | 2 +
arch/arm/mach-pxa/lp8x4x.c | 26 ++++
drivers/mtd/devices/Kconfig | 13 ++
drivers/mtd/devices/Makefile | 1 +
drivers/mtd/devices/lp8x4x_sram.c | 229 ++++++++++++++++++++++++++++++++
6 files changed, 272 insertions(+)
create mode 100644 drivers/mtd/devices/lp8x4x_sram.c

diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
index 27831e4..03c85bc 100644
--- a/arch/arm/configs/lp8x4x_defconfig
+++ b/arch/arm/configs/lp8x4x_defconfig
@@ -874,6 +874,7 @@ CONFIG_MTD_PXA2XX=y
# Disk-On-Chip Device Drivers
#
# CONFIG_MTD_DOCG3 is not set
+CONFIG_MTD_LP8X4X_SRAM=y
# CONFIG_MTD_NAND is not set
# CONFIG_MTD_ONENAND is not set

diff --git a/arch/arm/mach-pxa/include/mach/lp8x4x.h b/arch/arm/mach-pxa/include/mach/lp8x4x.h
index d8a1376..a49df22 100644
--- a/arch/arm/mach-pxa/include/mach/lp8x4x.h
+++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h
@@ -49,6 +49,8 @@
#define LP8X4X_ENFALLINT LP8X4X_P2V(0x17009018)
#define LP8X4X_CLRFALLINT LP8X4X_P2V(0x1700901a)
#define LP8X4X_RWRTC LP8X4X_P2V(0x1700901c)
+#define LP8X4X_SRAMBANK 0x1700901e
+#define LP8X4X_SRAM 0x1700a000

/* board specific IRQs */

diff --git a/arch/arm/mach-pxa/lp8x4x.c b/arch/arm/mach-pxa/lp8x4x.c
index a31b556..47a8776 100644
--- a/arch/arm/mach-pxa/lp8x4x.c
+++ b/arch/arm/mach-pxa/lp8x4x.c
@@ -234,6 +234,17 @@ static struct resource lp8x4x_flash_resources[] = {
.end = PXA_CS1_PHYS + SZ_32M - 1,
.flags = IORESOURCE_MEM,
},
+ [2] = {
+ .start = LP8X4X_SRAMBANK,
+ .end = LP8X4X_SRAMBANK + 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [3] = {
+ .start = LP8X4X_SRAM,
+ .end = LP8X4X_SRAM + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+
};

static struct mtd_partition lp8x4x_flash0_partitions[] = {
@@ -267,6 +278,10 @@ static struct flash_platform_data lp8x4x_flash_data[] = {
.parts = NULL,
.nr_parts = 0,
.width = 2,
+ }, {
+ .parts = NULL,
+ .nr_parts = 0,
+ .width = 1,
}
};

@@ -289,6 +304,16 @@ static struct platform_device lp8x4x_flash_device[] = {
.resource = &lp8x4x_flash_resources[1],
.num_resources = 1,
},
+ {
+ .name = "lp8x4x-sram",
+ .id = 0,
+ .dev = {
+ .platform_data = &lp8x4x_flash_data[2],
+ },
+ .resource = &lp8x4x_flash_resources[2],
+ .num_resources = 2,
+ },
+
};

static struct pxafb_mode_info lp8x4x_vga_60_mode = {
@@ -396,6 +421,7 @@ static struct platform_device lp8x4x_ds1302_device[] = {
static struct platform_device *lp8x4x_devices[] __initdata = {
&lp8x4x_flash_device[0],
&lp8x4x_flash_device[1],
+ &lp8x4x_flash_device[2],
&lp8x4x_dm9000_device[0],
&lp8x4x_dm9000_device[1],
&lp8x4x_ds1302_device[0],
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 0128138..7da0c21 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -217,4 +217,17 @@ config BCH_CONST_T
default 4
endif

+config MTD_LP8X4X_SRAM
+ tristate "SRAM on ICPDAS LP-8X4X"
+ ---help---
+ This provides an MTD device driver for 512kB of battery backed up SRAM
+ on ICPDAS LP-8X4X programmable automation controllers.
+
+ SRAM chip is connected via FPGA and is not accessible without a driver,
+ unlike flash memory which is wired to CPU MMU.
+
+ Say N, unless you plan to run this kernel on LP-8X4X.
+
+ If you say M, the module will be called lp8x4x_sram.
+
endmenu
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index d83bd73..8c5d9b0 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
obj-$(CONFIG_MTD_SST25L) += sst25l.o
obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
+obj-$(CONFIG_MTD_LP8X4X_SRAM) += lp8x4x_sram.o


CFLAGS_docg3.o += -I$(src)
diff --git a/drivers/mtd/devices/lp8x4x_sram.c b/drivers/mtd/devices/lp8x4x_sram.c
new file mode 100644
index 0000000..8fe625d
--- /dev/null
+++ b/drivers/mtd/devices/lp8x4x_sram.c
@@ -0,0 +1,229 @@
+/*
+ * linux/drivers/mtd/devices/lp8x4x_sram.c
+ *
+ * MTD Driver for SRAM on ICPDAS LP-8x4x
+ * Copyright (C) 2013 Sergei Ianovich <ynv...@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation or any later version.
+ */
+
+#include <linux/string_helpers.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+#include <asm/mach/flash.h>
+
+struct lp8x4x_sram_info {
+ void __iomem *bank;
+ void __iomem *virt;
+ struct mutex lock;
+ unsigned active_bank;
+ struct mtd_info mtd;
+};
+
+static int
+lp8x4x_sram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct lp8x4x_sram_info *info = mtd->priv;
+ unsigned bank = instr->addr >> 11;
+ unsigned offset = (instr->addr & 0x7ff) << 1;
+ loff_t i;
+
+ mutex_lock(&info->lock);
+ if (unlikely(bank != info->active_bank)) {
+ info->active_bank = bank;
+ iowrite8(bank, info->bank);
+ }
+ for (i = 0; i < instr->len; i++) {
+ iowrite8(0xff, info->virt + offset);
+ offset += 2;
+ if (unlikely(offset == 0)) {
+ info->active_bank++;
+ iowrite8(info->active_bank, info->bank);
+ }
+ }
+ mutex_unlock(&info->lock);
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
+}
+
+static int
+lp8x4x_sram_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *b)
+{
+ struct lp8x4x_sram_info *info = mtd->priv;
+ unsigned bank = to >> 11;
+ unsigned offset = (to & 0x7ff) << 1;
+ loff_t i;
+
+ mutex_lock(&info->lock);
+ if (unlikely(bank != info->active_bank)) {
+ info->active_bank = bank;
+ iowrite8(bank, info->bank);
+ }
+ for (i = 0; i < len; i++) {
+ iowrite8(b[i], info->virt + offset);
+ offset += 2;
+ if (unlikely(offset == 0)) {
+ info->active_bank++;
+ iowrite8(info->active_bank, info->bank);
+ }
+ }
+ mutex_unlock(&info->lock);
+ *retlen = len;
+ return 0;
+}
+
+static int
+lp8x4x_sram_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *b)
+{
+ struct lp8x4x_sram_info *info = mtd->priv;
+ unsigned bank = from >> 11;
+ unsigned offset = (from & 0x7ff) << 1;
+ loff_t i;
+
+ mutex_lock(&info->lock);
+ if (unlikely(bank != info->active_bank)) {
+ info->active_bank = bank;
+ iowrite8(bank, info->bank);
+ }
+ for (i = 0; i < len; i++) {
+ b[i] = ioread8(info->virt + offset);
+ offset += 2;
+ if (unlikely(offset == 0)) {
+ info->active_bank++;
+ iowrite8(info->active_bank, info->bank);
+ }
+ }
+ mutex_unlock(&info->lock);
+ *retlen = len;
+ return 0;
+}
+
+static void
+lp8x4x_sram_sync(struct mtd_info *mtd)
+{
+}
+
+static const char const *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+static int
+lp8x4x_sram_probe(struct platform_device *pdev)
+{
+ struct flash_platform_data *flash = pdev->dev.platform_data;
+ struct lp8x4x_sram_info *info;
+ struct resource *res;
+ char sz_str[16];
+ int err = 0;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENODEV;
+ goto err1;
+ }
+
+ info->bank = ioremap(res->start, resource_size(res));
+ if (!info->bank) {
+ dev_err(&pdev->dev, "Failed to ioremap %p\n",
+ info->bank);
+ err = -EFAULT;
+ goto err1;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ err = -ENODEV;
+ goto err2;
+ }
+
+ info->virt = ioremap(res->start, resource_size(res));
+ if (!info->virt) {
+ dev_err(&pdev->dev, "Failed to ioremap %p\n",
+ info->virt);
+ err = -EFAULT;
+ goto err2;
+ }
+
+ info->mtd.priv = info;
+ info->mtd.name = "SRAM";
+ info->mtd.type = MTD_RAM;
+ info->mtd.flags = MTD_CAP_RAM;
+ info->mtd.size = resource_size(res) << 7;
+ info->mtd.erasesize = 512;
+ info->mtd.writesize = 4;
+ info->mtd._erase = lp8x4x_sram_erase;
+ info->mtd._write = lp8x4x_sram_write;
+ info->mtd._read = lp8x4x_sram_read;
+ info->mtd._sync = lp8x4x_sram_sync;
+ info->mtd.owner = THIS_MODULE;
+
+ err = mtd_device_parse_register(&info->mtd, probes, NULL, flash->parts,
+ flash->nr_parts);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Failed to register device\n");
+ goto err3;
+ }
+
+ mutex_init(&info->lock);
+ iowrite8(info->active_bank, info->bank);
+ platform_set_drvdata(pdev, info);
+ string_get_size(info->mtd.size, STRING_UNITS_2, sz_str,
+ sizeof(sz_str));
+ dev_info(&pdev->dev, "using %s SRAM on LP-8X4X as %s\n", sz_str,
+ dev_name(&info->mtd.dev));
+ return 0;
+err3:
+ iounmap(info->virt);
+err2:
+ iounmap(info->bank);
+err1:
+ kfree(info);
+ return err;
+}
+
+static int
+lp8x4x_sram_remove(struct platform_device *dev)
+{
+ struct lp8x4x_sram_info *info = platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+ mtd_device_unregister(&info->mtd);
+ iounmap(info->virt);
+ iounmap(info->bank);
+ kfree(info);
+ return 0;
+}
+
+static struct platform_driver lp8x4x_sram_driver = {
+ .driver = {
+ .name = "lp8x4x-sram",
+ .owner = THIS_MODULE,
+ },
+ .probe = lp8x4x_sram_probe,
+ .remove = lp8x4x_sram_remove,
+};
+
+module_platform_driver(lp8x4x_sram_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sergei Ianovich <ynv...@gmail.com>");
+MODULE_DESCRIPTION("MTD driver for SRAM on ICPDAS LP-8x4x");

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
This patch implements probing for the bus and reporting the number
of available expansion slots.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
Documentation/misc-devices/lp8x4x_bus.txt | 30 ++++++
arch/arm/configs/lp8x4x_defconfig | 1 +
arch/arm/mach-pxa/include/mach/lp8x4x.h | 1 +
arch/arm/mach-pxa/lp8x4x.c | 18 ++++
drivers/misc/Kconfig | 12 +++
drivers/misc/Makefile | 1 +
drivers/misc/lp8x4x_bus.c | 165 ++++++++++++++++++++++++++++++
7 files changed, 228 insertions(+)
create mode 100644 Documentation/misc-devices/lp8x4x_bus.txt
create mode 100644 drivers/misc/lp8x4x_bus.c

diff --git a/Documentation/misc-devices/lp8x4x_bus.txt b/Documentation/misc-devices/lp8x4x_bus.txt
new file mode 100644
index 0000000..f5392b3
--- /dev/null
+++ b/Documentation/misc-devices/lp8x4x_bus.txt
@@ -0,0 +1,30 @@
+Kernel driver lpx8x4x_bus
+======================
+
+Supported hardare:
+Custom parallel bus on ICP DAS LP-8x4x industrial computers
+
+Data sheet:
+Not freely available
+
+Author:
+Sergei Ianovich <ynv...@gmail.com>
+
+Description
+-----------
+
+http://www.icpdas.com/root/product/solutions/pac/linpac/lp-8x4x_hardware.html
+
+LP-8x4x is an ARM-based industrial computer with a custom parallel bus to
+connect expansion modules with digital input/output, analog input/output,
+serial, CAN and other types of ports.
+
+The bus is implemented by a FPGA.
+
+SYSFS
+-----
+
+/sys/bus/icpdas/devices/backplane:
+
+slot_count
+ RO - shows total number of expansion slots on the device
diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
index d297a67..5f2b842 100644
--- a/arch/arm/configs/lp8x4x_defconfig
+++ b/arch/arm/configs/lp8x4x_defconfig
@@ -921,6 +921,7 @@ CONFIG_BLK_DEV_LOOP_MIN_COUNT=2
# CONFIG_BMP085_I2C is not set
# CONFIG_USB_SWITCH_FSA9480 is not set
# CONFIG_SRAM is not set
+CONFIG_LP8X4X_BUS=m
# CONFIG_C2PORT is not set

#
diff --git a/arch/arm/mach-pxa/include/mach/lp8x4x.h b/arch/arm/mach-pxa/include/mach/lp8x4x.h
index 4d5474e..5d289bf 100644
--- a/arch/arm/mach-pxa/include/mach/lp8x4x.h
+++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h
@@ -53,6 +53,7 @@
#define LP8X4X_TTYS0_QUIRK 0x17009030
#define LP8X4X_TTYS1_QUIRK 0x17009032
#define LP8X4X_TTYS2_QUIRK 0x17009034
+#define LP8X4X_MOD_NUM 0x17009046
#define LP8X4X_TTYS0_IOMEM 0x17009050
#define LP8X4X_TTYS1_IOMEM 0x17009060
#define LP8X4X_TTYS2_IOMEM 0x17009070
diff --git a/arch/arm/mach-pxa/lp8x4x.c b/arch/arm/mach-pxa/lp8x4x.c
index 47a8776..38482d3 100644
--- a/arch/arm/mach-pxa/lp8x4x.c
+++ b/arch/arm/mach-pxa/lp8x4x.c
@@ -418,6 +418,23 @@ static struct platform_device lp8x4x_ds1302_device[] = {
},
};

+static struct resource lp8x4x_bus_resources[] = {
+ [0] = {
+ .start = LP8X4X_MOD_NUM,
+ .end = LP8X4X_MOD_NUM,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device lp8x4x_bus_device[] = {
+ {
+ .name = "lp8x4x-bus",
+ .id = 0,
+ .resource = &lp8x4x_bus_resources[0],
+ .num_resources = 1,
+ },
+};
+
static struct platform_device *lp8x4x_devices[] __initdata = {
&lp8x4x_flash_device[0],
&lp8x4x_flash_device[1],
@@ -425,6 +442,7 @@ static struct platform_device *lp8x4x_devices[] __initdata = {
&lp8x4x_dm9000_device[0],
&lp8x4x_dm9000_device[1],
&lp8x4x_ds1302_device[0],
+ &lp8x4x_bus_device[0],
};

static struct pxaohci_platform_data lp8x4x_ohci_platform_data = {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a3e291d..85676c4 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -515,6 +515,18 @@ config SRAM
the genalloc API. It is supposed to be used for small on-chip SRAM
areas found on many SoCs.

+config LP8X4X_BUS
+ tristate "ICP DAS LP-8x4x industrial IO bus"
+ depends on MACH_LP8X4X && SYSFS
+ ---help---
+ This is a driver for ICP DAS LP-8x4x programmable automation
+ controller. It exposes a custom parallel bus. The bus services
+ data acquisition and control modules.
+
+ Say N, unless you plan to run this kernel on a LP-8x4x system.
+
+ If you say M here, the module will be called lp8x4x_bus.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f45473e..7578cff 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/
+obj-$(CONFIG_LP8X4X_BUS) += lp8x4x_bus.o
diff --git a/drivers/misc/lp8x4x_bus.c b/drivers/misc/lp8x4x_bus.c
new file mode 100644
index 0000000..9cd840e
--- /dev/null
+++ b/drivers/misc/lp8x4x_bus.c
@@ -0,0 +1,165 @@
+/*
+ * linux/misc/lp8x4x_bus.c
+ *
+ * Support for ICP DAS LP-8x4x programmable automation controller bus
+ * Copyright (C) 2013 Sergei Ianovich <ynv...@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation or any later version.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+#include <mach/mfp-pxa27x.h>
+#include <mach/lp8x4x.h>
+#include <asm/system_info.h>
+
+#define MODULE_NAME "lp8x4x-bus"
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sergei Ianovich <ynv...@gmail.com>");
+MODULE_DESCRIPTION("ICP DAS LP-8x4x parallel bus driver");
+
+struct lp8x4x_master {
+ unsigned int slot_count;
+ void *count_addr;
+ struct device dev;
+};
+
+static int lp8x4x_match(struct device *dev, struct device_driver *drv)
+{
+ return 1;
+}
+
+static struct bus_type lp8x4x_bus_type = {
+ .name = "icpdas",
+ .match = lp8x4x_match,
+};
+
+static void lp8x4x_master_release(struct device *dev)
+{
+ struct lp8x4x_master *m = container_of(dev, struct lp8x4x_master, dev);
+ BUG_ON(!dev);
+
+ kfree(m);
+}
+
+static ssize_t slot_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lp8x4x_master *m = container_of(dev, struct lp8x4x_master, dev);
+
+ return sprintf(buf, "%u\n", m->slot_count);
+}
+
+static DEVICE_ATTR_RO(slot_count);
+
+static struct attribute *master_dev_attrs[] = {
+ &dev_attr_slot_count.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(master_dev);
+
+
+static void devm_lp8x4x_bus_release(struct device *dev, void *res)
+{
+ struct lp8x4x_master *m = *(struct lp8x4x_master **)res;
+ void *mem = m->count_addr;
+
+ dev_info(dev, "releasing devices\n");
+ device_unregister(&m->dev);
+ bus_unregister(&lp8x4x_bus_type);
+ iounmap(mem);
+}
+
+static int __init lp8x4x_bus_probe(struct platform_device *pdev)
+{
+ struct lp8x4x_master *m, **p;
+ struct resource *res;
+ int err = 0;
+
+ m = kzalloc(sizeof(*m), GFP_KERNEL);
+ if (!m)
+ return -ENOMEM;
+
+ p = devres_alloc(devm_lp8x4x_bus_release, sizeof(*p), GFP_KERNEL);
+ if (!m) {
+ err = -ENOMEM;
+ goto err1;
+ }
+ *p = m;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENODEV;
+ goto err2;
+ }
+
+ m->count_addr = ioremap(res->start, resource_size(res));
+ if (!m->count_addr) {
+ dev_err(&pdev->dev, "Failed to ioremap %p\n",
+ m->count_addr);
+ err = -EFAULT;
+ goto err2;
+ }
+
+ m->slot_count = ioread8(m->count_addr);
+ switch (m->slot_count) {
+ case 1:
+ case 4:
+ break;
+ case 7:
+ m->slot_count = 8;
+ break;
+ default:
+ dev_info(&pdev->dev, "unexpected slot number(%u)",
+ m->slot_count);
+ goto err3;
+ };
+
+ dev_info(&pdev->dev, "found bus with up to %u slots\n", m->slot_count);
+
+ err = bus_register(&lp8x4x_bus_type);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to register bus type\n");
+ goto err3;
+ }
+
+ m->dev.bus = &lp8x4x_bus_type;
+ dev_set_name(&m->dev, "backplane");
+ m->dev.parent = &pdev->dev;
+ m->dev.release = lp8x4x_master_release;
+ m->dev.groups = master_dev_groups;
+
+ err = device_register(&m->dev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to register backplane device\n");
+ goto err4;
+ }
+
+ devres_add(&pdev->dev, p);
+ return 0;
+
+err4:
+ bus_unregister(&lp8x4x_bus_type);
+err3:
+ iounmap(m->count_addr);
+err2:
+ devres_free(p);
+err1:
+ kfree(m);
+ return err;
+}
+
+static struct platform_driver lp8x4x_bus_driver = {
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver_probe(lp8x4x_bus_driver, lp8x4x_bus_probe);

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
Status of I-8042 4 analog output channels can be managed via
sysfs.

http://www.icpdas.com/root/product/solutions/remote_io/rs-485/i-8k_i-87k/i-8024w.html

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
Documentation/misc-devices/lp8x4x_bus.txt | 15 ++++++
drivers/misc/lp8x4x_bus.c | 89 +++++++++++++++++++++++++++++++
2 files changed, 104 insertions(+)

diff --git a/Documentation/misc-devices/lp8x4x_bus.txt b/Documentation/misc-devices/lp8x4x_bus.txt
index e3a8bcf..08419d1 100644
--- a/Documentation/misc-devices/lp8x4x_bus.txt
+++ b/Documentation/misc-devices/lp8x4x_bus.txt
@@ -57,3 +57,18 @@ input_status
output_status
RW - set status of digital output channels on the module in
the expansion slot. Value can be read back.
+
+analog_output
+ RW - set status of analog output channels on the module in
+ the expansion slot. Tested with voltage output. Bits 0-13:
+ 0x00c0 is -10.0V
+ 0x2000 is 0.0V
+ 0x3f40 is +10.0V
+
+ So 1 unit of output is 1.25 mV.
+
+ Bits 15 and 14 determine which channel to apply the value:
+ 0x0000 is channel 1
+ 0x4000 is channel 2
+ 0x8000 is channel 3
+ 0xc000 is channel 4
diff --git a/drivers/misc/lp8x4x_bus.c b/drivers/misc/lp8x4x_bus.c
index fce11c4..0fa13a3 100644
--- a/drivers/misc/lp8x4x_bus.c
+++ b/drivers/misc/lp8x4x_bus.c
@@ -14,6 +14,8 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/hrtimer.h>

#include <mach/mfp-pxa27x.h>
#include <mach/lp8x4x.h>
@@ -24,6 +26,7 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sergei Ianovich <ynv...@gmail.com>");
MODULE_DESCRIPTION("ICP DAS LP-8x4x parallel bus driver");

+#define LP8X4X_MAX_AO_CHANNELS 4
struct lp8x4x_slot {
void *data_addr;
unsigned int model;
@@ -32,6 +35,8 @@ struct lp8x4x_slot {
u32 DO;
unsigned int DI_len;
u32 DI;
+ unsigned int AO_len;
+ u32 AO[LP8X4X_MAX_AO_CHANNELS];
struct device dev;
};

@@ -118,6 +123,36 @@ static void lp8x4x_slot_set_DO(struct lp8x4x_slot *s)
mutex_unlock(&s->lock);
}

+void nsleep(unsigned long nanosec)
+{
+ ktime_t t = ns_to_ktime(nanosec);
+ long state = current->state;
+
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&t, HRTIMER_MODE_REL);
+ __set_current_state(state);
+}
+
+static void lp8x4x_slot_reset_AO(struct lp8x4x_slot *s)
+{
+ int i;
+ mutex_lock(&s->lock);
+ for (i = 0; i < s->AO_len; i++)
+ s->AO[i] = 0x2000;
+ iowrite8(0x00, s->data_addr);
+ nsleep(450);
+ iowrite8(0xff, s->data_addr);
+ mutex_unlock(&s->lock);
+}
+
+static void lp8x4x_slot_set_AO(struct lp8x4x_slot *s, u32 val)
+{
+ mutex_lock(&s->lock);
+ iowrite8(val & 0xff, s->data_addr + 2);
+ iowrite8((val >> 8) & 0xff, s->data_addr + 4);
+ mutex_unlock(&s->lock);
+}
+
static ssize_t input_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -189,6 +224,48 @@ static ssize_t output_status_store(struct device *dev,

static DEVICE_ATTR_RW(output_status);

+static ssize_t analog_output_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lp8x4x_slot *s = container_of(dev, struct lp8x4x_slot, dev);
+ int i, c = 0;
+
+ for (i = 0; i < s->AO_len; i++)
+ c += sprintf(&buf[c], "0x%04x\n", s->AO[i]);
+ return c;
+}
+
+static ssize_t analog_output_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lp8x4x_slot *s = container_of(dev, struct lp8x4x_slot, dev);
+ u32 AO;
+ int i;
+
+ if (!buf)
+ return count;
+ if (0 == count)
+ return count;
+
+ if (kstrtouint(buf, 16, &AO) != 0) {
+ dev_err(dev, "bad input\n");
+ return count;
+ }
+
+ if (AO & 0xffff0000) {
+ dev_err(dev, "bad input\n");
+ return count;
+ }
+
+ i = AO >> 14;
+ s->AO[i] = AO & 0x3fff;
+ lp8x4x_slot_set_AO(s, AO);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(analog_output);
+
static ssize_t model_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -220,6 +297,13 @@ static struct attribute *dio_slot_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(dio_slot_dev);

+static struct attribute *ao_slot_dev_attrs[] = {
+ &dev_attr_model.attr,
+ &dev_attr_analog_output.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(ao_slot_dev);
+
static void lp8x4x_master_release(struct device *dev)
{
struct lp8x4x_master *m = container_of(dev, struct lp8x4x_master, dev);
@@ -324,6 +408,11 @@ static void __init lp8x4x_bus_probe_slot(struct lp8x4x_master *m, int i,
mutex_init(&s->lock);

switch (model) {
+ case 24:
+ s->AO_len = 4;
+ lp8x4x_slot_reset_AO(s);
+ s->dev.groups = ao_slot_dev_groups;
+ break;
case 41:
s->DO_len = 4;
lp8x4x_slot_set_DO(s);

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
ICP DAS calls LP-8x4x 'programmable automation controller'. It is
an industrial computer based on PXA270 SoC. They ship it with a 2.6.19
kernel and proprietary kernel module and userspace library to access
its industrial IO.

This patch allows to boot the device with a modern kernel. It adds
support for:
* FPGA irq chip
* MMC card interface on PXA270
* USB 1.1 port on PXA270
* 2 NOR flash devices
* VGA interface on PXA270
* 2 onboard ethernet Davicom DM9000 devices
* 3 serial UART ports on PXA270

Support for these devices will be added in separate patches, since
they are not currently supported by the kernel:
* DS1302 RTC
* 512kiB SRAM
* 3 built-in and up to 32 pluggable 8250 serial UART ports
* industrial IO parallel bus
* digital and analog industrial IO modules for parallel bus
* serial interface for digital and analog industrial IO modules on
parallel bus

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
arch/arm/configs/lp8x4x_defconfig | 2320 +++++++++++++++++++++++++++++++
arch/arm/mach-pxa/Kconfig | 16 +
arch/arm/mach-pxa/Makefile | 1 +
arch/arm/mach-pxa/include/mach/lp8x4x.h | 74 +
arch/arm/mach-pxa/lp8x4x.c | 460 ++++++
5 files changed, 2871 insertions(+)
create mode 100644 arch/arm/configs/lp8x4x_defconfig
create mode 100644 arch/arm/mach-pxa/include/mach/lp8x4x.h
create mode 100644 arch/arm/mach-pxa/lp8x4x.c

diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
new file mode 100644
index 0000000..5cd6d38
--- /dev/null
+++ b/arch/arm/configs/lp8x4x_defconfig
@@ -0,0 +1,2320 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.13.0-rc1 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+
+#
+# General setup
+#
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE="arm-linux-gnueabi-"
+# CONFIG_COMPILE_TEST is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_AUDIT is not set
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ_COMMON=y
+# CONFIG_HZ_PERIODIC is not set
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_PREEMPT_RCU=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RCU_FANOUT=32
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=1
+CONFIG_RCU_BOOST_DELAY=500
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GENERIC_SCHED_CLOCK=y
+# CONFIG_CGROUPS is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_HAVE_UID16=y
+CONFIG_EXPERT=y
+# CONFIG_UID16 is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_SHMEM is not set
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+# CONFIG_SLUB is not set
+CONFIG_SLOB=y
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_JUMP_LABEL=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OLD_SIGACTION=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULE_SIG is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+CONFIG_BLK_CMDLINE_PARSER=y
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_CMDLINE_PARTITION is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_MULTIPLATFORM is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_LPC32XX is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C24XX is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_GPIO_PCA953X is not set
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+
+#
+# Intel/Marvell Dev Platforms (sorted by hardware release time)
+#
+# CONFIG_MACH_PXA3XX_DT is not set
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_MACH_ZYLONITE300 is not set
+# CONFIG_MACH_ZYLONITE320 is not set
+# CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
+
+#
+# Third Party Dev Platforms (sorted by vendor name)
+#
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_VIPER is not set
+# CONFIG_MACH_ARCOM_ZEUS is not set
+# CONFIG_MACH_BALLOON3 is not set
+# CONFIG_MACH_CSB726 is not set
+# CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_EXEDA is not set
+# CONFIG_MACH_CM_X300 is not set
+# CONFIG_MACH_CAPC7117 is not set
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_MACH_INTELMOTE2 is not set
+# CONFIG_MACH_STARGATE2 is not set
+# CONFIG_MACH_XCEP is not set
+# CONFIG_TRIZEPS_PXA is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_PCM027 is not set
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_COLIBRI300 is not set
+# CONFIG_MACH_COLIBRI320 is not set
+# CONFIG_MACH_VPAC270 is not set
+
+#
+# End-user Products (sorted by vendor name)
+#
+CONFIG_MACH_LP8X4X=y
+# CONFIG_MACH_H4700 is not set
+# CONFIG_MACH_H5000 is not set
+# CONFIG_MACH_HIMALAYA is not set
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_MIOA701 is not set
+# CONFIG_PXA_EZX is not set
+# CONFIG_MACH_MP900C is not set
+# CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_MACH_RAUMFELD_RC is not set
+# CONFIG_MACH_RAUMFELD_CONNECTOR is not set
+# CONFIG_MACH_RAUMFELD_SPEAKER is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_MACH_ICONTROL is not set
+# CONFIG_ARCH_PXA_ESERIES is not set
+# CONFIG_MACH_ZIPIT2 is not set
+CONFIG_PXA27x=y
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_PLAT_PXA=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_USE_DOMAINS=y
+
+#
+# Processor Features
+#
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_NEED_KUSER_HELPERS=y
+CONFIG_KUSER_HELPERS=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_NR_BANKS=8
+CONFIG_IWMMXT=y
+CONFIG_MULTI_IRQ_HANDLER=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_ARCH_NR_GPIO=0
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+CONFIG_HZ_FIXED=0
+CONFIG_HZ_100=y
+# CONFIG_HZ_200 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_500 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+# CONFIG_HIGHMEM is not set
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+# CONFIG_COMPACTION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_CLEANCACHE is not set
+# CONFIG_CMA is not set
+# CONFIG_ZBUD is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_SWIOTLB=y
+CONFIG_IOMMU_HELPER=y
+
+#
+# Boot options
+#
+# CONFIG_USE_OF is not set
+CONFIG_ATAGS=y
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/sbin/init root=/dev/mmcblk0p1 rw rootfstype=ext4 console=ttySA0,115200 mem=128M rootwait"
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
+# CONFIG_CMDLINE_EXTEND is not set
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_AUTO_ZRELADDR=y
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# CPU Idle
+#
+# CONFIG_CPU_IDLE is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_BINFMT_SCRIPT=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_COREDUMP=y
+
+#
+# Power management options
+#
+# CONFIG_SUSPEND is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARM_CPU_SUSPEND is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=m
+CONFIG_UNIX=y
+CONFIG_UNIX_DIAG=m
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=m
+# CONFIG_XFRM_USER is not set
+CONFIG_XFRM_SUB_POLICY=y
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_CLASSID=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IP_TUNNEL=y
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_NET_IPVTI=m
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_UDP_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_IPV6_VTI is not set
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_GRE is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_ACCT is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=y
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_HL=m
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
+# CONFIG_NETFILTER_XT_TARGET_LOG is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ECN=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+CONFIG_NETFILTER_XT_MATCH_HL=y
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+# CONFIG_IP_NF_MATCH_RPFILTER is not set
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV6 is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_L2TP=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_STP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_VLAN_FILTERING is not set
+CONFIG_HAVE_NET_DSA=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_VLAN_8021Q_MVRP is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+CONFIG_LLC2=y
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+CONFIG_X25=y
+CONFIG_LAPB=m
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_HFSC=y
+CONFIG_NET_SCH_PRIO=y
+# CONFIG_NET_SCH_MULTIQ is not set
+CONFIG_NET_SCH_RED=y
+# CONFIG_NET_SCH_SFB is not set
+CONFIG_NET_SCH_SFQ=y
+CONFIG_NET_SCH_TEQL=y
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_GRED=y
+CONFIG_NET_SCH_DSMARK=y
+CONFIG_NET_SCH_NETEM=y
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_CHOKE is not set
+# CONFIG_NET_SCH_QFQ is not set
+# CONFIG_NET_SCH_CODEL is not set
+# CONFIG_NET_SCH_FQ_CODEL is not set
+# CONFIG_NET_SCH_FQ is not set
+CONFIG_NET_SCH_INGRESS=y
+# CONFIG_NET_SCH_PLUG is not set
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=y
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_ROUTE4=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=y
+CONFIG_NET_CLS_RSVP6=y
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_CLS_BPF is not set
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_IPT=m
+# CONFIG_NET_ACT_NAT is not set
+CONFIG_NET_ACT_PEDIT=y
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+# CONFIG_NET_ACT_CSUM is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_HSR is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+# CONFIG_BPF_JIT is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+CONFIG_HAVE_BPF_JIT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+
+#
+# Bus devices
+#
+# CONFIG_ARM_CCI is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PXA2XX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOCG3 is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=2
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_BLK_DEV_RBD is not set
+
+#
+# Misc devices
+#
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ATMEL_PWM is not set
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ATMEL_SSC is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_SRAM is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_ALTERA_STAPL is not set
+
+#
+# Intel MIC Host Driver
+#
+
+#
+# Intel MIC Card Driver
+#
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_TARGET_CORE is not set
+CONFIG_NETDEVICES=y
+CONFIG_MII=m
+CONFIG_NET_CORE=y
+CONFIG_BONDING=m
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_IFB is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_VXLAN is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_NLMON is not set
+
+#
+# CAIF transport drivers
+#
+
+#
+# Distributed Switch Architecture drivers
+#
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
+CONFIG_ETHERNET=y
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_CALXEDA_XGMAC is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+CONFIG_DM9000=m
+CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
+# CONFIG_DNET is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SH_ETH is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPPOE=m
+CONFIG_PPTP=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLHC=m
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_RTL8152 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+# CONFIG_INPUT_MATRIXKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=600
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+# CONFIG_DEVKMEM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
+CONFIG_SERIAL_8250_NR_UARTS=36
+CONFIG_SERIAL_8250_RUNTIME_UARTS=36
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+# CONFIG_SERIAL_8250_DW is not set
+# CONFIG_SERIAL_8250_EM is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_PXA_AS_TTYSA=y
+# CONFIG_SERIAL_SH_SCI is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_ST_ASC is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_HW_RANDOM_ATMEL is not set
+# CONFIG_HW_RANDOM_EXYNOS is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_CBUS_GPIO is not set
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+CONFIG_I2C_PXA=m
+# CONFIG_I2C_PXA_PCI is not set
+CONFIG_I2C_PXA_SLAVE=y
+# CONFIG_I2C_SH_MOBILE is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I2C_RCAR is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+# CONFIG_PTP_1588_CLOCK is not set
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO drivers:
+#
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+CONFIG_GPIO_PXA=y
+# CONFIG_GPIO_RCAR is not set
+# CONFIG_GPIO_TS5500 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MCP23S08 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# LPC GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+
+#
+# USB GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_CORE is not set
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SA1100_WATCHDOG=m
+# CONFIG_DW_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_MEN_A21_WDT is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_VEXPRESS_CONFIG is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=m
+# CONFIG_FB_PXA_OVERLAY is not set
+# CONFIG_FB_PXA_SMARTPANEL is not set
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_PXA3XX_GCU is not set
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_W100 is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_GOLDFISH is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_EXYNOS_VIDEO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=m
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+
+#
+# HID support
+#
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=m
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=m
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+CONFIG_HID_CYPRESS=m
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_HUION is not set
+CONFIG_HID_KEYTOUCH=m
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=m
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO_TPKBD is not set
+CONFIG_HID_LOGITECH=m
+# CONFIG_HID_LOGITECH_DJ is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+# CONFIG_HID_MAGICMOUSE is not set
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=m
+# CONFIG_HID_PID is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+
+#
+# I2C HID support
+#
+CONFIG_I2C_HID=m
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=m
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_FUSBH200_HCD is not set
+# CONFIG_USB_FOTG210_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_HCD_PXA27X=m
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_DWC3 is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_WWAN=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_ZTE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+CONFIG_USB_EZUSB_FX2=m
+# CONFIG_USB_HSIC_USB3503 is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_USB_PHY is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_AM335X_PHY_USB is not set
+# CONFIG_SAMSUNG_USB2PHY is not set
+# CONFIG_SAMSUNG_USB3PHY is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_RCAR_PHY is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_CLKGATE is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_PXA=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SDHCI_PXAV3 is not set
+# CONFIG_MMC_SDHCI_PXAV2 is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_SA1100 is not set
+# CONFIG_RTC_DRV_PXA is not set
+# CONFIG_RTC_DRV_MOXART is not set
+
+#
+# HID Sensor RTC drivers
+#
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_VIRT_DRIVERS is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_MMIO is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+# CONFIG_STAGING is not set
+CONFIG_CLKDEV_LOOKUP=y
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_CLKSRC_MMIO=y
+# CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set
+# CONFIG_MAILBOX is not set
+# CONFIG_IOMMU_SUPPORT is not set
+
+#
+# Remoteproc drivers
+#
+# CONFIG_STE_MODEM_RPROC is not set
+
+#
+# Rpmsg drivers
+#
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_EXTCON is not set
+# CONFIG_MEMORY is not set
+# CONFIG_IIO is not set
+# CONFIG_PWM is not set
+# CONFIG_IPACK_BUS is not set
+# CONFIG_RESET_CONTROLLER is not set
+# CONFIG_FMC is not set
+
+#
+# PHY Subsystem
+#
+# CONFIG_GENERIC_PHY is not set
+# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set
+# CONFIG_POWERCAP is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_FS_XIP=y
+CONFIG_JBD=y
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_F2FS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V2=m
+CONFIG_NFS_V3=m
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=m
+# CONFIG_NFS_SWAP is not set
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_PNFS_FILE_LAYOUT=m
+CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
+# CONFIG_NFS_V4_1_MIGRATION is not set
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_SUNRPC_BACKCHANNEL=y
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_DEBUG is not set
+# CONFIG_CEPH_FS is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_UPCALL is not set
+# CONFIG_CIFS_XATTR is not set
+CONFIG_CIFS_DEBUG=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_DFS_UPCALL is not set
+# CONFIG_CIFS_SMB2 is not set
+# CONFIG_NCP_FS is not set
+CONFIG_CODA_FS=m
+# CONFIG_AFS_FS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp1251"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+CONFIG_NLS_CODEPAGE_863=y
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+CONFIG_NLS_CODEPAGE_866=y
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+# CONFIG_NLS_CODEPAGE_1250 is not set
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Kernel hacking
+#
+
+#
+# printk and dmesg options
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+# CONFIG_BOOT_PRINTK_DELAY is not set
+
+#
+# Compile-time checks and compiler options
+#
+# CONFIG_DEBUG_INFO is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+
+#
+# Memory Debugging
+#
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_OBJECTS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_SHIRQ is not set
+
+#
+# Debug Lockups and Hangs
+#
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_PREEMPT is not set
+
+#
+# Lock Debugging (spinlocks, mutexes, etc...)
+#
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+
+#
+# RCU Debugging
+#
+# CONFIG_PROVE_RCU_DELAY is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+CONFIG_RCU_CPU_STALL_VERBOSE=y
+# CONFIG_RCU_CPU_STALL_INFO is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+
+#
+# Runtime Testing
+#
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_PERCPU_TEST is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_STRICT_DEVMEM is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+# CONFIG_DEBUG_UART_PL01X is not set
+# CONFIG_DEBUG_UART_8250 is not set
+CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_CMAC=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRCT10DIF is not set
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA1_ARM=y
+CONFIG_CRYPTO_SHA256=y
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_AES_ARM=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=y
+CONFIG_TEXTSEARCH_BM=y
+CONFIG_TEXTSEARCH_FSM=y
+CONFIG_ASSOCIATIVE_ARRAY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+CONFIG_OID_REGISTRY=m
+CONFIG_FONT_SUPPORT=m
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 96100db..efaf2d0 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -273,6 +273,22 @@ config MACH_VPAC270

comment "End-user Products (sorted by vendor name)"

+config MACH_LP8X4X
+ bool "ICP DAS LP-8X4X"
+ select IWMMXT
+ select PXA27x
+ help
+ Say Y here if you intend to run this kernel on an ICP DAS
+ LP-8x4x programmable automation controller.
+
+ LP-8x4x is ARM-based and built around PXA270 SoC. The device
+ has 128 MiB SDRAM, 48 or 96 MiB NOR flash, VGA port with
+ 800x600 resolution, MMC card slot, 2 Ethernet ports, 1 USB
+ port, 5 serial ports (1 on them is wired internally to
+ expansion slots). The device has a range of digital and
+ analog expansion IO modules which can be installed in 1, 4 or
+ 8 slots depending on the model.
+
config MACH_H4700
bool "HP iPAQ hx4700"
select HAVE_PWM
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 648867a..b264325 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_MACH_COLIBRI320) += colibri-pxa3xx.o colibri-pxa320.o
obj-$(CONFIG_MACH_VPAC270) += vpac270.o

# End-user Products
+obj-$(CONFIG_MACH_LP8X4X) += lp8x4x.o
obj-$(CONFIG_MACH_H4700) += hx4700.o
obj-$(CONFIG_MACH_H5000) += h5000.o
obj-$(CONFIG_MACH_HIMALAYA) += himalaya.o
diff --git a/arch/arm/mach-pxa/include/mach/lp8x4x.h b/arch/arm/mach-pxa/include/mach/lp8x4x.h
new file mode 100644
index 0000000..8c501fd
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h
@@ -0,0 +1,74 @@
+/*
+ * arch/arm/mach-pxa/include/mach/lp8x4x.h
+ *
+ * Support for ICP DAS LP-8x4x programmable automation controller
+ * Copyright (C) 2013 Sergei Ianovich <ynv...@gmail.com>
+ *
+ * borrowed heavily from
+ * Support for the Intel HCDDBBVA0 Development Platform.
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 14, 2002
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ASM_ARCH_LP8X4X_H
+#define ASM_ARCH_LP8X4X_H
+
+#include <asm/io.h>
+#include <mach/irqs.h>
+
+#define LP8X4X_ETH0_BASE 0x0c000000
+#define LP8X4X_ETH0_IO 0x0c004000
+#define LP8X4X_ETH0_IRQ PXA_GPIO_TO_IRQ(9)
+
+#define LP8X4X_ETH1_BASE 0x0d000000
+#define LP8X4X_ETH1_IO 0x0d004000
+#define LP8X4X_ETH1_IRQ PXA_GPIO_TO_IRQ(82)
+
+#define LP8X4X_FPGA_PHYS 0x17000000
+#define LP8X4X_FPGA_VIRT 0xf1000000
+#define LP8X4X_P2V(x) IOMEM((x) - LP8X4X_FPGA_PHYS + LP8X4X_FPGA_VIRT)
+#define LP8X4X_V2P(x) ((x) - LP8X4X_FPGA_VIRT + LP8X4X_FPGA_PHYS)
+
+/* board level registers in the FPGA */
+
+#define LP8X4X_EOI LP8X4X_P2V(0x17009006)
+#define LP8X4X_INSINT LP8X4X_P2V(0x17009008)
+#define LP8X4X_ENSYSINT LP8X4X_P2V(0x1700900A)
+#define LP8X4X_PRIMINT LP8X4X_P2V(0x1700900C)
+#define LP8X4X_SECOINT LP8X4X_P2V(0x1700900E)
+#define LP8X4X_ENRISEINT LP8X4X_P2V(0x17009010)
+#define LP8X4X_CLRRISEINT LP8X4X_P2V(0x17009012)
+#define LP8X4X_ENHILVINT LP8X4X_P2V(0x17009014)
+#define LP8X4X_CLRHILVINT LP8X4X_P2V(0x17009016)
+#define LP8X4X_ENFALLINT LP8X4X_P2V(0x17009018)
+#define LP8X4X_CLRFALLINT LP8X4X_P2V(0x1700901a)
+
+/* board specific IRQs */
+
+#define LP8X4X_IRQ(x) (IRQ_BOARD_START + (x))
+#define LP8X4X_SLOT1_IRQ LP8X4X_IRQ(0)
+#define LP8X4X_SLOT2_IRQ LP8X4X_IRQ(1)
+#define LP8X4X_SLOT3_IRQ LP8X4X_IRQ(2)
+#define LP8X4X_SLOT4_IRQ LP8X4X_IRQ(3)
+#define LP8X4X_SLOT5_IRQ LP8X4X_IRQ(4)
+#define LP8X4X_SLOT6_IRQ LP8X4X_IRQ(5)
+#define LP8X4X_SLOT7_IRQ LP8X4X_IRQ(6)
+#define LP8X4X_SLOT8_IRQ LP8X4X_IRQ(7)
+#define LP8X4X_TIMER1_IRQ LP8X4X_IRQ(8)
+#define LP8X4X_TIMER2_IRQ LP8X4X_IRQ(9)
+#define LP8X4X_TIMEROUT_IRQ LP8X4X_IRQ(10)
+#define LP8X4X_HOTPLUG_IRQ LP8X4X_IRQ(11)
+#define LP8X4X_BATLOW_IRQ LP8X4X_IRQ(12)
+#define LP8X4X_TTYS0_IRQ LP8X4X_IRQ(13)
+#define LP8X4X_TTYS1_IRQ LP8X4X_IRQ(14)
+#define LP8X4X_TTYS2_IRQ LP8X4X_IRQ(15)
+
+#define LP8X4X_NR_IRQS (IRQ_BOARD_START + 16)
+
+#endif
diff --git a/arch/arm/mach-pxa/lp8x4x.c b/arch/arm/mach-pxa/lp8x4x.c
new file mode 100644
index 0000000..0b77e7a
--- /dev/null
+++ b/arch/arm/mach-pxa/lp8x4x.c
@@ -0,0 +1,460 @@
+/*
+ * linux/arch/arm/mach-pxa/lp8x4x.c
+ *
+ * Support for ICP DAS LP-8x4x programmable automation controller
+ * Copyright (C) 2013 Sergei Ianovich <ynv...@gmail.com>
+ *
+ * borrowed heavily from
+ * Support for the Intel HCDDBBVA0 Development Platform.
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 05, 2002
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation or any later version.
+ */
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/syscore_ops.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/input.h>
+#include <linux/dm9000.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <linux/ktime.h>
+#include <linux/irqchip/chained_irq.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
+
+#include <mach/pxa27x.h>
+#include <mach/lp8x4x.h>
+#include <linux/platform_data/video-pxafb.h>
+#include <linux/platform_data/mmc-pxamci.h>
+#include <linux/platform_data/usb-ohci-pxa27x.h>
+#include <mach/smemc.h>
+
+#include "generic.h"
+#include "devices.h"
+
+static unsigned char lp8x4x_irq_sys_enabled;
+static unsigned char lp8x4x_irq_high_enabled;
+
+static void lp8x4x_ack_irq(struct irq_data *d)
+{
+ unsigned mask;
+ int irq = d->irq - IRQ_BOARD_START;
+
+ if (irq < 0 || irq > 15) {
+ pr_err("lp8x4x: wrong irq handler for irq %i\n", d->irq);
+ return;
+ }
+
+ if (irq < 8) {
+ mask = ioread8(LP8X4X_CLRHILVINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_CLRHILVINT);
+ } else if (irq < 13) {
+ irq -= 8;
+ mask = ioread8(LP8X4X_SECOINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_SECOINT);
+ } else {
+ irq -= 8;
+ mask = ioread8(LP8X4X_PRIMINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_PRIMINT);
+ }
+}
+
+static void lp8x4x_mask_irq(struct irq_data *d)
+{
+ int irq = d->irq - IRQ_BOARD_START;
+
+ if (irq < 0 || irq > 15) {
+ pr_err("lp8x4x: wrong irq handler for irq %i\n", d->irq);
+ return;
+ }
+
+ if (irq < 8) {
+ lp8x4x_irq_high_enabled &= ~(1 << irq);
+ iowrite8(lp8x4x_irq_high_enabled, LP8X4X_ENHILVINT);
+ } else {
+ irq -= 8;
+ lp8x4x_irq_sys_enabled &= ~(1 << irq);
+ iowrite8(lp8x4x_irq_sys_enabled, LP8X4X_ENSYSINT);
+ }
+}
+
+static void lp8x4x_unmask_irq(struct irq_data *d)
+{
+ unsigned mask;
+ int irq = d->irq - IRQ_BOARD_START;
+
+ if (irq < 0 || irq > 15) {
+ pr_err("wrong irq handler for irq %i\n", d->irq);
+ return;
+ }
+
+ if (irq < 8) {
+ lp8x4x_irq_high_enabled |= 1 << irq;
+ mask = ioread8(LP8X4X_CLRHILVINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_CLRHILVINT);
+ iowrite8(lp8x4x_irq_high_enabled, LP8X4X_ENHILVINT);
+ } else if (irq < 13) {
+ irq -= 8;
+ lp8x4x_irq_sys_enabled |= 1 << irq;
+ mask = ioread8(LP8X4X_SECOINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_SECOINT);
+ iowrite8(lp8x4x_irq_sys_enabled, LP8X4X_ENSYSINT);
+ } else {
+ irq -= 8;
+ lp8x4x_irq_sys_enabled |= 1 << irq;
+ mask = ioread8(LP8X4X_PRIMINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_PRIMINT);
+ iowrite8(lp8x4x_irq_sys_enabled, LP8X4X_ENSYSINT);
+ }
+}
+
+static struct irq_chip lp8x4x_irq_chip = {
+ .name = "FPGA",
+ .irq_ack = lp8x4x_ack_irq,
+ .irq_mask = lp8x4x_mask_irq,
+ .irq_unmask = lp8x4x_unmask_irq,
+};
+
+static spinlock_t fpga_irq_lock;
+
+static void lp8x4x_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ int loop, n;
+ unsigned long mask;
+ unsigned long flags;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ spin_lock_irqsave(&fpga_irq_lock, flags);
+ chained_irq_enter(chip, desc);
+
+ do {
+ loop = 0;
+ mask = ioread8(LP8X4X_CLRHILVINT) & 0xff;
+ mask |= (ioread8(LP8X4X_SECOINT) & 0x1f) << 8;
+ mask |= (ioread8(LP8X4X_PRIMINT) & 0xe0) << 8;
+ mask &= (lp8x4x_irq_high_enabled
+ | (lp8x4x_irq_sys_enabled << 8));
+ for_each_set_bit(n, &mask, BITS_PER_LONG) {
+ loop = 1;
+
+ generic_handle_irq(IRQ_BOARD_START + n);
+ }
+ } while (loop);
+
+ chained_irq_exit(chip, desc);
+ iowrite8(0, LP8X4X_EOI);
+ spin_unlock_irqrestore(&fpga_irq_lock, flags);
+}
+
+static void __init lp8x4x_init_irq(void)
+{
+ int irq;
+ int err;
+
+ err = irq_set_irq_type(PXA_GPIO_TO_IRQ(3), IRQ_TYPE_EDGE_RISING);
+ if (err < 0) {
+ pr_err("lp8x4x: irq init failed\n");
+ return;
+ }
+
+ spin_lock_init(&fpga_irq_lock);
+ irq_set_chained_handler(PXA_GPIO_TO_IRQ(3), lp8x4x_irq_handler);
+
+ for (irq = IRQ_BOARD_START; irq < LP8X4X_NR_IRQS; irq++) {
+ irq_set_chip_and_handler(irq, &lp8x4x_irq_chip,
+ handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+
+ iowrite8(0, LP8X4X_CLRRISEINT);
+ iowrite8(0, LP8X4X_ENRISEINT);
+ iowrite8(0, LP8X4X_CLRFALLINT);
+ iowrite8(0, LP8X4X_ENFALLINT);
+ iowrite8(0, LP8X4X_CLRHILVINT);
+ iowrite8(0, LP8X4X_ENHILVINT);
+ iowrite8(0, LP8X4X_ENSYSINT);
+ iowrite8(0, LP8X4X_PRIMINT);
+ iowrite8(0, LP8X4X_SECOINT);
+
+ return;
+}
+
+static unsigned long lp8x4x_pin_config[] = {
+ /* MMC */
+ GPIO32_MMC_CLK,
+ GPIO112_MMC_CMD,
+ GPIO92_MMC_DAT_0,
+ GPIO109_MMC_DAT_1,
+ GPIO110_MMC_DAT_2,
+ GPIO111_MMC_DAT_3,
+
+ /* USB Host Port 1 */
+ GPIO88_USBH1_PWR,
+ GPIO89_USBH1_PEN,
+};
+
+static struct resource lp8x4x_flash_resources[] = {
+ [0] = {
+ .start = PXA_CS0_PHYS,
+ .end = PXA_CS0_PHYS + SZ_64M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = PXA_CS1_PHYS,
+ .end = PXA_CS1_PHYS + SZ_32M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct mtd_partition lp8x4x_flash0_partitions[] = {
+ {
+ .name = "Bootloader",
+ .size = 0x00040000,
+ .offset = 0,
+ }, {
+ .name = "Settings",
+ .size = 0x00040000,
+ .offset = 0x00040000,
+ }, {
+ .name = "Kernel",
+ .size = 0x00280000,
+ .offset = 0x00080000,
+ }, {
+ .name = "Filesystem",
+ .size = MTDPART_SIZ_FULL,
+ .offset = 0x00300000
+ }
+};
+
+static struct flash_platform_data lp8x4x_flash_data[] = {
+ {
+ .map_name = "cfi_probe",
+ .parts = lp8x4x_flash0_partitions,
+ .nr_parts = ARRAY_SIZE(lp8x4x_flash0_partitions),
+ .width = 4,
+ }, {
+ .map_name = "cfi_probe",
+ .parts = NULL,
+ .nr_parts = 0,
+ .width = 2,
+ }
+};
+
+static struct platform_device lp8x4x_flash_device[] = {
+ {
+ .name = "pxa2xx-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &lp8x4x_flash_data[0],
+ },
+ .resource = &lp8x4x_flash_resources[0],
+ .num_resources = 1,
+ },
+ {
+ .name = "pxa2xx-flash",
+ .id = 1,
+ .dev = {
+ .platform_data = &lp8x4x_flash_data[1],
+ },
+ .resource = &lp8x4x_flash_resources[1],
+ .num_resources = 1,
+ },
+};
+
+static struct pxafb_mode_info lp8x4x_vga_60_mode = {
+ .pixclock = 38461,
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .hsync_len = 64,
+ .left_margin = 78,
+ .right_margin = 46,
+ .vsync_len = 12,
+ .upper_margin = 22,
+ .lower_margin = 10,
+ .sync = 0,
+};
+
+static struct pxafb_mach_info lp8x4x_pxafb_info = {
+ .num_modes = 1,
+ .lccr0 = LCCR0_Act,
+ .lccr3 = LCCR3_PCP,
+};
+
+static int lp8x4x_mci_init(struct device *dev,
+ irq_handler_t mstone_detect_int, void *data)
+{
+ return 0;
+}
+
+static int lp8x4x_mci_setpower(struct device *dev, unsigned int vdd)
+{
+ return 0;
+}
+
+static void lp8x4x_mci_exit(struct device *dev, void *data)
+{
+}
+
+static struct pxamci_platform_data lp8x4x_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = lp8x4x_mci_init,
+ .setpower = lp8x4x_mci_setpower,
+ .exit = lp8x4x_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
+};
+
+static struct resource lp8x4x_dm9000_resources[] = {
+ [0] = {
+ .start = LP8X4X_ETH0_BASE,
+ .end = LP8X4X_ETH0_BASE + 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = LP8X4X_ETH0_IO,
+ .end = LP8X4X_ETH0_IO + 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = LP8X4X_ETH0_IRQ,
+ .end = LP8X4X_ETH0_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ },
+ [3] = {
+ .start = LP8X4X_ETH1_BASE,
+ .end = LP8X4X_ETH1_BASE + 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [4] = {
+ .start = LP8X4X_ETH1_IO,
+ .end = LP8X4X_ETH1_IO + 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [5] = {
+ .start = LP8X4X_ETH1_IRQ,
+ .end = LP8X4X_ETH1_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ },
+};
+
+static struct platform_device lp8x4x_dm9000_device[2] = {
+ {
+ .name = "dm9000",
+ .id = 0,
+ .dev = {},
+ .resource = &lp8x4x_dm9000_resources[0],
+ .num_resources = 3,
+ },
+ {
+ .name = "dm9000",
+ .id = 1,
+ .dev = {},
+ .resource = &lp8x4x_dm9000_resources[3],
+ .num_resources = 3,
+ },
+};
+
+static struct platform_device *lp8x4x_devices[] __initdata = {
+ &lp8x4x_flash_device[0],
+ &lp8x4x_flash_device[1],
+ &lp8x4x_dm9000_device[0],
+ &lp8x4x_dm9000_device[1],
+};
+
+static struct pxaohci_platform_data lp8x4x_ohci_platform_data = {
+ .port_mode = PMM_PERPORT_MODE,
+ .flags = ENABLE_PORT1 | OC_MODE_PERPORT,
+};
+
+static void lp8x4x_restart(enum reboot_mode mode, const char *cmd)
+{
+ /* Switch off fast-bus and turbo mode */
+ asm volatile("mcr p14, 0, %0, c6, c0, 0" : :
+ "r"(2));
+ /* SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) */
+ pxa_restart(REBOOT_SOFT, cmd);
+}
+
+static void __init lp8x4x_init(void)
+{
+ pxa2xx_mfp_config(ARRAY_AND_SIZE(lp8x4x_pin_config));
+
+ pxa_set_ffuart_info(NULL);
+ pxa_set_btuart_info(NULL);
+ pxa_set_stuart_info(NULL);
+
+ /* system bus arbiter setting
+ * - Core_Park
+ * - LCD_wt:DMA_wt:CORE_Wt = 2:3:4
+ */
+ ARB_CNTRL = ARB_CORE_PARK | 0x234;
+
+ pxa_set_mci_info(&lp8x4x_mci_platform_data);
+ pxa_set_ohci_info(&lp8x4x_ohci_platform_data);
+
+ platform_add_devices(ARRAY_AND_SIZE(lp8x4x_devices));
+
+ lp8x4x_pxafb_info.modes = &lp8x4x_vga_60_mode;
+ pxa_set_fb_info(NULL, &lp8x4x_pxafb_info);
+
+ /* Could not do this in MACHINE since GPIO is not ready then */
+ lp8x4x_init_irq();
+}
+
+static struct map_desc lp8x4x_io_desc[] __initdata = {
+ { /* CPLD */
+ .virtual = LP8X4X_FPGA_VIRT,
+ .pfn = __phys_to_pfn(LP8X4X_FPGA_PHYS),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
+};
+
+static void __init lp8x4x_map_io(void)
+{
+ pxa27x_map_io();
+ iotable_init(lp8x4x_io_desc, ARRAY_SIZE(lp8x4x_io_desc));
+}
+
+MACHINE_START(LP8X4X, "ICP DAS LP-8x4x programmable automation controller")
+ .atag_offset = 0x100,
+ .map_io = lp8x4x_map_io,
+ .nr_irqs = LP8X4X_NR_IRQS,
+ .init_irq = pxa27x_init_irq,
+ .handle_irq = pxa27x_handle_irq,
+ .init_time = pxa_timer_init,
+ .init_machine = lp8x4x_init,
+ .restart = lp8x4x_restart,
+MACHINE_END

Sergei Ianovich

unread,
Dec 1, 2013, 1:30:02 AM12/1/13
to
ICP DAS calls LP-8x4x 'programmable automation controller'. It is
an industrial computer based on PXA270 SoC. They ship it with a 2.6.19
kernel and proprietary kernel module and userspace library to access its
industrial IO.

This patch series allows to boot the device with a modern kernel. It adds
support for:
* FPGA irq chip
* MMC card interface on PXA270
* USB 1.1 port on PXA270
* 2 NOR flash devices
* VGA interface on PXA270
* 2 onboard ethernet Davicom DM9000 devices
* 3 serial UART ports on PXA270
* DS1302 RTC
* 512kiB SRAM with double battery-backup
* 3 built-in 16550 serial UART ports
* industrial IO parallel bus
* serial interface for digital and analog industrial IO modules on
parallel bus (any I-870xx series)
* digital and analog industrial IO modules for parallel bus:
* I-8024 (analog output)
* I-8041 (digital output)
* I-8042 (digital input-output)

Sergei Ianovich (11):
resolve PXA<->8250 serial device address conflict
arm: pxa27x: support ICP DAS LP-8x4x
rtc: support DS1302 RTC on ICP DAS LP-8x4x
mtd: support BB SRAM on ICP DAS LP-8x4x
serial: support for 16550 serial ports on LP-8x4x
misc: support for LP-8x4x custom parallel bus
misc: support for serial slots in LP-8x4x
misc: support for parallel slots in LP-8x4x
misc: support for I-8041 in LP-8x4x
misc: support for I-8042 in LP-8x4x
misc: support for I-8024 in LP-8x4x

Documentation/misc-devices/lp8x4x_bus.txt | 74 +
arch/arm/configs/lp8x4x_defconfig | 2324 +++++++++++++++++++++++++++++
arch/arm/mach-pxa/Kconfig | 8 +
arch/arm/mach-pxa/Makefile | 1 +
arch/arm/mach-pxa/include/mach/lp8x4x.h | 95 ++
arch/arm/mach-pxa/lp8x4x.c | 557 +++++++
drivers/misc/Kconfig | 12 +
drivers/misc/Makefile | 1 +
drivers/misc/lp8x4x_bus.c | 581 ++++++++
drivers/mtd/devices/Kconfig | 13 +
drivers/mtd/devices/Makefile | 1 +
drivers/mtd/devices/lp8x4x_sram.c | 229 +++
drivers/rtc/Kconfig | 2 +-
drivers/rtc/rtc-ds1302.c | 85 ++
drivers/tty/serial/8250/8250_lp8x4x.c | 181 +++
drivers/tty/serial/8250/Kconfig | 11 +
drivers/tty/serial/8250/Makefile | 1 +
drivers/tty/serial/Kconfig | 19 +
drivers/tty/serial/pxa.c | 22 +-
19 files changed, 4212 insertions(+), 5 deletions(-)
create mode 100644 Documentation/misc-devices/lp8x4x_bus.txt
create mode 100644 arch/arm/configs/lp8x4x_defconfig
create mode 100644 arch/arm/mach-pxa/include/mach/lp8x4x.h
create mode 100644 arch/arm/mach-pxa/lp8x4x.c
create mode 100644 drivers/misc/lp8x4x_bus.c
create mode 100644 drivers/mtd/devices/lp8x4x_sram.c
create mode 100644 drivers/tty/serial/8250/8250_lp8x4x.c

Heikki Krogerus

unread,
Dec 2, 2013, 3:50:02 AM12/2/13
to
Hi,
<snip>
Instead of registering a platform device for serial8250 here, you need
to simply register a platform driver for something like lp8x4x_serial.
The platform code will to registers the platform devices for it. You
will use serial8250_register_8250_port() in your probe to register a
new port. Use 8250_em.c and 8250_dw.c under drivers/tty/serial/8250/
as an example.

You don't need to introduce plat_serial8250_port so you won't need
the QUIRK_PORT stuff. You deliver the iomem and the irq as normal
resources that the driver uses when you create the platform device.
That of course also means the driver does not need to care about the
instances. The platform code will generate a platform device for as
many ports you have and set to resources accordingly.


Thanks,

--
heikki

Heikki Krogerus

unread,
Dec 2, 2013, 4:10:01 AM12/2/13
to
Hi,

On Sun, Dec 01, 2013 at 10:26:14AM +0400, Sergei Ianovich wrote:
> PXA serial ports have "standard" UART names (ttyS[0-3]), major
> device number (4) and first minor device number (64) by default.
>
> If the system has extra 8250 serial port hardware in addition
> to onboard PXA serial ports, default settings produce a device
> allocation conflict.
>
> The patch provides a configuration option which can move onboard
> ports out of the way of 8250_core by assigning a different (204)
> major number and corresponding device names (ttySA[0-3]).
>
> Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
> ---
> drivers/tty/serial/Kconfig | 19 +++++++++++++++++++
> drivers/tty/serial/pxa.c | 22 ++++++++++++++++++----
> 2 files changed, 37 insertions(+), 4 deletions(-)
> diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c

<snip>
If drivers/tty/serial/pxa.c was converted to an other probe driver for
the 8250, this would not be an issue.

Br,

--
heikki

Sergei Ianovich

unread,
Dec 2, 2013, 4:30:02 AM12/2/13
to
On Mon, 2013-12-02 at 11:02 +0200, Heikki Krogerus wrote:
> On Sun, Dec 01, 2013 at 10:26:14AM +0400, Sergei Ianovich wrote:
> > PXA serial ports have "standard" UART names (ttyS[0-3]), major
> > device number (4) and first minor device number (64) by default.
> >
> > If the system has extra 8250 serial port hardware in addition
> > to onboard PXA serial ports, default settings produce a device
> > allocation conflict.
> >
> > The patch provides a configuration option which can move onboard
> > ports out of the way of 8250_core by assigning a different (204)
> > major number and corresponding device names (ttySA[0-3]).
> >
> <snip>
>
> If drivers/tty/serial/pxa.c was converted to an other probe driver for
> the 8250, this would not be an issue.

It seems that my patch is not going to be accepted. However, there is a
device which has both PXA ports and a additional 8250 accent chip. As a
result, there is a device allocation conflict. For the device to be
usable the conflict needs to be resolved.

Do you mean that drivers/tty/serial/pxa.c needs to be rewritten to
support lp8x4x special case?

Heikki Krogerus

unread,
Dec 2, 2013, 5:00:01 AM12/2/13
to
Hi,

On Mon, Dec 02, 2013 at 01:23:58PM +0400, Sergei Ianovich wrote:
> On Mon, 2013-12-02 at 11:02 +0200, Heikki Krogerus wrote:
> > On Sun, Dec 01, 2013 at 10:26:14AM +0400, Sergei Ianovich wrote:
> > > PXA serial ports have "standard" UART names (ttyS[0-3]), major
> > > device number (4) and first minor device number (64) by default.
> > >
> > > If the system has extra 8250 serial port hardware in addition
> > > to onboard PXA serial ports, default settings produce a device
> > > allocation conflict.
> > >
> > > The patch provides a configuration option which can move onboard
> > > ports out of the way of 8250_core by assigning a different (204)
> > > major number and corresponding device names (ttySA[0-3]).
> > >
> > <snip>
> >
> > If drivers/tty/serial/pxa.c was converted to an other probe driver for
> > the 8250, this would not be an issue.
>
> It seems that my patch is not going to be accepted. However, there is a
> device which has both PXA ports and a additional 8250 accent chip. As a
> result, there is a device allocation conflict. For the device to be
> usable the conflict needs to be resolved.
>
> Do you mean that drivers/tty/serial/pxa.c needs to be rewritten to
> support lp8x4x special case?

Sorry I was not clear. I was suggesting that drivers/tty/serial/pxa.c
would be converted to drivers/tty/serial/8250/8250_pxa.c since it
looks to me like just an other 16x50 compatible UART. That would fix
the issue with the name conflict. You would then simply register 8250
ports from two probe drivers (drivers/tty/serial/8250/8250_pxa.c and
drivers/tty/serial/8250/8250_lp8x4x.c).

Depending on the order you register your platform devices (which you
decide in your platform code), but let's say the pxa gets registered
first and let's say it only has one port. You will then have in your
system /dev/ttyS0 for the pxa port and /dev/ttyS[1-4] for the other
UART.

I hope I was able to explain what I mean this time :)

Thanks,

--
heikki

Sergei Ianovich

unread,
Dec 2, 2013, 5:30:02 AM12/2/13
to
Sorry, I wasn't clear as well. I got it right the first time. You mean
pxa.c needs to merged into 8250. This will solve the conflict in
question, and do it the right way. However, this will be a *much* bigger
patch, and it will affect everyone on pxa.

Who makes the decision which way to go?

Russell King - ARM Linux

unread,
Dec 2, 2013, 6:40:02 AM12/2/13
to
On Sun, Dec 01, 2013 at 10:26:18AM +0400, Sergei Ianovich wrote:
> +static struct platform_device lp8x4x_device = {
> + .name = "serial8250",
> + .id = PLAT8250_DEV_ACCENT,

You should not re-use the enum value here. The enum is designed as a
method to provide the platform devices with a unique id, not as a means
to identify the manufacturer or anything else like that.

Sergei Ianovich

unread,
Dec 2, 2013, 6:40:02 AM12/2/13
to
On Mon, 2013-12-02 at 11:30 +0000, Russell King - ARM Linux wrote:
> On Sun, Dec 01, 2013 at 10:26:18AM +0400, Sergei Ianovich wrote:
> > +static struct platform_device lp8x4x_device = {
> > + .name = "serial8250",
> > + .id = PLAT8250_DEV_ACCENT,
>
> You should not re-use the enum value here. The enum is designed as a
> method to provide the platform devices with a unique id, not as a means
> to identify the manufacturer or anything else like that.

Should I add a new enum?

Or should I use zero?

Sergei Ianovich

unread,
Dec 2, 2013, 6:50:01 AM12/2/13
to
On Mon, 2013-12-02 at 10:48 +0200, Heikki Krogerus wrote:
> On Sun, Dec 01, 2013 at 10:26:18AM +0400, Sergei Ianovich wrote:
> > The patch adds support for 3 additional LP-8x4x built-in serial
> > ports.
> >
> > The device can also host up to 8 extension cards with 4 serial ports
> > on each card for a total of 35 ports. However, I don't have
> > the hardware to test extension cards, so they are not supported, yet.

> > --- a/arch/arm/mach-pxa/include/mach/lp8x4x.h
> > +++ b/arch/arm/mach-pxa/include/mach/lp8x4x.h
> > @@ -50,6 +50,12 @@
> > #define LP8X4X_CLRFALLINT LP8X4X_P2V(0x1700901a)
> > #define LP8X4X_RWRTC LP8X4X_P2V(0x1700901c)
> > #define LP8X4X_SRAMBANK 0x1700901e
> > +#define LP8X4X_TTYS0_QUIRK 0x17009030
> > +#define LP8X4X_TTYS1_QUIRK 0x17009032
> > +#define LP8X4X_TTYS2_QUIRK 0x17009034
> > +#define LP8X4X_TTYS0_IOMEM 0x17009050
> > +#define LP8X4X_TTYS1_IOMEM 0x17009060
> > +#define LP8X4X_TTYS2_IOMEM 0x17009070
> > +
> > +static void lp8x4x_set_termios(struct uart_port *port,
> > + struct ktermios *termios, struct ktermios *old)
> > +{
>
> <snip>
>
> > +static int request_and_remap(int i)
> > +{
> > + if (!request_mem_region(extra_mem[i], 1, "serial"))
> > + return -EBUSY;
> > +
> > + lp8x4x_data[i].private_data = ioremap(extra_mem[i], 1);
> > + if (lp8x4x_data[i].private_data)
> > + return 0;
> > +
> > + release_mem_region(extra_mem[i], 1);
> > + return -ENODEV;

> Instead of registering a platform device for serial8250 here, you need
> to simply register a platform driver for something like lp8x4x_serial.
> The platform code will to registers the platform devices for it. You
> will use serial8250_register_8250_port() in your probe to register a
> new port. Use 8250_em.c and 8250_dw.c under drivers/tty/serial/8250/
> as an example.
>
> You don't need to introduce plat_serial8250_port so you won't need
> the QUIRK_PORT stuff. You deliver the iomem and the irq as normal
> resources that the driver uses when you create the platform device.
> That of course also means the driver does not need to care about the
> instances. The platform code will generate a platform device for as
> many ports you have and set to resources accordingly.

8250_core.c doesn't use platform infrastructure to request and map IO
memory. There will be a conflict (and an error in
serial8250_request_std_resource()), if main IO memory is requested by
the platform device, won't it?

Russell King - ARM Linux

unread,
Dec 2, 2013, 7:00:02 AM12/2/13
to
On Mon, Dec 02, 2013 at 03:39:26PM +0400, Sergei Ianovich wrote:
> On Mon, 2013-12-02 at 11:30 +0000, Russell King - ARM Linux wrote:
> > On Sun, Dec 01, 2013 at 10:26:18AM +0400, Sergei Ianovich wrote:
> > > +static struct platform_device lp8x4x_device = {
> > > + .name = "serial8250",
> > > + .id = PLAT8250_DEV_ACCENT,
> >
> > You should not re-use the enum value here. The enum is designed as a
> > method to provide the platform devices with a unique id, not as a means
> > to identify the manufacturer or anything else like that.
>
> Should I add a new enum?

Add a new enum.

Sergei Ianovich

unread,
Dec 2, 2013, 7:10:03 AM12/2/13
to
On Mon, 2013-12-02 at 11:52 +0000, Russell King - ARM Linux wrote:
> Add a new enum.

I will. Thanks for prompt replies.

A side work process question:
Should I respin this single patch?

Or should I wait for other patch reviews and respin the whole series
when ready?

Heikki Krogerus

unread,
Dec 2, 2013, 9:00:02 AM12/2/13
to
Hi,
You don't need to request the mem region in your probe driver.

You can still map it. You have the flag UPF_IOREMAP that you can use
to tell 8250_code.c to map the region. If you don't set the flag,
8250_core.c will in practice expect that port->membase is already set
by the probe driver.

Check 8250_dw.c. It does the mapping on it's own and simply doesn't
set the flag.

Br,

--
heikki

Heikki Krogerus

unread,
Dec 2, 2013, 9:20:02 AM12/2/13
to
Hi,
Greg and Russel make this decision. By having the pxa driver simply
register 8250 ports would probable reduce the code. Thats about the
biggest benefit from it.

It would still be something nice to have IMO. Ideally all the
8250/16x50 UARTs should register the ports with 8250_core.c, and not
create complete uart driver on their own.

Br,

--
heikki

Greg Kroah-Hartman

unread,
Dec 4, 2013, 11:20:01 PM12/4/13
to
I agree, this is the best way to resolve this, having a separate uart
driver isn't that good at all to be doing, if at all possible.

thanks,

greg k-h

Greg Kroah-Hartman

unread,
Dec 4, 2013, 11:40:02 PM12/4/13
to
On Thu, Dec 05, 2013 at 08:31:36AM +0400, Sergei Ianovich wrote:
> I'm reading the last message as a confirmation that
> drivers/tty/serial/pxa.c needs to be rewritten using 8250_core.c.

Yes, how much work is this really?

Sergei Ianovich

unread,
Dec 4, 2013, 11:40:02 PM12/4/13
to
On Wed, 2013-12-04 at 20:35 -0800, Greg Kroah-Hartman wrote:
> On Thu, Dec 05, 2013 at 08:31:36AM +0400, Sergei Ianovich wrote:
> > I'm reading the last message as a confirmation that
> > drivers/tty/serial/pxa.c needs to be rewritten using 8250_core.c.
>
> Yes, how much work is this really?

Great. It seems two drivers practically match. I'll do and submit a
merge patch.

Sergei Ianovich

unread,
Dec 4, 2013, 11:40:02 PM12/4/13
to
I'm reading the last message as a confirmation that
drivers/tty/serial/pxa.c needs to be rewritten using 8250_core.c.
However, "if at all possible" confuses me, since we have pxa.c in the
tree and it works. Greg, could you please clarify?

Sergei Ianovich

unread,
Dec 5, 2013, 6:30:02 PM12/5/13
to
pxa2xx-uart was a separate uart platform driver. It was declaring
the same device names and numbers as 8250 driver. As a result,
it was impossible to use 8250 driver on PXA SoCs.

Upon closer examination pxa2xx-uart turned out to be a clone of
8250_core driver.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Heikki Krogerus <heikki....@linux.intel.com>
CC: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
arch/arm/configs/am200epdkit_defconfig | 3 +-
arch/arm/configs/cm_x2xx_defconfig | 3 +-
arch/arm/configs/cm_x300_defconfig | 3 +-
arch/arm/configs/colibri_pxa270_defconfig | 3 +-
arch/arm/configs/colibri_pxa300_defconfig | 3 +-
arch/arm/configs/corgi_defconfig | 4 +-
arch/arm/configs/em_x270_defconfig | 3 +-
arch/arm/configs/ezx_defconfig | 3 +-
arch/arm/configs/h5000_defconfig | 3 +-
arch/arm/configs/imote2_defconfig | 3 +-
arch/arm/configs/lpd270_defconfig | 3 +-
arch/arm/configs/lubbock_defconfig | 3 +-
arch/arm/configs/mainstone_defconfig | 3 +-
arch/arm/configs/mmp2_defconfig | 3 +-
arch/arm/configs/pcm027_defconfig | 3 +-
arch/arm/configs/pxa168_defconfig | 3 +-
arch/arm/configs/pxa255-idp_defconfig | 3 +-
arch/arm/configs/pxa3xx_defconfig | 3 +-
arch/arm/configs/pxa910_defconfig | 3 +-
arch/arm/configs/raumfeld_defconfig | 3 +-
arch/arm/configs/spitz_defconfig | 4 +-
arch/arm/configs/trizeps4_defconfig | 3 +-
arch/arm/configs/viper_defconfig | 4 +-
arch/arm/configs/xcep_defconfig | 3 +-
drivers/tty/serial/8250/8250_pxa.c | 180 ++++++
drivers/tty/serial/8250/Kconfig | 9 +
drivers/tty/serial/8250/Makefile | 1 +
drivers/tty/serial/Kconfig | 23 -
drivers/tty/serial/Makefile | 1 -
drivers/tty/serial/pxa.c | 971 ------------------------------
30 files changed, 238 insertions(+), 1022 deletions(-)
create mode 100644 drivers/tty/serial/8250/8250_pxa.c
delete mode 100644 drivers/tty/serial/pxa.c

diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig
index f0dea52..0cde234 100644
--- a/arch/arm/configs/am200epdkit_defconfig
+++ b/arch/arm/configs/am200epdkit_defconfig
@@ -60,8 +60,9 @@ CONFIG_BLK_DEV_IDECS=m
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_SMC91X=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/cm_x2xx_defconfig b/arch/arm/configs/cm_x2xx_defconfig
index a93ff8d..b9fbe65 100644
--- a/arch/arm/configs/cm_x2xx_defconfig
+++ b/arch/arm/configs/cm_x2xx_defconfig
@@ -96,8 +96,9 @@ CONFIG_KEYBOARD_PXA27x=m
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_UCB1400=m
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig
index f4b7672..53a82ae 100644
--- a/arch/arm/configs/cm_x300_defconfig
+++ b/arch/arm/configs/cm_x300_defconfig
@@ -80,8 +80,9 @@ CONFIG_TOUCHSCREEN_WM97XX=m
# CONFIG_TOUCHSCREEN_WM9713 is not set
# CONFIG_SERIO is not set
# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_PXA=y
diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig
index 2ef2c5e..1ce0409 100644
--- a/arch/arm/configs/colibri_pxa270_defconfig
+++ b/arch/arm/configs/colibri_pxa270_defconfig
@@ -103,8 +103,9 @@ CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/configs/colibri_pxa300_defconfig b/arch/arm/configs/colibri_pxa300_defconfig
index b985334..f96bda0 100644
--- a/arch/arm/configs/colibri_pxa300_defconfig
+++ b/arch/arm/configs/colibri_pxa300_defconfig
@@ -31,8 +31,9 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_MISC=y
CONFIG_INPUT_GPIO_ROTARY_ENCODER=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_DEBUG_GPIO=y
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig
index 1fd1d1d..bb4842d 100644
--- a/arch/arm/configs/corgi_defconfig
+++ b/arch/arm/configs/corgi_defconfig
@@ -131,10 +131,10 @@ CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
# CONFIG_SERIO is not set
-CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_CS=m
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_I2C=y
CONFIG_I2C_PXA=y
diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig
index 60a21e0..ec0ec54 100644
--- a/arch/arm/configs/em_x270_defconfig
+++ b/arch/arm/configs/em_x270_defconfig
@@ -90,8 +90,9 @@ CONFIG_TOUCHSCREEN_WM97XX=m
# CONFIG_TOUCHSCREEN_WM9705 is not set
# CONFIG_TOUCHSCREEN_WM9713 is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig
index d95763d..631e2ec 100644
--- a/arch/arm/configs/ezx_defconfig
+++ b/arch/arm/configs/ezx_defconfig
@@ -215,8 +215,9 @@ CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_PCAP=y
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=8
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/h5000_defconfig b/arch/arm/configs/h5000_defconfig
index 37903e3..655b735 100644
--- a/arch/arm/configs/h5000_defconfig
+++ b/arch/arm/configs/h5000_defconfig
@@ -47,8 +47,9 @@ CONFIG_MTD_PHYSMAP=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=32
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/imote2_defconfig b/arch/arm/configs/imote2_defconfig
index fd996bb..49d45e9 100644
--- a/arch/arm/configs/imote2_defconfig
+++ b/arch/arm/configs/imote2_defconfig
@@ -193,8 +193,9 @@ CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=8
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/lpd270_defconfig b/arch/arm/configs/lpd270_defconfig
index 1c8c9ee..c3927b6 100644
--- a/arch/arm/configs/lpd270_defconfig
+++ b/arch/arm/configs/lpd270_defconfig
@@ -38,8 +38,9 @@ CONFIG_SMC91X=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_HW_RANDOM is not set
CONFIG_FB=y
CONFIG_FB_PXA=y
diff --git a/arch/arm/configs/lubbock_defconfig b/arch/arm/configs/lubbock_defconfig
index c4ba274..c8b0436 100644
--- a/arch/arm/configs/lubbock_defconfig
+++ b/arch/arm/configs/lubbock_defconfig
@@ -37,8 +37,9 @@ CONFIG_PCMCIA_PCNET=y
CONFIG_INPUT_EVDEV=y
# CONFIG_SERIO_SERPORT is not set
CONFIG_SERIO_SA1111=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_USB_GADGET=y
CONFIG_USB_G_SERIAL=m
diff --git a/arch/arm/configs/mainstone_defconfig b/arch/arm/configs/mainstone_defconfig
index 04efa1b..768892c 100644
--- a/arch/arm/configs/mainstone_defconfig
+++ b/arch/arm/configs/mainstone_defconfig
@@ -34,8 +34,9 @@ CONFIG_SMC91X=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_PXA=y
# CONFIG_VGA_CONSOLE is not set
diff --git a/arch/arm/configs/mmp2_defconfig b/arch/arm/configs/mmp2_defconfig
index f1cb95e..1ced9df 100644
--- a/arch/arm/configs/mmp2_defconfig
+++ b/arch/arm/configs/mmp2_defconfig
@@ -44,8 +44,9 @@ CONFIG_SMC91X=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig
index 2f136c3..1280128 100644
--- a/arch/arm/configs/pcm027_defconfig
+++ b/arch/arm/configs/pcm027_defconfig
@@ -60,8 +60,9 @@ CONFIG_SMC91X=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/pxa168_defconfig b/arch/arm/configs/pxa168_defconfig
index 74d7e01..1668dac 100644
--- a/arch/arm/configs/pxa168_defconfig
+++ b/arch/arm/configs/pxa168_defconfig
@@ -40,8 +40,9 @@ CONFIG_SMC91X=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/pxa255-idp_defconfig b/arch/arm/configs/pxa255-idp_defconfig
index 917a070..399a706 100644
--- a/arch/arm/configs/pxa255-idp_defconfig
+++ b/arch/arm/configs/pxa255-idp_defconfig
@@ -35,8 +35,9 @@ CONFIG_SMC91X=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_PXA=y
# CONFIG_VGA_CONSOLE is not set
diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig
index 60e3138..7c3e052 100644
--- a/arch/arm/configs/pxa3xx_defconfig
+++ b/arch/arm/configs/pxa3xx_defconfig
@@ -56,8 +56,9 @@ CONFIG_KEYBOARD_PXA27x=y
CONFIG_KEYBOARD_PXA930_ROTARY=y
CONFIG_MOUSE_PXA930_TRKBALL=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/pxa910_defconfig b/arch/arm/configs/pxa910_defconfig
index 3bb7771..cdacfcb 100644
--- a/arch/arm/configs/pxa910_defconfig
+++ b/arch/arm/configs/pxa910_defconfig
@@ -40,8 +40,9 @@ CONFIG_SMC91X=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_SPI=y
CONFIG_FB=y
CONFIG_MMP_DISP=y
diff --git a/arch/arm/configs/raumfeld_defconfig b/arch/arm/configs/raumfeld_defconfig
index f7caa90..f1e16f2 100644
--- a/arch/arm/configs/raumfeld_defconfig
+++ b/arch/arm/configs/raumfeld_defconfig
@@ -67,8 +67,9 @@ CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_EETI=m
CONFIG_INPUT_MISC=y
CONFIG_INPUT_GPIO_ROTARY_ENCODER=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig
index 2e0419d..b6efcf5 100644
--- a/arch/arm/configs/spitz_defconfig
+++ b/arch/arm/configs/spitz_defconfig
@@ -128,10 +128,10 @@ CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
# CONFIG_SERIO is not set
-CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_CS=m
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_SPI=y
CONFIG_SPI_PXA2XX=y
diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig
index 3162173..453c79c 100644
--- a/arch/arm/configs/trizeps4_defconfig
+++ b/arch/arm/configs/trizeps4_defconfig
@@ -132,8 +132,9 @@ CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/configs/viper_defconfig b/arch/arm/configs/viper_defconfig
index d36e0d3..4efac06 100644
--- a/arch/arm/configs/viper_defconfig
+++ b/arch/arm/configs/viper_defconfig
@@ -101,11 +101,11 @@ CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
# CONFIG_CONSOLE_TRANSLATIONS is not set
# CONFIG_VT_CONSOLE is not set
-CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=5
CONFIG_SERIAL_8250_RUNTIME_UARTS=5
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/configs/xcep_defconfig b/arch/arm/configs/xcep_defconfig
index 721832f..b67aeaf 100644
--- a/arch/arm/configs/xcep_defconfig
+++ b/arch/arm/configs/xcep_defconfig
@@ -60,8 +60,9 @@ CONFIG_NET_ETHERNET=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=m
diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
new file mode 100644
index 0000000..5658fc9
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -0,0 +1,180 @@
+/*
+ * drivers/tty/serial/8250/8250_pxa.c -- driver for PXA on-board UARTS
+ * Copyright: (C) 2013 Sergei Ianovich <ynv...@gmail.com>
+ *
+ * replaces drivers/serial/pxa.c by Nicolas Pitre
+ * Created: Feb 20, 2003
+ * Copyright: (C) 2003 Monta Vista Software, Inc.
+ *
+ * Based on drivers/serial/8250.c by Russell King.
+ *
+ * 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/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+
+#include "8250.h"
+
+struct pxa8250_data {
+ int line;
+ struct clk *clk;
+};
+
+#ifdef CONFIG_PM
+static int serial_pxa_suspend(struct device *dev)
+{
+ struct pxa8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_suspend_port(data->line);
+
+ return 0;
+}
+
+static int serial_pxa_resume(struct device *dev)
+{
+ struct pxa8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+}
+
+static const struct dev_pm_ops serial_pxa_pm_ops = {
+ .suspend = serial_pxa_suspend,
+ .resume = serial_pxa_resume,
+};
+#endif
+
+static struct of_device_id serial_pxa_dt_ids[] = {
+ { .compatible = "mrvl,pxa-uart", },
+ { .compatible = "mrvl,mmp-uart", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
+
+/* Uart divisor latch write */
+static void serial_pxa_dl_write(struct uart_8250_port *up, int value)
+{
+ serial_out(up, UART_DLL, value & 0xff);
+ serial_out(up, UART_DLM, value >> 8 & 0xff);
+}
+
+
+static void serial_pxa_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct pxa8250_data *data = port->private_data;
+
+ if (!state)
+ clk_prepare_enable(data->clk);
+ else
+ clk_disable_unprepare(data->clk);
+}
+
+static int serial_pxa_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port uart = {};
+ struct pxa8250_data *data;
+ struct resource *mmres, *irqres;
+ int ret;
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mmres || !irqres)
+ return -ENODEV;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ goto err_free;
+ }
+
+ ret = clk_prepare(data->clk);
+ if (ret)
+ goto err_free_clk;
+
+ uart.port.type = PORT_XSCALE;
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.mapbase = mmres->start;
+ uart.port.regshift = 2;
+ uart.port.irq = irqres->start;
+ uart.port.fifosize = 64;
+ uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST;
+ uart.port.dev = &pdev->dev;
+ uart.port.uartclk = clk_get_rate(data->clk);
+ uart.port.pm = serial_pxa_pm;
+ uart.port.private_data = data;
+ uart.dl_write = serial_pxa_dl_write;
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0)
+ goto err_clk;
+
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+ err_clk:
+ clk_unprepare(data->clk);
+ err_free_clk:
+ devm_clk_put(&pdev->dev, data->clk);
+ err_free:
+ devm_kfree(&pdev->dev, data);
+ return ret;
+}
+
+static int serial_pxa_remove(struct platform_device *pdev)
+{
+ struct pxa8250_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+
+ clk_unprepare(data->clk);
+ devm_clk_put(&pdev->dev, data->clk);
+ devm_kfree(&pdev->dev, data);
+
+ return 0;
+}
+
+static struct platform_driver serial_pxa_driver = {
+ .probe = serial_pxa_probe,
+ .remove = serial_pxa_remove,
+
+ .driver = {
+ .name = "pxa2xx-uart",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &serial_pxa_pm_ops,
+#endif
+ .of_match_table = serial_pxa_dt_ids,
+ },
+};
+
+module_platform_driver(serial_pxa_driver);
+
+MODULE_AUTHOR("Sergei Ianovich");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-uart");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 2332991..81bd7c9 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -302,3 +302,12 @@ config SERIAL_8250_RT288X
If you have a Ralink RT288x/RT305x SoC based board and want to use the
serial port, say Y to this option. The driver can handle up to 2 serial
ports. If unsure, say N.
+
+config SERIAL_PXA
+ tristate "PXA serial port support"
+ depends on SERIAL_8250 && (ARCH_PXA || ARCH_MMP)
+ help
+ If you have a machine based on an Intel XScale PXA2xx CPU you
+ can enable its onboard serial ports by enabling this option.
+
+ If you choose M here, the module name will be 8250_pxa.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 36d68d0..b7d1b61 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
+obj-$(CONFIG_SERIAL_PXA) += 8250_pxa.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index a3817ab..2ad7184b 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -396,29 +396,6 @@ config SERIAL_MPSC_CONSOLE
help
Say Y here if you want to support a serial console on a Marvell MPSC.

-config SERIAL_PXA
- bool "PXA serial port support"
- depends on ARCH_PXA || ARCH_MMP
- select SERIAL_CORE
- help
- If you have a machine based on an Intel XScale PXA2xx CPU you
- can enable its onboard serial ports by enabling this option.
-
-config SERIAL_PXA_CONSOLE
- bool "Console on PXA serial port"
- depends on SERIAL_PXA
- select SERIAL_CORE_CONSOLE
- help
- If you have enabled the serial port on the Intel XScale PXA
- CPU you can make it the console by answering Y to this option.
-
- Even if you say Y here, the currently visible virtual console
- (/dev/tty0) will still be used as the system console by default, but
- you can alter that using a kernel command line option such as
- "console=ttySA0". (Try "man bootparam" or see the documentation of
- your boot loader (lilo or loadlin) about how to pass options to the
- kernel at boot time.)
-
config SERIAL_SA1100
bool "SA1100 serial port support"
depends on ARCH_SA1100
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 3068c77..4ac337b 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_SERIAL_8250) += 8250/
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
-obj-$(CONFIG_SERIAL_PXA) += pxa.o
obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
deleted file mode 100644
index f9f20f3..0000000
--- a/drivers/tty/serial/pxa.c
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- * Based on drivers/serial/8250.c by Russell King.
- *
- * Author: Nicolas Pitre
- * Created: Feb 20, 2003
- * Copyright: (C) 2003 Monta Vista Software, Inc.
- *
- * 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.
- *
- * Note 1: This driver is made separate from the already too overloaded
- * 8250.c because it needs some kirks of its own and that'll make it
- * easier to add DMA support.
- *
- * Note 2: I'm too sick of device allocation policies for serial ports.
- * If someone else wants to request an "official" allocation of major/minor
- * for this driver please be my guest. And don't forget that new hardware
- * to come from Intel might have more than 3 or 4 of those UARTs. Let's
- * hope for a better port registration and dynamic device allocation scheme
- * with the serial core maintainer satisfaction to appear soon.
- */
-
-
-#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#define PXA_NAME_LEN 8
-
-struct uart_pxa_port {
- struct uart_port port;
- unsigned char ier;
- unsigned char lcr;
- unsigned char mcr;
- unsigned int lsr_break_flag;
- struct clk *clk;
- char name[PXA_NAME_LEN];
-};
-
-static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
-{
- offset <<= 2;
- return readl(up->port.membase + offset);
-}
-
-static inline void serial_out(struct uart_pxa_port *up, int offset, int value)
-{
- offset <<= 2;
- writel(value, up->port.membase + offset);
-}
-
-static void serial_pxa_enable_ms(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- up->ier |= UART_IER_MSI;
- serial_out(up, UART_IER, up->ier);
-}
-
-static void serial_pxa_stop_tx(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- if (up->ier & UART_IER_THRI) {
- up->ier &= ~UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
- }
-}
-
-static void serial_pxa_stop_rx(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- up->ier &= ~UART_IER_RLSI;
- up->port.read_status_mask &= ~UART_LSR_DR;
- serial_out(up, UART_IER, up->ier);
-}
-
-static inline void receive_chars(struct uart_pxa_port *up, int *status)
-{
- unsigned int ch, flag;
- int max_count = 256;
-
- do {
- /* work around Errata #20 according to
- * Intel(R) PXA27x Processor Family
- * Specification Update (May 2005)
- *
- * Step 2
- * Disable the Reciever Time Out Interrupt via IER[RTOEI]
- */
- up->ier &= ~UART_IER_RTOIE;
- serial_out(up, UART_IER, up->ier);
-
- ch = serial_in(up, UART_RX);
- flag = TTY_NORMAL;
- up->port.icount.rx++;
-
- if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE))) {
- /*
- * For statistics only
- */
- if (*status & UART_LSR_BI) {
- *status &= ~(UART_LSR_FE | UART_LSR_PE);
- up->port.icount.brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
- if (uart_handle_break(&up->port))
- goto ignore_char;
- } else if (*status & UART_LSR_PE)
- up->port.icount.parity++;
- else if (*status & UART_LSR_FE)
- up->port.icount.frame++;
- if (*status & UART_LSR_OE)
- up->port.icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- *status &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
- if (up->port.line == up->port.cons->index) {
- /* Recover the break flag from console xmit */
- *status |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
- }
-#endif
- if (*status & UART_LSR_BI) {
- flag = TTY_BREAK;
- } else if (*status & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (*status & UART_LSR_FE)
- flag = TTY_FRAME;
- }
-
- if (uart_handle_sysrq_char(&up->port, ch))
- goto ignore_char;
-
- uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
-
- ignore_char:
- *status = serial_in(up, UART_LSR);
- } while ((*status & UART_LSR_DR) && (max_count-- > 0));
- tty_flip_buffer_push(&up->port.state->port);
-
- /* work around Errata #20 according to
- * Intel(R) PXA27x Processor Family
- * Specification Update (May 2005)
- *
- * Step 6:
- * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
- */
- up->ier |= UART_IER_RTOIE;
- serial_out(up, UART_IER, up->ier);
-}
-
-static void transmit_chars(struct uart_pxa_port *up)
-{
- struct circ_buf *xmit = &up->port.state->xmit;
- int count;
-
- if (up->port.x_char) {
- serial_out(up, UART_TX, up->port.x_char);
- up->port.icount.tx++;
- up->port.x_char = 0;
- return;
- }
- if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- serial_pxa_stop_tx(&up->port);
- return;
- }
-
- count = up->port.fifosize / 2;
- do {
- serial_out(up, UART_TX, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- up->port.icount.tx++;
- if (uart_circ_empty(xmit))
- break;
- } while (--count > 0);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&up->port);
-
-
- if (uart_circ_empty(xmit))
- serial_pxa_stop_tx(&up->port);
-}
-
-static void serial_pxa_start_tx(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- if (!(up->ier & UART_IER_THRI)) {
- up->ier |= UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
- }
-}
-
-static inline void check_modem_status(struct uart_pxa_port *up)
-{
- int status;
-
- status = serial_in(up, UART_MSR);
-
- if ((status & UART_MSR_ANY_DELTA) == 0)
- return;
-
- if (status & UART_MSR_TERI)
- up->port.icount.rng++;
- if (status & UART_MSR_DDSR)
- up->port.icount.dsr++;
- if (status & UART_MSR_DDCD)
- uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
- if (status & UART_MSR_DCTS)
- uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
- wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
-{
- struct uart_pxa_port *up = dev_id;
- unsigned int iir, lsr;
-
- iir = serial_in(up, UART_IIR);
- if (iir & UART_IIR_NO_INT)
- return IRQ_NONE;
- lsr = serial_in(up, UART_LSR);
- if (lsr & UART_LSR_DR)
- receive_chars(up, &lsr);
- check_modem_status(up);
- if (lsr & UART_LSR_THRE)
- transmit_chars(up);
- return IRQ_HANDLED;
-}
-
-static unsigned int serial_pxa_tx_empty(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
- unsigned int ret;
-
- spin_lock_irqsave(&up->port.lock, flags);
- ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- return ret;
-}
-
-static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned char status;
- unsigned int ret;
-
- status = serial_in(up, UART_MSR);
-
- ret = 0;
- if (status & UART_MSR_DCD)
- ret |= TIOCM_CAR;
- if (status & UART_MSR_RI)
- ret |= TIOCM_RNG;
- if (status & UART_MSR_DSR)
- ret |= TIOCM_DSR;
- if (status & UART_MSR_CTS)
- ret |= TIOCM_CTS;
- return ret;
-}
-
-static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned char mcr = 0;
-
- if (mctrl & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (mctrl & TIOCM_DTR)
- mcr |= UART_MCR_DTR;
- if (mctrl & TIOCM_OUT1)
- mcr |= UART_MCR_OUT1;
- if (mctrl & TIOCM_OUT2)
- mcr |= UART_MCR_OUT2;
- if (mctrl & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
-
- mcr |= up->mcr;
-
- serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
-
- spin_lock_irqsave(&up->port.lock, flags);
- if (break_state == -1)
- up->lcr |= UART_LCR_SBC;
- else
- up->lcr &= ~UART_LCR_SBC;
- serial_out(up, UART_LCR, up->lcr);
- spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int serial_pxa_startup(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
- int retval;
-
- if (port->line == 3) /* HWUART */
- up->mcr |= UART_MCR_AFE;
- else
- up->mcr = 0;
-
- up->port.uartclk = clk_get_rate(up->clk);
-
- /*
- * Allocate the IRQ
- */
- retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
- if (retval)
- return retval;
-
- /*
- * Clear the FIFO buffers and disable them.
- * (they will be reenabled in set_termios())
- */
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_out(up, UART_FCR, 0);
-
- /*
- * Clear the interrupt registers.
- */
- (void) serial_in(up, UART_LSR);
- (void) serial_in(up, UART_RX);
- (void) serial_in(up, UART_IIR);
- (void) serial_in(up, UART_MSR);
-
- /*
- * Now, initialize the UART
- */
- serial_out(up, UART_LCR, UART_LCR_WLEN8);
-
- spin_lock_irqsave(&up->port.lock, flags);
- up->port.mctrl |= TIOCM_OUT2;
- serial_pxa_set_mctrl(&up->port, up->port.mctrl);
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- /*
- * Finally, enable interrupts. Note: Modem status interrupts
- * are set via set_termios(), which will be occurring imminently
- * anyway, so we don't enable them here.
- */
- up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
- serial_out(up, UART_IER, up->ier);
-
- /*
- * And clear the interrupt registers again for luck.
- */
- (void) serial_in(up, UART_LSR);
- (void) serial_in(up, UART_RX);
- (void) serial_in(up, UART_IIR);
- (void) serial_in(up, UART_MSR);
-
- return 0;
-}
-
-static void serial_pxa_shutdown(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
-
- free_irq(up->port.irq, up);
-
- /*
- * Disable interrupts from this port
- */
- up->ier = 0;
- serial_out(up, UART_IER, 0);
-
- spin_lock_irqsave(&up->port.lock, flags);
- up->port.mctrl &= ~TIOCM_OUT2;
- serial_pxa_set_mctrl(&up->port, up->port.mctrl);
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- /*
- * Disable break condition and FIFOs
- */
- serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT);
- serial_out(up, UART_FCR, 0);
-}
-
-static void
-serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned char cval, fcr = 0;
- unsigned long flags;
- unsigned int baud, quot;
- unsigned int dll;
-
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- cval = UART_LCR_WLEN5;
- break;
- case CS6:
- cval = UART_LCR_WLEN6;
- break;
- case CS7:
- cval = UART_LCR_WLEN7;
- break;
- default:
- case CS8:
- cval = UART_LCR_WLEN8;
- break;
- }
-
- if (termios->c_cflag & CSTOPB)
- cval |= UART_LCR_STOP;
- if (termios->c_cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(termios->c_cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
- /*
- * Ask the core to calculate the divisor for us.
- */
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- quot = uart_get_divisor(port, baud);
-
- if ((up->port.uartclk / quot) < (2400 * 16))
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
- else if ((up->port.uartclk / quot) < (230400 * 16))
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
- else
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
-
- /*
- * Ok, we're now changing the port state. Do it with
- * interrupts disabled.
- */
- spin_lock_irqsave(&up->port.lock, flags);
-
- /*
- * Ensure the port will be enabled.
- * This is required especially for serial console.
- */
- up->ier |= UART_IER_UUE;
-
- /*
- * Update the per-port timeout.
- */
- uart_update_timeout(port, termios->c_cflag, baud);
-
- up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (termios->c_iflag & INPCK)
- up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
- up->port.read_status_mask |= UART_LSR_BI;
-
- /*
- * Characters to ignore
- */
- up->port.ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
- if (termios->c_iflag & IGNBRK) {
- up->port.ignore_status_mask |= UART_LSR_BI;
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns too (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- up->port.ignore_status_mask |= UART_LSR_OE;
- }
-
- /*
- * ignore all characters if CREAD is not set
- */
- if ((termios->c_cflag & CREAD) == 0)
- up->port.ignore_status_mask |= UART_LSR_DR;
-
- /*
- * CTS flow control flag and modem status interrupts
- */
- up->ier &= ~UART_IER_MSI;
- if (UART_ENABLE_MS(&up->port, termios->c_cflag))
- up->ier |= UART_IER_MSI;
-
- serial_out(up, UART_IER, up->ier);
-
- if (termios->c_cflag & CRTSCTS)
- up->mcr |= UART_MCR_AFE;
- else
- up->mcr &= ~UART_MCR_AFE;
-
- serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
- serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
-
- /*
- * work around Errata #75 according to Intel(R) PXA27x Processor Family
- * Specification Update (Nov 2005)
- */
- dll = serial_in(up, UART_DLL);
- WARN_ON(dll != (quot & 0xff));
-
- serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
- serial_out(up, UART_LCR, cval); /* reset DLAB */
- up->lcr = cval; /* Save LCR */
- serial_pxa_set_mctrl(&up->port, up->port.mctrl);
- serial_out(up, UART_FCR, fcr);
- spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_pxa_pm(struct uart_port *port, unsigned int state,
- unsigned int oldstate)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- if (!state)
- clk_prepare_enable(up->clk);
- else
- clk_disable_unprepare(up->clk);
-}
-
-static void serial_pxa_release_port(struct uart_port *port)
-{
-}
-
-static int serial_pxa_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-static void serial_pxa_config_port(struct uart_port *port, int flags)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- up->port.type = PORT_PXA;
-}
-
-static int
-serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
- /* we don't want the core code to modify any port params */
- return -EINVAL;
-}
-
-static const char *
-serial_pxa_type(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- return up->name;
-}
-
-static struct uart_pxa_port *serial_pxa_ports[4];
-static struct uart_driver serial_pxa_reg;
-
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- * Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_pxa_port *up)
-{
- unsigned int status, tmout = 10000;
-
- /* Wait up to 10ms for the character(s) to be sent. */
- do {
- status = serial_in(up, UART_LSR);
-
- if (status & UART_LSR_BI)
- up->lsr_break_flag = UART_LSR_BI;
-
- if (--tmout == 0)
- break;
- udelay(1);
- } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
- /* Wait up to 1s for flow control if necessary */
- if (up->port.flags & UPF_CONS_FLOW) {
- tmout = 1000000;
- while (--tmout &&
- ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
- udelay(1);
- }
-}
-
-static void serial_pxa_console_putchar(struct uart_port *port, int ch)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- wait_for_xmitr(up);
- serial_out(up, UART_TX, ch);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- * The console_lock must be held when we get here.
- */
-static void
-serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct uart_pxa_port *up = serial_pxa_ports[co->index];
- unsigned int ier;
- unsigned long flags;
- int locked = 1;
-
- clk_enable(up->clk);
- local_irq_save(flags);
- if (up->port.sysrq)
- locked = 0;
- else if (oops_in_progress)
- locked = spin_trylock(&up->port.lock);
- else
- spin_lock(&up->port.lock);
-
- /*
- * First save the IER then disable the interrupts
- */
- ier = serial_in(up, UART_IER);
- serial_out(up, UART_IER, UART_IER_UUE);
-
- uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
-
- /*
- * Finally, wait for transmitter to become empty
- * and restore the IER
- */
- wait_for_xmitr(up);
- serial_out(up, UART_IER, ier);
-
- if (locked)
- spin_unlock(&up->port.lock);
- local_irq_restore(flags);
- clk_disable(up->clk);
-
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-/*
- * Console polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static int serial_pxa_get_poll_char(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned char lsr = serial_in(up, UART_LSR);
-
- while (!(lsr & UART_LSR_DR))
- lsr = serial_in(up, UART_LSR);
-
- return serial_in(up, UART_RX);
-}
-
-
-static void serial_pxa_put_poll_char(struct uart_port *port,
- unsigned char c)
-{
- unsigned int ier;
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- /*
- * First save the IER then disable the interrupts
- */
- ier = serial_in(up, UART_IER);
- serial_out(up, UART_IER, UART_IER_UUE);
-
- wait_for_xmitr(up);
- /*
- * Send the character out.
- * If a LF, also do CR...
- */
- serial_out(up, UART_TX, c);
- if (c == 10) {
- wait_for_xmitr(up);
- serial_out(up, UART_TX, 13);
- }
-
- /*
- * Finally, wait for transmitter to become empty
- * and restore the IER
- */
- wait_for_xmitr(up);
- serial_out(up, UART_IER, ier);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static int __init
-serial_pxa_console_setup(struct console *co, char *options)
-{
- struct uart_pxa_port *up;
- int baud = 9600;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- if (co->index == -1 || co->index >= serial_pxa_reg.nr)
- co->index = 0;
- up = serial_pxa_ports[co->index];
- if (!up)
- return -ENODEV;
-
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
-
- return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static struct console serial_pxa_console = {
- .name = "ttyS",
- .write = serial_pxa_console_write,
- .device = uart_console_device,
- .setup = serial_pxa_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &serial_pxa_reg,
-};
-
-#define PXA_CONSOLE &serial_pxa_console
-#else
-#define PXA_CONSOLE NULL
-#endif
-
-static struct uart_ops serial_pxa_pops = {
- .tx_empty = serial_pxa_tx_empty,
- .set_mctrl = serial_pxa_set_mctrl,
- .get_mctrl = serial_pxa_get_mctrl,
- .stop_tx = serial_pxa_stop_tx,
- .start_tx = serial_pxa_start_tx,
- .stop_rx = serial_pxa_stop_rx,
- .enable_ms = serial_pxa_enable_ms,
- .break_ctl = serial_pxa_break_ctl,
- .startup = serial_pxa_startup,
- .shutdown = serial_pxa_shutdown,
- .set_termios = serial_pxa_set_termios,
- .pm = serial_pxa_pm,
- .type = serial_pxa_type,
- .release_port = serial_pxa_release_port,
- .request_port = serial_pxa_request_port,
- .config_port = serial_pxa_config_port,
- .verify_port = serial_pxa_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
- .poll_get_char = serial_pxa_get_poll_char,
- .poll_put_char = serial_pxa_put_poll_char,
-#endif
-};
-
-static struct uart_driver serial_pxa_reg = {
- .owner = THIS_MODULE,
- .driver_name = "PXA serial",
- .dev_name = "ttyS",
- .major = TTY_MAJOR,
- .minor = 64,
- .nr = 4,
- .cons = PXA_CONSOLE,
-};
-
-#ifdef CONFIG_PM
-static int serial_pxa_suspend(struct device *dev)
-{
- struct uart_pxa_port *sport = dev_get_drvdata(dev);
-
- if (sport)
- uart_suspend_port(&serial_pxa_reg, &sport->port);
-
- return 0;
-}
-
-static int serial_pxa_resume(struct device *dev)
-{
- struct uart_pxa_port *sport = dev_get_drvdata(dev);
-
- if (sport)
- uart_resume_port(&serial_pxa_reg, &sport->port);
-
- return 0;
-}
-
-static const struct dev_pm_ops serial_pxa_pm_ops = {
- .suspend = serial_pxa_suspend,
- .resume = serial_pxa_resume,
-};
-#endif
-
-static struct of_device_id serial_pxa_dt_ids[] = {
- { .compatible = "mrvl,pxa-uart", },
- { .compatible = "mrvl,mmp-uart", },
- {}
-};
-MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
-
-static int serial_pxa_probe_dt(struct platform_device *pdev,
- struct uart_pxa_port *sport)
-{
- struct device_node *np = pdev->dev.of_node;
- int ret;
-
- if (!np)
- return 1;
-
- ret = of_alias_get_id(np, "serial");
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
- return ret;
- }
- sport->port.line = ret;
- return 0;
-}
-
-static int serial_pxa_probe(struct platform_device *dev)
-{
- struct uart_pxa_port *sport;
- struct resource *mmres, *irqres;
- int ret;
-
- mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
- irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
- if (!mmres || !irqres)
- return -ENODEV;
-
- sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
- if (!sport)
- return -ENOMEM;
-
- sport->clk = clk_get(&dev->dev, NULL);
- if (IS_ERR(sport->clk)) {
- ret = PTR_ERR(sport->clk);
- goto err_free;
- }
-
- ret = clk_prepare(sport->clk);
- if (ret) {
- clk_put(sport->clk);
- goto err_free;
- }
-
- sport->port.type = PORT_PXA;
- sport->port.iotype = UPIO_MEM;
- sport->port.mapbase = mmres->start;
- sport->port.irq = irqres->start;
- sport->port.fifosize = 64;
- sport->port.ops = &serial_pxa_pops;
- sport->port.dev = &dev->dev;
- sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
- sport->port.uartclk = clk_get_rate(sport->clk);
-
- ret = serial_pxa_probe_dt(dev, sport);
- if (ret > 0)
- sport->port.line = dev->id;
- else if (ret < 0)
- goto err_clk;
- snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
-
- sport->port.membase = ioremap(mmres->start, resource_size(mmres));
- if (!sport->port.membase) {
- ret = -ENOMEM;
- goto err_clk;
- }
-
- serial_pxa_ports[sport->port.line] = sport;
-
- uart_add_one_port(&serial_pxa_reg, &sport->port);
- platform_set_drvdata(dev, sport);
-
- return 0;
-
- err_clk:
- clk_unprepare(sport->clk);
- clk_put(sport->clk);
- err_free:
- kfree(sport);
- return ret;
-}
-
-static int serial_pxa_remove(struct platform_device *dev)
-{
- struct uart_pxa_port *sport = platform_get_drvdata(dev);
-
- uart_remove_one_port(&serial_pxa_reg, &sport->port);
-
- clk_unprepare(sport->clk);
- clk_put(sport->clk);
- kfree(sport);
-
- return 0;
-}
-
-static struct platform_driver serial_pxa_driver = {
- .probe = serial_pxa_probe,
- .remove = serial_pxa_remove,
-
- .driver = {
- .name = "pxa2xx-uart",
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &serial_pxa_pm_ops,
-#endif
- .of_match_table = serial_pxa_dt_ids,
- },
-};
-
-static int __init serial_pxa_init(void)
-{
- int ret;
-
- ret = uart_register_driver(&serial_pxa_reg);
- if (ret != 0)
- return ret;
-
- ret = platform_driver_register(&serial_pxa_driver);
- if (ret != 0)
- uart_unregister_driver(&serial_pxa_reg);
-
- return ret;
-}
-
-static void __exit serial_pxa_exit(void)
-{
- platform_driver_unregister(&serial_pxa_driver);
- uart_unregister_driver(&serial_pxa_reg);
-}
-
-module_init(serial_pxa_init);
-module_exit(serial_pxa_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pxa2xx-uart");
--
1.8.4.3

Greg Kroah-Hartman

unread,
Dec 5, 2013, 7:10:01 PM12/5/13
to
On Fri, Dec 06, 2013 at 03:28:37AM +0400, Sergei Ianovich wrote:
> pxa2xx-uart was a separate uart platform driver. It was declaring
> the same device names and numbers as 8250 driver. As a result,
> it was impossible to use 8250 driver on PXA SoCs.
>
> Upon closer examination pxa2xx-uart turned out to be a clone of
> 8250_core driver.
>
> Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
> CC: Heikki Krogerus <heikki....@linux.intel.com>
> CC: Greg Kroah-Hartman <gre...@linuxfoundation.org>

Wonderful!

Can someone else test this to verify it works for them on their platform
as well?

thanks,

greg k-h

Russell King - ARM Linux

unread,
Dec 5, 2013, 7:20:01 PM12/5/13
to
On Thu, Dec 05, 2013 at 04:02:53PM -0800, Greg Kroah-Hartman wrote:
> On Fri, Dec 06, 2013 at 03:28:37AM +0400, Sergei Ianovich wrote:
> > pxa2xx-uart was a separate uart platform driver. It was declaring
> > the same device names and numbers as 8250 driver. As a result,
> > it was impossible to use 8250 driver on PXA SoCs.
> >
> > Upon closer examination pxa2xx-uart turned out to be a clone of
> > 8250_core driver.
> >
> > Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
> > CC: Heikki Krogerus <heikki....@linux.intel.com>
> > CC: Greg Kroah-Hartman <gre...@linuxfoundation.org>
>
> Wonderful!
>
> Can someone else test this to verify it works for them on their platform
> as well?

I may be able to - one of the downsides though is that many of these
systems had hard-coded scripts which started a getty on the original
port - and that kind of makes it difficult to sort out. This kind of
change becomes very much one of Linus' "flag days".

So I'd suggest that we have a period where the old driver is still
available, so at least people can choose to use the old major/minor
numbers for a while.

Arnd Bergmann

unread,
Dec 5, 2013, 7:50:01 PM12/5/13
to
On Sunday 01 December 2013, Sergei Ianovich wrote:
>
> diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
> new file mode 100644
> index 0000000..5cd6d38
> --- /dev/null
> +++ b/arch/arm/configs/lp8x4x_defconfig
> @@ -0,0 +1,2320 @@
> +#
> +# Automatically generated file; DO NOT EDIT.
> +# Linux/arm 3.13.0-rc1 Kernel Configuration
> +#

Please use 'make savedefconfig' to generate a smaller version of this file.

Ideally we want shared defconfigs where you enable multiple (or all) pxa boards
at once and end up with a kernel that works on all of them.

For most other platforms the goal is even to have a shared defconfig across
SoC families, but PXA is one of the exceptions that I would make because
it is both old and rather different from even the ARM9 or Marvell Feroceon
based SoCs.

> +#define LP8X4X_FPGA_PHYS 0x17000000
> +#define LP8X4X_FPGA_VIRT 0xf1000000
> +#define LP8X4X_P2V(x) IOMEM((x) - LP8X4X_FPGA_PHYS + LP8X4X_FPGA_VIRT)
> +#define LP8X4X_V2P(x) ((x) - LP8X4X_FPGA_VIRT + LP8X4X_FPGA_PHYS)

I would recommend defining LP8X4X_FPGA_VIRT as "(void *)0xf1000000". Ideally
we try to avoid hardwired virtual addresses entirely and instead use platform
device resources, but I realize that there are limits to how far you get with
that. Please make an effort to convert as many parts of the FPGA into platform
devices with regular resources, but know that we would not enforce this as
strictly as we do for new platforms.

> +
> +static struct irq_chip lp8x4x_irq_chip = {
> + .name = "FPGA",
> + .irq_ack = lp8x4x_ack_irq,
> + .irq_mask = lp8x4x_mask_irq,
> + .irq_unmask = lp8x4x_unmask_irq,
> +};

Please try to move the irqchip code to drivers/irqchip/.

> +static struct platform_device lp8x4x_flash_device[] = {

static platform_device definitions are no longer the way to do this. For
modern platforms, you'd use a device tree, but here I think it is acceptable
(because of the PXA exception) to use a hardcoded board file.

The correct way to create the devices is using platform_device_register_data()
or a related function that returns a dynamically allocated platform device.

Arnd

James Cameron

unread,
Dec 5, 2013, 7:50:02 PM12/5/13
to
On Fri, Dec 06, 2013 at 03:28:37AM +0400, Sergei Ianovich wrote:
> pxa2xx-uart was a separate uart platform driver. It was declaring
> the same device names and numbers as 8250 driver. As a result,
> it was impossible to use 8250 driver on PXA SoCs.
>
> Upon closer examination pxa2xx-uart turned out to be a clone of
> 8250_core driver.

I'm testing this backported to 3.5 on the OLPC XO-4 [1] [2].

As Russell says, the getty had to change, but after that the shell
worked fine; no more or no less responsive.

What hasn't worked yet is the console; no kernel messages appear. I
have tried changing command line to console=ttyS0,115200.

1. http://dev.laptop.org/~quozl/y/1VojGn.txt (diff relative to
olpc-kernel/arm-3.5)

2. http://dev.laptop.org/~quozl/z/1VojLz.txt (dmesg)

--
James Cameron
http://quozl.linux.org.au/

James Cameron

unread,
Dec 5, 2013, 9:50:01 PM12/5/13
to
On Fri, Dec 06, 2013 at 03:28:37AM +0400, Sergei Ianovich wrote:
> pxa2xx-uart was a separate uart platform driver. It was declaring
> the same device names and numbers as 8250 driver. As a result,
> it was impossible to use 8250 driver on PXA SoCs.
>
> Upon closer examination pxa2xx-uart turned out to be a clone of
> 8250_core driver.

[...]

> +/* Uart divisor latch write */
> +static void serial_pxa_dl_write(struct uart_8250_port *up, int value)
> +{
> + serial_out(up, UART_DLL, value & 0xff);
> + serial_out(up, UART_DLM, value >> 8 & 0xff);
> +}

This is a change. drivers/tty/serial/pxa.c did read back UART_DLL as
an errata work around:

> - /*
> - * work around Errata #75 according to Intel(R) PXA27x Processor Family
> - * Specification Update (Nov 2005)
> - */
> - dll = serial_in(up, UART_DLL);
> - WARN_ON(dll != (quot & 0xff));

If this is no longer needed, serial_pxa_dl_write can be removed
because it is same as default_serial_dl_write.

I did not check the other errata work arounds.

--
James Cameron
http://quozl.linux.org.au/

James Cameron

unread,
Dec 5, 2013, 10:00:01 PM12/5/13
to
On Fri, Dec 06, 2013 at 11:38:51AM +1100, James Cameron wrote:
> On Fri, Dec 06, 2013 at 03:28:37AM +0400, Sergei Ianovich wrote:
> > pxa2xx-uart was a separate uart platform driver. It was declaring
> > the same device names and numbers as 8250 driver. As a result,
> > it was impossible to use 8250 driver on PXA SoCs.
> >
> > Upon closer examination pxa2xx-uart turned out to be a clone of
> > 8250_core driver.
>
> I'm testing this backported to 3.5 on the OLPC XO-4 [1] [2].
>
> As Russell says, the getty had to change, but after that the shell
> worked fine; no more or no less responsive.
>
> What hasn't worked yet is the console; no kernel messages appear. I
> have tried changing command line to console=ttyS0,115200.

My error. Our kernel had CONFIG_CMDLINE set, changing that fixed it.
Console is working fine.

Sergei Ianovich

unread,
Dec 6, 2013, 4:20:04 AM12/6/13
to
On Fri, 2013-12-06 at 13:42 +1100, James Cameron wrote:
> On Fri, Dec 06, 2013 at 03:28:37AM +0400, Sergei Ianovich wrote:
> > +/* Uart divisor latch write */
> > +static void serial_pxa_dl_write(struct uart_8250_port *up, int value)
> > +{
> > + serial_out(up, UART_DLL, value & 0xff);
> > + serial_out(up, UART_DLM, value >> 8 & 0xff);
> > +}
>
> This is a change. drivers/tty/serial/pxa.c did read back UART_DLL as
> an errata work around:
>
> > - /*
> > - * work around Errata #75 according to Intel(R) PXA27x Processor Family
> > - * Specification Update (Nov 2005)
> > - */
> > - dll = serial_in(up, UART_DLL);
> > - WARN_ON(dll != (quot & 0xff));
>
> If this is no longer needed, serial_pxa_dl_write can be removed
> because it is same as default_serial_dl_write.

Thanks for spotting this. I prepared infrastructure, but the tests never
failed so I never returned here. I've filed v2 with correct dl_write.

> I did not check the other errata work arounds.

I've intentionally dropped workaround for E20 from old pxa.c
receive_chars(). 8250_core reads FIFO immediately after it checks DR bit
in LSR, so that issue never happens. New version states this in commit
message.

Sergei Ianovich

unread,
Dec 6, 2013, 4:20:04 AM12/6/13
to
pxa2xx-uart was a separate uart platform driver. It was declaring
the same device names and numbers as 8250 driver. As a result,
it was impossible to use 8250 driver on PXA SoCs.

Upon closer examination pxa2xx-uart turned out to be a clone of
8250_core driver.

Workaround for Erratum #19 according to Marvel(R) PXA270M Processor
Specification Update (April 19, 2010) is dropped. 8250_core reads
from FIFO immediately after checking DR bit in LSR.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Heikki Krogerus <heikki....@linux.intel.com>
CC: Greg Kroah-Hartman <gre...@linuxfoundation.org>
CC: James Cameron <qu...@laptop.org>
---
changes v1..v2
* actually implement workaround for E74 in dl_write as spooted
by James Cameron
* added comment about E19 in commit message

arch/arm/configs/am200epdkit_defconfig | 3 +-
arch/arm/configs/cm_x2xx_defconfig | 3 +-
arch/arm/configs/cm_x300_defconfig | 3 +-
arch/arm/configs/colibri_pxa270_defconfig | 3 +-
arch/arm/configs/colibri_pxa300_defconfig | 3 +-
arch/arm/configs/corgi_defconfig | 4 +-
arch/arm/configs/em_x270_defconfig | 3 +-
arch/arm/configs/ezx_defconfig | 3 +-
arch/arm/configs/h5000_defconfig | 3 +-
arch/arm/configs/imote2_defconfig | 3 +-
arch/arm/configs/lpd270_defconfig | 3 +-
arch/arm/configs/lubbock_defconfig | 3 +-
arch/arm/configs/mainstone_defconfig | 3 +-
arch/arm/configs/mmp2_defconfig | 3 +-
arch/arm/configs/pcm027_defconfig | 3 +-
arch/arm/configs/pxa168_defconfig | 3 +-
arch/arm/configs/pxa255-idp_defconfig | 3 +-
arch/arm/configs/pxa3xx_defconfig | 3 +-
arch/arm/configs/pxa910_defconfig | 3 +-
arch/arm/configs/raumfeld_defconfig | 3 +-
arch/arm/configs/spitz_defconfig | 4 +-
arch/arm/configs/trizeps4_defconfig | 3 +-
arch/arm/configs/viper_defconfig | 4 +-
arch/arm/configs/xcep_defconfig | 3 +-
drivers/tty/serial/8250/8250_pxa.c | 189 ++++++
drivers/tty/serial/8250/Kconfig | 9 +
drivers/tty/serial/8250/Makefile | 1 +
drivers/tty/serial/Kconfig | 23 -
drivers/tty/serial/Makefile | 1 -
drivers/tty/serial/pxa.c | 971 ------------------------------
30 files changed, 247 insertions(+), 1022 deletions(-)
index 0000000..88ae73c
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -0,0 +1,189 @@
+ unsigned int dll;
+
+ serial_out(up, UART_DLL, value & 0xff);
+ /*
+ * work around Erratum #74 according to Marvel(R) PXA270M Processor
+ * Specification Update (April 19, 2010)
+ */
+ dll = serial_in(up, UART_DLL);
+ WARN_ON(dll != (value & 0xff));
+
1.8.4.2

James Cameron

unread,
Dec 6, 2013, 4:30:02 AM12/6/13
to
On Fri, Dec 06, 2013 at 01:09:31PM +0400, Sergei Ianovich wrote:
> pxa2xx-uart was a separate uart platform driver. It was declaring
> the same device names and numbers as 8250 driver. As a result,
> it was impossible to use 8250 driver on PXA SoCs.
>
> Upon closer examination pxa2xx-uart turned out to be a clone of
> 8250_core driver.
>
> Workaround for Erratum #19 according to Marvel(R) PXA270M Processor
> Specification Update (April 19, 2010) is dropped. 8250_core reads
> from FIFO immediately after checking DR bit in LSR.

Reviewed-by: James Cameron <qu...@laptop.org>

Thanks.

(for my notes ... V1 has passed 4.5 hours in OLPC's RUNIN test.)

--
James Cameron
http://quozl.linux.org.au/

Sergei Ianovich

unread,
Dec 6, 2013, 4:30:03 AM12/6/13
to
On Fri, 2013-12-06 at 00:17 +0000, Russell King - ARM Linux wrote:

> I may be able to - one of the downsides though is that many of these
> systems had hard-coded scripts which started a getty on the original
> port - and that kind of makes it difficult to sort out. This kind of
> change becomes very much one of Linus' "flag days".

> So I'd suggest that we have a period where the old driver is still
> available, so at least people can choose to use the old major/minor
> numbers for a while.

The patch doesn't change how the driver looks from the outside. The old
driver was using 8250 name (ttyS), major (4) and first minor (64). So we
only resolve an internal conflict.

Kernel configuration is the place where issues may appear, since the
patch removes CONFIG_SERIAL_PXA_CONSOLE option. I've updated all
in-kernel users. However, out-of-kernel configs will no longer provide
serial console, unless manually reconfigured. Is this the case we should
worry about?

James Cameron

unread,
Dec 6, 2013, 5:00:03 AM12/6/13
to
On Fri, Dec 06, 2013 at 01:28:51PM +0400, Sergei Ianovich wrote:
> On Fri, 2013-12-06 at 00:17 +0000, Russell King - ARM Linux wrote:
>
> > I may be able to - one of the downsides though is that many of these
> > systems had hard-coded scripts which started a getty on the original
> > port - and that kind of makes it difficult to sort out. This kind of
> > change becomes very much one of Linus' "flag days".
>
> > So I'd suggest that we have a period where the old driver is still
> > available, so at least people can choose to use the old major/minor
> > numbers for a while.
>
> The patch doesn't change how the driver looks from the outside. The old
> driver was using 8250 name (ttyS), major (4) and first minor (64). So we
> only resolve an internal conflict.

I don't understand why /dev/ttyS2 (4,66) changed to /dev/ttyS0 (4,64)
after the patch was applied to olpc-kernel/arm-3.5 but, as you say it
doesn't change, perhaps there is something between 3.5 and now for me
to watch out for. My problem.

> Kernel configuration is the place where issues may appear, since the
> patch removes CONFIG_SERIAL_PXA_CONSOLE option. I've updated all
> in-kernel users. However, out-of-kernel configs will no longer provide
> serial console, unless manually reconfigured. Is this the case we should
> worry about?

OLPC holds an out-of-kernel config (xo_4_defconfig); but no, I don't
think we'd have trouble with this. Go for it.

--
James Cameron
http://quozl.linux.org.au/

Sergei Ianovich

unread,
Dec 6, 2013, 5:40:01 AM12/6/13
to
On Fri, 2013-12-06 at 20:53 +1100, James Cameron wrote:
> I don't understand why /dev/ttyS2 (4,66) changed to /dev/ttyS0 (4,64)
> after the patch was applied to olpc-kernel/arm-3.5 but, as you say it
> doesn't change, perhaps there is something between 3.5 and now for me
> to watch out for. My problem.

The old pxa.c set device ids explicitly:
-static int serial_pxa_probe_dt(struct platform_device *pdev,
- struct uart_pxa_port *sport)
-{
- struct device_node *np = pdev->dev.of_node;
- int ret;
-
- if (!np)
- return 1;
-
- ret = of_alias_get_id(np, "serial");
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias id, errno %d
\n", ret);
- return ret;
- }
- sport->port.line = ret;
- return 0;
-}

and

- ret = serial_pxa_probe_dt(dev, sport);
- if (ret > 0)
- sport->port.line = dev->id;


However, this is not possible with 8250_core. The latter assigns device
ids strictly in the call order of serial8250_register_8250_port().

Hope it helps.

James Cameron

unread,
Dec 6, 2013, 6:10:02 AM12/6/13
to
Yes, thanks, that explains it.

Your patch deprecates the use of property "linux,unit#" in the device
tree for serial ports, or the numbering according to the ordering of
the device tree.

(On OLPC XO-4, we set the numbering according to the ordering, we don't
use "linux,unit#".)

It is sad to see device tree sawdust. ;-)

--
James Cameron
http://quozl.linux.org.au/

Sergei Ianovich

unread,
Dec 6, 2013, 11:40:02 AM12/6/13
to
On Fri, 2013-12-06 at 01:40 +0100, Arnd Bergmann wrote:
> On Sunday 01 December 2013, Sergei Ianovich wrote:
> >
> > diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
> > new file mode 100644
> > index 0000000..5cd6d38
> > --- /dev/null
> > +++ b/arch/arm/configs/lp8x4x_defconfig
> > @@ -0,0 +1,2320 @@
> > +#
> > +# Automatically generated file; DO NOT EDIT.
> > +# Linux/arm 3.13.0-rc1 Kernel Configuration
> > +#
>
> Please use 'make savedefconfig' to generate a smaller version of this file.

Done. Updated in v2.

> Ideally we want shared defconfigs where you enable multiple (or all) pxa boards
> at once and end up with a kernel that works on all of them.
>
> For most other platforms the goal is even to have a shared defconfig across
> SoC families, but PXA is one of the exceptions that I would make because
> it is both old and rather different from even the ARM9 or Marvell Feroceon
> based SoCs.

There is probably no in point sharing this config with most other
devices on PXA2xx SoC. This device is an industrial PC. Its config needs
to be optimized for low latency even by the cost of greater power
consumption. It is not supposed to run on batteries or enter any low
power mode anyway.

> > +#define LP8X4X_FPGA_PHYS 0x17000000
> > +#define LP8X4X_FPGA_VIRT 0xf1000000
> > +#define LP8X4X_P2V(x) IOMEM((x) - LP8X4X_FPGA_PHYS + LP8X4X_FPGA_VIRT)
> > +#define LP8X4X_V2P(x) ((x) - LP8X4X_FPGA_VIRT + LP8X4X_FPGA_PHYS)
>
> I would recommend defining LP8X4X_FPGA_VIRT as "(void *)0xf1000000". Ideally

Done in v2.

> we try to avoid hardwired virtual addresses entirely and instead use platform
> device resources, but I realize that there are limits to how far you get with
> that. Please make an effort to convert as many parts of the FPGA into platform
> devices with regular resources, but know that we would not enforce this as
> strictly as we do for new platforms.
>
> > +
> > +static struct irq_chip lp8x4x_irq_chip = {
> > + .name = "FPGA",
> > + .irq_ack = lp8x4x_ack_irq,
> > + .irq_mask = lp8x4x_mask_irq,
> > + .irq_unmask = lp8x4x_unmask_irq,
> > +};
>
> Please try to move the irqchip code to drivers/irqchip/.

CONFIG_IRQCHIP depends on CONFIG_OF_IRQ which in turn depends on Open
Firmware.

The device is shipped with such a flash device partition table, which
makes migration to device tree rather difficult. The partition for
U-Boot is just 256kiB. This is a high aim already. U-Boot needs to be
compiled without command line help and USB support to fit into this
size. Otherwise the main flash needs to be repartitioned.

Could it be acceptable to accept the device without device tree support?

If so, FPGA irqchip could remain in the machine source file. It is
highly unlikely, it will ever be reused. In this case all fixed virtual
address definitions could be moved to the machine source file. The file
will be the only place where LP8X4X_FPGA_VIRT is used directly.

> > +static struct platform_device lp8x4x_flash_device[] = {
>
> static platform_device definitions are no longer the way to do this. For
> modern platforms, you'd use a device tree, but here I think it is acceptable
> (because of the PXA exception) to use a hardcoded board file.
>
> The correct way to create the devices is using platform_device_register_data()
> or a related function that returns a dynamically allocated platform device.

Done in v2. Allocation migrated to use
platform_device_register_resndata() and
platform_device_register_simple().

Sergei Ianovich

unread,
Dec 6, 2013, 11:50:02 AM12/6/13
to
ICP DAS calls LP-8x4x 'programmable automation controller'. It is
an industrial computer based on PXA270 SoC. They ship it with a 2.6.19
kernel and proprietary kernel module and userspace library to access
its industrial IO.

This patch allows to boot the device with a modern kernel. It adds
support for:
* FPGA irq chip
* MMC card interface on PXA270
* USB 1.1 port on PXA270
* 2 NOR flash devices
* VGA interface on PXA270
* 2 onboard ethernet Davicom DM9000 devices
* 3 serial UART ports on PXA270

Support for these devices will be added in separate patches, since
they are not currently supported by the kernel:
* DS1302 RTC
* 512kiB SRAM
* 3 built-in and up to 32 pluggable 8250 serial UART ports
* industrial IO parallel bus
* digital and analog industrial IO modules for parallel bus
* serial interface for digital and analog industrial IO modules on
parallel bus

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
changes v1..v2
* clean up defconfig (reduces size by 10) as suggested
by Arnd Bergmann

* fixed constant address definition to include (void *) cast
as suggested by Arnd Bergmann

* moved fixed virtual addresses into the machine source file.
Header file is dropped.

* static platform devices are replaced by dynamically allocated
as suggested by Arnd Bergmann

arch/arm/configs/lp8x4x_defconfig | 235 +++++++++++++++++++
arch/arm/mach-pxa/Kconfig | 16 ++
arch/arm/mach-pxa/Makefile | 1 +
arch/arm/mach-pxa/lp8x4x.c | 473 ++++++++++++++++++++++++++++++++++++++
4 files changed, 725 insertions(+)
create mode 100644 arch/arm/configs/lp8x4x_defconfig
create mode 100644 arch/arm/mach-pxa/lp8x4x.c

diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
new file mode 100644
index 0000000..2612e60
--- /dev/null
+++ b/arch/arm/configs/lp8x4x_defconfig
@@ -0,0 +1,235 @@
+CONFIG_CROSS_COMPILE="arm-linux-gnueabi-"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_RCU_BOOST=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_SHMEM is not set
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_LBDAF is not set
+CONFIG_BLK_CMDLINE_PARSER=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_PXA=y
+CONFIG_MACH_LP8X4X=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_COMPACTION is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/sbin/init root=/dev/mmcblk0p1 rw rootfstype=ext4 console=ttyS0,115200 mem=128M rootwait"
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_VLAN_FILTERING=y
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VLAN_8021Q_MVRP=y
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PXA2XX=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=2
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+CONFIG_DM9000=y
+CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_WLAN is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=600
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=40
+CONFIG_SERIAL_8250_RUNTIME_UARTS=40
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_PXA=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=m
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_PXA=m
+CONFIG_I2C_PXA_SLAVE=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_SA1100_WATCHDOG=m
+CONFIG_FB=y
+CONFIG_FB_PXA=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_HID_GENERIC=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_USB_HIDDEV=y
+CONFIG_I2C_HID=m
+CONFIG_USB=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_ZTE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_MMC=y
+CONFIG_MMC_PXA=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PXA=m
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=m
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
+CONFIG_REISERFS_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CODA_FS=m
+CONFIG_NLS_DEFAULT="cp1251"
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 96100db..efaf2d0 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -273,6 +273,22 @@ config MACH_VPAC270

comment "End-user Products (sorted by vendor name)"

+config MACH_LP8X4X
+ bool "ICP DAS LP-8X4X"
+ select IWMMXT
+ select PXA27x
+ help
+ Say Y here if you intend to run this kernel on an ICP DAS
+ LP-8x4x programmable automation controller.
+
+ LP-8x4x is ARM-based and built around PXA270 SoC. The device
+ has 128 MiB SDRAM, 48 or 96 MiB NOR flash, VGA port with
+ 800x600 resolution, MMC card slot, 2 Ethernet ports, 1 USB
+ port, 5 serial ports (1 on them is wired internally to
+ expansion slots). The device has a range of digital and
+ analog expansion IO modules which can be installed in 1, 4 or
+ 8 slots depending on the model.
+
config MACH_H4700
bool "HP iPAQ hx4700"
select HAVE_PWM
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 648867a..b264325 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_MACH_COLIBRI320) += colibri-pxa3xx.o colibri-pxa320.o
obj-$(CONFIG_MACH_VPAC270) += vpac270.o

# End-user Products
+obj-$(CONFIG_MACH_LP8X4X) += lp8x4x.o
obj-$(CONFIG_MACH_H4700) += hx4700.o
obj-$(CONFIG_MACH_H5000) += h5000.o
obj-$(CONFIG_MACH_HIMALAYA) += himalaya.o
diff --git a/arch/arm/mach-pxa/lp8x4x.c b/arch/arm/mach-pxa/lp8x4x.c
new file mode 100644
index 0000000..0d3d8c0
--- /dev/null
+++ b/arch/arm/mach-pxa/lp8x4x.c
@@ -0,0 +1,473 @@
+/*
+ * linux/arch/arm/mach-pxa/lp8x4x.c
+ *
+ * Support for ICP DAS LP-8x4x programmable automation controller
+ * Copyright (C) 2013 Sergei Ianovich <ynv...@gmail.com>
+ *
+ * borrowed heavily from
+ * Support for the Intel HCDDBBVA0 Development Platform.
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 05, 2002
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation or any later version.
+ */
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/syscore_ops.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/input.h>
+#include <linux/dm9000.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <linux/ktime.h>
+#include <linux/irqchip/chained_irq.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
+
+#include <mach/irqs.h>
+#include <mach/pxa27x.h>
+#include <linux/platform_data/video-pxafb.h>
+#include <linux/platform_data/mmc-pxamci.h>
+#include <linux/platform_data/usb-ohci-pxa27x.h>
+#include <mach/smemc.h>
+
+#include "generic.h"
+#include "devices.h"
+
+#define LP8X4X_ETH0_BASE 0x0c000000
+#define LP8X4X_ETH0_IO 0x0c004000
+#define LP8X4X_ETH0_IRQ PXA_GPIO_TO_IRQ(9)
+
+#define LP8X4X_ETH1_BASE 0x0d000000
+#define LP8X4X_ETH1_IO 0x0d004000
+#define LP8X4X_ETH1_IRQ PXA_GPIO_TO_IRQ(82)
+
+#define LP8X4X_FPGA_PHYS 0x17000000
+#define LP8X4X_FPGA_VIRT ((void *) 0xf1000000)
+#define LP8X4X_P2V(x) IOMEM((x) - LP8X4X_FPGA_PHYS + LP8X4X_FPGA_VIRT)
+#define LP8X4X_V2P(x) ((x) - LP8X4X_FPGA_VIRT + LP8X4X_FPGA_PHYS)
+
+/* board level registers in the FPGA */
+
+#define LP8X4X_EOI LP8X4X_P2V(0x17009006)
+#define LP8X4X_INSINT LP8X4X_P2V(0x17009008)
+#define LP8X4X_ENSYSINT LP8X4X_P2V(0x1700900A)
+#define LP8X4X_PRIMINT LP8X4X_P2V(0x1700900C)
+#define LP8X4X_SECOINT LP8X4X_P2V(0x1700900E)
+#define LP8X4X_ENRISEINT LP8X4X_P2V(0x17009010)
+#define LP8X4X_CLRRISEINT LP8X4X_P2V(0x17009012)
+#define LP8X4X_ENHILVINT LP8X4X_P2V(0x17009014)
+#define LP8X4X_CLRHILVINT LP8X4X_P2V(0x17009016)
+#define LP8X4X_ENFALLINT LP8X4X_P2V(0x17009018)
+#define LP8X4X_CLRFALLINT LP8X4X_P2V(0x1700901a)
+
+/* board specific IRQs */
+
+#define LP8X4X_IRQ(x) (IRQ_BOARD_START + (x))
+#define LP8X4X_SLOT1_IRQ LP8X4X_IRQ(0)
+#define LP8X4X_SLOT2_IRQ LP8X4X_IRQ(1)
+#define LP8X4X_SLOT3_IRQ LP8X4X_IRQ(2)
+#define LP8X4X_SLOT4_IRQ LP8X4X_IRQ(3)
+#define LP8X4X_SLOT5_IRQ LP8X4X_IRQ(4)
+#define LP8X4X_SLOT6_IRQ LP8X4X_IRQ(5)
+#define LP8X4X_SLOT7_IRQ LP8X4X_IRQ(6)
+#define LP8X4X_SLOT8_IRQ LP8X4X_IRQ(7)
+#define LP8X4X_TIMER1_IRQ LP8X4X_IRQ(8)
+#define LP8X4X_TIMER2_IRQ LP8X4X_IRQ(9)
+#define LP8X4X_TIMEROUT_IRQ LP8X4X_IRQ(10)
+#define LP8X4X_HOTPLUG_IRQ LP8X4X_IRQ(11)
+#define LP8X4X_BATLOW_IRQ LP8X4X_IRQ(12)
+#define LP8X4X_TTYS0_IRQ LP8X4X_IRQ(13)
+#define LP8X4X_TTYS1_IRQ LP8X4X_IRQ(14)
+#define LP8X4X_TTYS2_IRQ LP8X4X_IRQ(15)
+
+#define LP8X4X_NR_IRQS (IRQ_BOARD_START + 16)
+
+static unsigned char lp8x4x_irq_sys_enabled;
+static unsigned char lp8x4x_irq_high_enabled;
+
+static void lp8x4x_ack_irq(struct irq_data *d)
+{
+ unsigned mask;
+ int irq = d->irq - IRQ_BOARD_START;
+
+ if (irq < 0 || irq > 15) {
+ pr_err("lp8x4x: wrong irq handler for irq %i\n", d->irq);
+ return;
+ }
+
+ if (irq < 8) {
+ mask = ioread8(LP8X4X_CLRHILVINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_CLRHILVINT);
+ } else if (irq < 13) {
+ irq -= 8;
+ mask = ioread8(LP8X4X_SECOINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_SECOINT);
+ } else {
+ irq -= 8;
+ mask = ioread8(LP8X4X_PRIMINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_PRIMINT);
+ }
+}
+
+static void lp8x4x_mask_irq(struct irq_data *d)
+{
+ int irq = d->irq - IRQ_BOARD_START;
+
+ if (irq < 0 || irq > 15) {
+ pr_err("lp8x4x: wrong irq handler for irq %i\n", d->irq);
+ return;
+ }
+
+ if (irq < 8) {
+ lp8x4x_irq_high_enabled &= ~(1 << irq);
+ iowrite8(lp8x4x_irq_high_enabled, LP8X4X_ENHILVINT);
+ } else {
+ irq -= 8;
+ lp8x4x_irq_sys_enabled &= ~(1 << irq);
+ iowrite8(lp8x4x_irq_sys_enabled, LP8X4X_ENSYSINT);
+ }
+}
+
+static void lp8x4x_unmask_irq(struct irq_data *d)
+{
+ unsigned mask;
+ int irq = d->irq - IRQ_BOARD_START;
+
+ if (irq < 0 || irq > 15) {
+ pr_err("wrong irq handler for irq %i\n", d->irq);
+ return;
+ }
+
+ if (irq < 8) {
+ lp8x4x_irq_high_enabled |= 1 << irq;
+ mask = ioread8(LP8X4X_CLRHILVINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_CLRHILVINT);
+ iowrite8(lp8x4x_irq_high_enabled, LP8X4X_ENHILVINT);
+ } else if (irq < 13) {
+ irq -= 8;
+ lp8x4x_irq_sys_enabled |= 1 << irq;
+ mask = ioread8(LP8X4X_SECOINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_SECOINT);
+ iowrite8(lp8x4x_irq_sys_enabled, LP8X4X_ENSYSINT);
+ } else {
+ irq -= 8;
+ lp8x4x_irq_sys_enabled |= 1 << irq;
+ mask = ioread8(LP8X4X_PRIMINT);
+ mask |= 1 << irq;
+ iowrite8(mask, LP8X4X_PRIMINT);
+ iowrite8(lp8x4x_irq_sys_enabled, LP8X4X_ENSYSINT);
+ }
+}
+
+static struct irq_chip lp8x4x_irq_chip = {
+ .name = "FPGA",
+ .irq_ack = lp8x4x_ack_irq,
+ .irq_mask = lp8x4x_mask_irq,
+ .irq_unmask = lp8x4x_unmask_irq,
+};
+
+static spinlock_t fpga_irq_lock;
+
+static void lp8x4x_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ int loop, n;
+ unsigned long mask;
+ unsigned long flags;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ spin_lock_irqsave(&fpga_irq_lock, flags);
+ chained_irq_enter(chip, desc);
+
+ do {
+ loop = 0;
+ mask = ioread8(LP8X4X_CLRHILVINT) & 0xff;
+ mask |= (ioread8(LP8X4X_SECOINT) & 0x1f) << 8;
+ mask |= (ioread8(LP8X4X_PRIMINT) & 0xe0) << 8;
+ mask &= (lp8x4x_irq_high_enabled
+ | (lp8x4x_irq_sys_enabled << 8));
+ for_each_set_bit(n, &mask, BITS_PER_LONG) {
+ loop = 1;
+
+ generic_handle_irq(IRQ_BOARD_START + n);
+ }
+ } while (loop);
+
+ chained_irq_exit(chip, desc);
+ iowrite8(0, LP8X4X_EOI);
+ spin_unlock_irqrestore(&fpga_irq_lock, flags);
+}
+
+static void __init lp8x4x_init_irq(void)
+{
+ int irq;
+ int err;
+
+ err = irq_set_irq_type(PXA_GPIO_TO_IRQ(3), IRQ_TYPE_EDGE_RISING);
+ if (err < 0) {
+ pr_err("lp8x4x: irq init failed\n");
+ return;
+ }
+
+ spin_lock_init(&fpga_irq_lock);
+ irq_set_chained_handler(PXA_GPIO_TO_IRQ(3), lp8x4x_irq_handler);
+
+ for (irq = IRQ_BOARD_START; irq < LP8X4X_NR_IRQS; irq++) {
+ irq_set_chip_and_handler(irq, &lp8x4x_irq_chip,
+ handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+
+ iowrite8(0, LP8X4X_CLRRISEINT);
+ iowrite8(0, LP8X4X_ENRISEINT);
+ iowrite8(0, LP8X4X_CLRFALLINT);
+ iowrite8(0, LP8X4X_ENFALLINT);
+ iowrite8(0, LP8X4X_CLRHILVINT);
+ iowrite8(0, LP8X4X_ENHILVINT);
+ iowrite8(0, LP8X4X_ENSYSINT);
+ iowrite8(0, LP8X4X_PRIMINT);
+ iowrite8(0, LP8X4X_SECOINT);
+
+ return;
+}
+
+static unsigned long lp8x4x_pin_config[] = {
+ /* MMC */
+ GPIO32_MMC_CLK,
+ GPIO112_MMC_CMD,
+ GPIO92_MMC_DAT_0,
+ GPIO109_MMC_DAT_1,
+ GPIO110_MMC_DAT_2,
+ GPIO111_MMC_DAT_3,
+
+ /* USB Host Port 1 */
+ GPIO88_USBH1_PWR,
+ GPIO89_USBH1_PEN,
+};
+
+static struct resource lp8x4x_flash_resources[] __initdata = {
+ [0] = {
+ .start = PXA_CS0_PHYS,
+ .end = PXA_CS0_PHYS + SZ_64M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = PXA_CS1_PHYS,
+ .end = PXA_CS1_PHYS + SZ_32M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct mtd_partition lp8x4x_flash0_partitions[] = {
+ {
+ .name = "Bootloader",
+ .size = 0x00040000,
+ .offset = 0,
+ }, {
+ .name = "Settings",
+ .size = 0x00040000,
+ .offset = 0x00040000,
+ }, {
+ .name = "Kernel",
+ .size = 0x00280000,
+ .offset = 0x00080000,
+ }, {
+ .name = "Filesystem",
+ .size = MTDPART_SIZ_FULL,
+ .offset = 0x00300000
+ }
+};
+
+static struct flash_platform_data lp8x4x_flash_data[] __initdata = {
+ {
+ .map_name = "cfi_probe",
+ .parts = lp8x4x_flash0_partitions,
+ .nr_parts = ARRAY_SIZE(lp8x4x_flash0_partitions),
+ .width = 4,
+ }, {
+ .map_name = "cfi_probe",
+ .parts = NULL,
+ .nr_parts = 0,
+ .width = 2,
+ }
+};
+
+static struct pxafb_mode_info lp8x4x_vga_60_mode = {
+ .pixclock = 38461,
+ .xres = 640,
+ .yres = 480,
+ .bpp = 16,
+ .hsync_len = 64,
+ .left_margin = 78,
+ .right_margin = 46,
+ .vsync_len = 12,
+ .upper_margin = 22,
+ .lower_margin = 10,
+ .sync = 0,
+};
+
+static struct pxafb_mach_info lp8x4x_pxafb_info = {
+ .num_modes = 1,
+ .lccr0 = LCCR0_Act,
+ .lccr3 = LCCR3_PCP,
+};
+
+static int lp8x4x_mci_init(struct device *dev,
+ irq_handler_t mstone_detect_int, void *data)
+{
+ return 0;
+}
+
+static int lp8x4x_mci_setpower(struct device *dev, unsigned int vdd)
+{
+ return 0;
+}
+
+static void lp8x4x_mci_exit(struct device *dev, void *data)
+{
+}
+
+static struct pxamci_platform_data lp8x4x_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = lp8x4x_mci_init,
+ .setpower = lp8x4x_mci_setpower,
+ .exit = lp8x4x_mci_exit,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
+};
+
+static struct resource lp8x4x_dm9000_resources[] __initdata = {
+ [0] = {
+ .start = LP8X4X_ETH0_BASE,
+ .end = LP8X4X_ETH0_BASE + 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = LP8X4X_ETH0_IO,
+ .end = LP8X4X_ETH0_IO + 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = LP8X4X_ETH0_IRQ,
+ .end = LP8X4X_ETH0_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ },
+ [3] = {
+ .start = LP8X4X_ETH1_BASE,
+ .end = LP8X4X_ETH1_BASE + 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [4] = {
+ .start = LP8X4X_ETH1_IO,
+ .end = LP8X4X_ETH1_IO + 2 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [5] = {
+ .start = LP8X4X_ETH1_IRQ,
+ .end = LP8X4X_ETH1_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ },
+};
+
+static struct pxaohci_platform_data lp8x4x_ohci_platform_data = {
+ .port_mode = PMM_PERPORT_MODE,
+ .flags = ENABLE_PORT1 | OC_MODE_PERPORT,
+};
+
+static void lp8x4x_restart(enum reboot_mode mode, const char *cmd)
+{
+ /* Switch off fast-bus and turbo mode */
+ asm volatile("mcr p14, 0, %0, c6, c0, 0" : :
+ "r"(2));
+ /* SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) */
+ pxa_restart(REBOOT_SOFT, cmd);
+}
+
+static void __init lp8x4x_init(void)
+{
+ pxa2xx_mfp_config(ARRAY_AND_SIZE(lp8x4x_pin_config));
+
+ pxa_set_ffuart_info(NULL);
+ pxa_set_btuart_info(NULL);
+ pxa_set_stuart_info(NULL);
+
+ /* system bus arbiter setting
+ * - Core_Park
+ * - LCD_wt:DMA_wt:CORE_Wt = 2:3:4
+ */
+ ARB_CNTRL = ARB_CORE_PARK | 0x234;
+
+ pxa_set_mci_info(&lp8x4x_mci_platform_data);
+ pxa_set_ohci_info(&lp8x4x_ohci_platform_data);
+
+ platform_device_register_resndata(NULL, "pxa2xx-flash", 0,
+ &lp8x4x_flash_resources[0], 1,
+ &lp8x4x_flash_data[0], sizeof(lp8x4x_flash_data[0]));
+ platform_device_register_resndata(NULL, "pxa2xx-flash", 1,
+ &lp8x4x_flash_resources[1], 1,
+ &lp8x4x_flash_data[1], sizeof(lp8x4x_flash_data[1]));
+ platform_device_register_simple("dm9000", 0,
+ &lp8x4x_dm9000_resources[0], 3);
+ platform_device_register_simple("dm9000", 1,
+ &lp8x4x_dm9000_resources[3], 3);
+
+ lp8x4x_pxafb_info.modes = &lp8x4x_vga_60_mode;
+ pxa_set_fb_info(NULL, &lp8x4x_pxafb_info);
+
+ /* Could not do this in MACHINE since GPIO is not ready then */
+ lp8x4x_init_irq();
+}
+
+static struct map_desc lp8x4x_io_desc[] __initdata = {
+ { /* CPLD */
+ .virtual = (unsigned long) LP8X4X_FPGA_VIRT,
+ .pfn = __phys_to_pfn(LP8X4X_FPGA_PHYS),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
+};
+
+static void __init lp8x4x_map_io(void)
+{
+ pxa27x_map_io();
+ iotable_init(lp8x4x_io_desc, ARRAY_SIZE(lp8x4x_io_desc));
+}
+
+MACHINE_START(LP8X4X, "ICP DAS LP-8x4x programmable automation controller")
+ .atag_offset = 0x100,
+ .map_io = lp8x4x_map_io,
+ .nr_irqs = LP8X4X_NR_IRQS,
+ .init_irq = pxa27x_init_irq,
+ .handle_irq = pxa27x_handle_irq,
+ .init_time = pxa_timer_init,
+ .init_machine = lp8x4x_init,
+ .restart = lp8x4x_restart,
+MACHINE_END
--
1.8.4.2

Arnd Bergmann

unread,
Dec 6, 2013, 12:20:02 PM12/6/13
to
On Friday 06 December 2013, Sergei Ianovich wrote:
> On Fri, 2013-12-06 at 01:40 +0100, Arnd Bergmann wrote:
>
> > Ideally we want shared defconfigs where you enable multiple (or all) pxa boards
> > at once and end up with a kernel that works on all of them.
> >
> > For most other platforms the goal is even to have a shared defconfig across
> > SoC families, but PXA is one of the exceptions that I would make because
> > it is both old and rather different from even the ARM9 or Marvell Feroceon
> > based SoCs.
>
> There is probably no in point sharing this config with most other
> devices on PXA2xx SoC. This device is an industrial PC. Its config needs
> to be optimized for low latency even by the cost of greater power
> consumption. It is not supposed to run on batteries or enter any low
> power mode anyway.

Ok, I see. Note that while most of them are mobile, I believe there are
a couple of pxa boards that are in the same category as yours.

Unfortunately, PXA already has most defconfigs than any other platform (25
at the moment) and I would like to see that reduced in the future if
I can find someone to do the work.

> > we try to avoid hardwired virtual addresses entirely and instead use platform
> > device resources, but I realize that there are limits to how far you get with
> > that. Please make an effort to convert as many parts of the FPGA into platform
> > devices with regular resources, but know that we would not enforce this as
> > strictly as we do for new platforms.
> >
> > > +
> > > +static struct irq_chip lp8x4x_irq_chip = {
> > > + .name = "FPGA",
> > > + .irq_ack = lp8x4x_ack_irq,
> > > + .irq_mask = lp8x4x_mask_irq,
> > > + .irq_unmask = lp8x4x_unmask_irq,
> > > +};
> >
> > Please try to move the irqchip code to drivers/irqchip/.
>
> CONFIG_IRQCHIP depends on CONFIG_OF_IRQ which in turn depends on Open
> Firmware.

Hmm, I wonder if we should try to change Kconfig then. Let's leave it
alone for now, maybe Linus Walleij has some comments since he has
been looking into moving drivers out in the past.

> The device is shipped with such a flash device partition table, which
> makes migration to device tree rather difficult. The partition for
> U-Boot is just 256kiB. This is a high aim already. U-Boot needs to be
> compiled without command line help and USB support to fit into this
> size. Otherwise the main flash needs to be repartitioned.
>
> Could it be acceptable to accept the device without device tree support?

From my point of view it's ok, but I'll leave that up to Daniel Mack,
since he has been doing all the work on PXA migration to DT lately.
I believe with his work it won't actually be a problem to do DT.

> If so, FPGA irqchip could remain in the machine source file. It is
> highly unlikely, it will ever be reused. In this case all fixed virtual
> address definitions could be moved to the machine source file. The file
> will be the only place where LP8X4X_FPGA_VIRT is used directly.

That sounds reasonable to me as well.

Arnd

Arnd Bergmann

unread,
Dec 7, 2013, 9:30:01 PM12/7/13
to
On Friday 06 December 2013, Sergei Ianovich wrote:

> new file mode 100644
> index 0000000..2612e60
> --- /dev/null
> +++ b/arch/arm/configs/lp8x4x_defconfig
> @@ -0,0 +1,235 @@
> +CONFIG_CROSS_COMPILE="arm-linux-gnueabi-"

This will break some build bots, please remove it here and add it to your
build environment instead.

> +# CONFIG_LBDAF is not set
> +CONFIG_BLK_CMDLINE_PARSER=y
> +CONFIG_PARTITION_ADVANCED=y
> +CONFIG_BSD_DISKLABEL=y
> +CONFIG_MINIX_SUBPARTITION=y
> +CONFIG_SOLARIS_X86_PARTITION=y
> +CONFIG_UNIXWARE_DISKLABEL=y
> +CONFIG_LDM_PARTITION=y

You have some rather unusual options in here. I'd suggest you go through
the reduced defconfig file and remove all options that look like they
are unnecessary for your system.

It's probably based on some distro config that enables lots of modules
you don't actually want.

> +#define LP8X4X_FPGA_PHYS 0x17000000
> +#define LP8X4X_FPGA_VIRT ((void *) 0xf1000000)
> +#define LP8X4X_P2V(x) IOMEM((x) - LP8X4X_FPGA_PHYS + LP8X4X_FPGA_VIRT)
> +#define LP8X4X_V2P(x) ((x) - LP8X4X_FPGA_VIRT + LP8X4X_FPGA_PHYS)

I think you misunderstood my comment, the point was that you should
move the IOMEM() to the LP8X4X_FPGA_VIRT definition, like

#define LP8X4X_FPGA_VIRT ((void __iomem *) 0xf1000000)
#define LP8X4X_P2V(x) (x) - LP8X4X_FPGA_PHYS + LP8X4X_FPGA_VIRT)

which would result in the correct type because of pointer arithmetics.

> +/* board level registers in the FPGA */
> +
> +#define LP8X4X_EOI LP8X4X_P2V(0x17009006)
> +#define LP8X4X_INSINT LP8X4X_P2V(0x17009008)
> +#define LP8X4X_ENSYSINT LP8X4X_P2V(0x1700900A)
> +#define LP8X4X_PRIMINT LP8X4X_P2V(0x1700900C)
> +#define LP8X4X_SECOINT LP8X4X_P2V(0x1700900E)
> +#define LP8X4X_ENRISEINT LP8X4X_P2V(0x17009010)
> +#define LP8X4X_CLRRISEINT LP8X4X_P2V(0x17009012)
> +#define LP8X4X_ENHILVINT LP8X4X_P2V(0x17009014)
> +#define LP8X4X_CLRHILVINT LP8X4X_P2V(0x17009016)
> +#define LP8X4X_ENFALLINT LP8X4X_P2V(0x17009018)
> +#define LP8X4X_CLRFALLINT LP8X4X_P2V(0x1700901a)

Thinking about this again, it's actually better if you just get rid of
LP8X4X_P2V() entirely and redefine these to

#define LP8X4X_EOI 0x0006
#define LP8X4X_INSINT 0x0008
...

and change the users to do e.g.

readl(LP8X4X_FPGA_VIRT + LP8X4X_INSINT);

This is closer to the normal way of adding the offset to an __iomem
pointer returned from ioremap.

> + platform_device_register_resndata(NULL, "pxa2xx-flash", 0,
> + &lp8x4x_flash_resources[0], 1,
> + &lp8x4x_flash_data[0], sizeof(lp8x4x_flash_data[0]));
> + platform_device_register_resndata(NULL, "pxa2xx-flash", 1,
> + &lp8x4x_flash_resources[1], 1,
> + &lp8x4x_flash_data[1], sizeof(lp8x4x_flash_data[1]));
> + platform_device_register_simple("dm9000", 0,
> + &lp8x4x_dm9000_resources[0], 3);
> + platform_device_register_simple("dm9000", 1,
> + &lp8x4x_dm9000_resources[3], 3);

This looks much better than the first version, a slight improvement IMHO would
be to split the resource arrays into one symbol per device to turn this into

platform_device_register_resndata(NULL, "pxa2xx-flash", 0,
&lp8x4x_flash_resources0, 1,
&lp8x4x_flash_data0, sizeof(lp8x4x_flash_data0));
platform_device_register_resndata(NULL, "pxa2xx-flash", 1,
&lp8x4x_flash_resources1, 1,
&lp8x4x_flash_data1, sizeof(lp8x4x_flash_data1));

It's not important though if you have a strong preference for the way you
did this, it just seems unusual.

Arnd

Sergei Ianovich

unread,
Dec 8, 2013, 2:10:01 AM12/8/13
to
On Sun, 2013-12-08 at 03:21 +0100, Arnd Bergmann wrote:
> On Friday 06 December 2013, Sergei Ianovich wrote:
> You have some rather unusual options in here. I'd suggest you go through
> the reduced defconfig file and remove all options that look like they
> are unnecessary for your system.
>
> It's probably based on some distro config that enables lots of modules
> you don't actually want.

I tried to future-proof the config, by enabling all partition tables and
USB disks and modems that could be plugged into the device.

I'll remove those. However, I would like to retain config options
related to low latency and small kernel size. Keeping them will
hopefully allow being notified about changes affecting the system.

Will this fly?
I am trying to boot the system with device tree. If I manage, I'll move
this code into drivers/irqchip/ as a platform device. Otherwise, I'll
make this change.

> This is closer to the normal way of adding the offset to an __iomem
> pointer returned from ioremap.
>
> > + platform_device_register_resndata(NULL, "pxa2xx-flash", 0,
> > + &lp8x4x_flash_resources[0], 1,
> > + &lp8x4x_flash_data[0], sizeof(lp8x4x_flash_data[0]));
> > + platform_device_register_resndata(NULL, "pxa2xx-flash", 1,
> > + &lp8x4x_flash_resources[1], 1,
> > + &lp8x4x_flash_data[1], sizeof(lp8x4x_flash_data[1]));
> > + platform_device_register_simple("dm9000", 0,
> > + &lp8x4x_dm9000_resources[0], 3);
> > + platform_device_register_simple("dm9000", 1,
> > + &lp8x4x_dm9000_resources[3], 3);
>
> This looks much better than the first version, a slight improvement IMHO would
> be to split the resource arrays into one symbol per device to turn this into
>
> platform_device_register_resndata(NULL, "pxa2xx-flash", 0,
> &lp8x4x_flash_resources0, 1,
> &lp8x4x_flash_data0, sizeof(lp8x4x_flash_data0));
> platform_device_register_resndata(NULL, "pxa2xx-flash", 1,
> &lp8x4x_flash_resources1, 1,
> &lp8x4x_flash_data1, sizeof(lp8x4x_flash_data1));
>
> It's not important though if you have a strong preference for the way you
> did this, it just seems unusual.

I'll make this change, if device tree doesn't boot.

Thanks for reviewing.

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:01 PM12/8/13
to
Except for defconfig, this is a completely new series. The first
eight patches fix outstanding issues with device tree support
in PXA. The 9th boots ICP DAS LP-8x4x.

Daniel chose to add a lot of selects for his MACH_PXA3XX_DT config
option. I feel that it will be easier to create multi-machine kernel
configurations and support per-machine workaround, if those selects
reside in separate machine options.

If Daniel agrees with my arguments, MACH_PXA3XX_DT and MACH_PXA27X_DT
could be merged into a single MACH_PXA_DT option.

CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>

Sergei Ianovich (9):
ARM: dts: pxa2xx fix compatible strings
ARM: dts: fix pxa27x-gpio interrupts
ARM: fix ohci-pxa27x build error with OF enabled
ARM: pxa: remove unused variable
ARM: dts: provide DMA config to pxamci
ARM: dts: pxa3xx: move declaration to header
ARM: dts: pxa27x: skip static platform devices
ARM: dts: pxa27x: device tree irq init
ARM: pxa27x: device tree support ICP DAS LP-8x4x

Documentation/devicetree/bindings/mmc/pxa-mmc.txt | 2 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/pxa27x-lp8x4x.dts | 111 +++++++++++++++
arch/arm/boot/dts/pxa27x.dtsi | 10 ++
arch/arm/boot/dts/pxa2xx.dtsi | 5 +-
arch/arm/configs/lp8x4x_defconfig | 162 ++++++++++++++++++++++
arch/arm/mach-pxa/Kconfig | 31 +++++
arch/arm/mach-pxa/Makefile | 1 +
arch/arm/mach-pxa/include/mach/irqs.h | 4 +
arch/arm/mach-pxa/include/mach/pxa27x.h | 4 +
arch/arm/mach-pxa/irq.c | 2 -
arch/arm/mach-pxa/pxa27x-dt.c | 97 +++++++++++++
arch/arm/mach-pxa/pxa27x.c | 17 +++
arch/arm/mach-pxa/pxa3xx.c | 2 -
drivers/mmc/host/pxamci.c | 50 +++++--
drivers/usb/host/ohci-pxa27x.c | 1 +
16 files changed, 482 insertions(+), 18 deletions(-)
create mode 100644 arch/arm/boot/dts/pxa27x-lp8x4x.dts
create mode 100644 arch/arm/configs/lp8x4x_defconfig
create mode 100644 arch/arm/mach-pxa/pxa27x-dt.c

--
1.8.4.3

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:01 PM12/8/13
to
Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
---
arch/arm/mach-pxa/irq.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index b6cc181..432842c 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -236,7 +236,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
{
struct device_node *node;
const struct of_device_id *of_id;
- struct pxa_intc_conf *conf;
struct resource res;
int n, ret;

@@ -246,7 +245,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
return;
}
of_id = of_match_node(intc_ids, node);
- conf = of_id->data;

ret = of_property_read_u32(node, "marvell,intc-nr-irqs",
&pxa_internal_irq_nr);

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:02 PM12/8/13
to
Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
arch/arm/boot/dts/pxa27x.dtsi | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/pxa27x.dtsi b/arch/arm/boot/dts/pxa27x.dtsi
index d7c5d72..44df554 100644
--- a/arch/arm/boot/dts/pxa27x.dtsi
+++ b/arch/arm/boot/dts/pxa27x.dtsi
@@ -10,5 +10,11 @@
marvell,intc-priority;
marvell,intc-nr-irqs = <34>;
};
+
+ gpio: gpio@40e00000 {
+ compatible = "intel,pxa27x-gpio";
+ interrupts = <8>, <9>, <10>;
+ interrupt-names = "gpio0", "gpio1", "gpio_mux";
+ };
};
};

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:02 PM12/8/13
to
Static plaform devices are created from postcore_initcall(). The
status quo remains for non-device tree machines.

Device tree machine now have a chance to prevent spawning of static
devices by calling pxa27x_skip_init().

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Russell King - ARM Linux <li...@arm.linux.org.uk>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
arch/arm/mach-pxa/include/mach/pxa27x.h | 1 +
arch/arm/mach-pxa/pxa27x.c | 10 ++++++++++
2 files changed, 11 insertions(+)

diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/include/mach/pxa27x.h
index 7cff640..d62fc8f 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/pxa27x.h
@@ -23,6 +23,7 @@ extern void __init pxa27x_map_io(void);
extern void __init pxa27x_init_irq(void);
extern int __init pxa27x_set_pwrmode(unsigned int mode);
extern void pxa27x_cpu_pm_enter(suspend_state_t state);
+extern void __init pxa27x_skip_init(void);

#define pxa27x_handle_irq ichp_handle_irq

diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 301471a..98dea3a 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -452,6 +452,13 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_pwm1,
};

+static unsigned int skip_init;
+
+void __init pxa27x_skip_init(void)
+{
+ skip_init = 1;
+}
+
static int __init pxa27x_init(void)
{
int ret = 0;
@@ -471,6 +478,9 @@ static int __init pxa27x_init(void)
register_syscore_ops(&pxa2xx_mfp_syscore_ops);
register_syscore_ops(&pxa2xx_clock_syscore_ops);

+ if (skip_init)
+ return 0;
+
pxa_register_device(&pxa27x_device_gpio, &pxa27x_gpio_info);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:02 PM12/8/13
to
This way it will be more difficult to change the declaration in one
place, but not the other.

In addition, the change allows to use the binding for pxa-gpio on
other PXA CPUs.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
arch/arm/mach-pxa/include/mach/irqs.h | 4 ++++
arch/arm/mach-pxa/pxa3xx.c | 2 --
2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-pxa/include/mach/irqs.h b/arch/arm/mach-pxa/include/mach/irqs.h
index 48c2fd8..0d71ae9 100644
--- a/arch/arm/mach-pxa/include/mach/irqs.h
+++ b/arch/arm/mach-pxa/include/mach/irqs.h
@@ -113,4 +113,8 @@ void ichp_handle_irq(struct pt_regs *);
void pxa_init_irq(int irq_nr, int (*set_wake)(struct irq_data *, unsigned int));
#endif

+#ifdef CONFIG_OF
+extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int));
+#endif /* CONFIG_OF */
+
#endif /* __ASM_MACH_IRQS_H */
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 87011f3..2397dec 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -42,8 +42,6 @@
#define PECR_IE(n) ((1 << ((n) * 2)) << 28)
#define PECR_IS(n) ((1 << ((n) * 2)) << 29)

-extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int));
-
static DEFINE_PXA3_CKEN(pxa3xx_ffuart, FFUART, 14857000, 1);
static DEFINE_PXA3_CKEN(pxa3xx_btuart, BTUART, 14857000, 1);
static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1);

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:02 PM12/8/13
to
ICP DAS calls LP-8x4x 'programmable automation controller'. It is
an industrial computer based on PXA270 SoC. They ship it with a 2.6.19
kernel and proprietary kernel module and userspace library to access
its industrial IO.

This patch allows to boot the device with a modern kernel with device
tree. It adds support for:
* MMC card interface on PXA270
* USB 1.1 port on PXA270
* 2 NOR flash devices
* 2 onboard ethernet Davicom DM9000 devices
* 3 serial UART ports on PXA270

Support for these devices will be added in separate patches, since
they are not currently supported by the kernel:
* DS1302 RTC
* 512kiB SRAM
* FPGA irq chip
* 3 built-in and up to 32 pluggable 8250 serial UART ports
* industrial IO parallel bus
* digital and analog industrial IO modules for parallel bus
* serial interface for digital and analog industrial IO modules on
parallel bus

Not supported for now:
* VGA interface on PXA270 for lack of dts binding

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
CC: Olof Johansson <ol...@lixom.net>
CC: Linus Walleij <linus....@linaro.org>
---
Changes v2..v3:
* further clean up defconfig (minus 100 lines more) as suggested
by Arnd Bergmann

* rewrite machine support code to use device tree

changes v1..v2
* clean up defconfig (reduces size by 10) as suggested
by Arnd Bergmann

* the rest is now irrelevant

arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/pxa27x-lp8x4x.dts | 111 ++++++++++++++++++++++++
arch/arm/configs/lp8x4x_defconfig | 162 ++++++++++++++++++++++++++++++++++++
arch/arm/mach-pxa/Kconfig | 31 +++++++
arch/arm/mach-pxa/Makefile | 1 +
arch/arm/mach-pxa/pxa27x-dt.c | 97 +++++++++++++++++++++
6 files changed, 403 insertions(+)
create mode 100644 arch/arm/boot/dts/pxa27x-lp8x4x.dts
create mode 100644 arch/arm/configs/lp8x4x_defconfig
create mode 100644 arch/arm/mach-pxa/pxa27x-dt.c

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index d57c1a6..c4752ff 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -206,6 +206,7 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
dra7-evm.dtb
dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-ethernet-disk-mini-v2.dtb
dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb
+dtb-$(CONFIG_MACH_PXA27X_DT) += pxa27x-lp8x4x.dtb
dtb-$(CONFIG_ARCH_U8500) += ste-snowball.dtb \
ste-hrefprev60-stuib.dtb \
ste-hrefprev60-tvk.dtb \
diff --git a/arch/arm/boot/dts/pxa27x-lp8x4x.dts b/arch/arm/boot/dts/pxa27x-lp8x4x.dts
new file mode 100644
index 0000000..b288c98
--- /dev/null
+++ b/arch/arm/boot/dts/pxa27x-lp8x4x.dts
@@ -0,0 +1,111 @@
+/* Device tree for ICP DAS LP-8x4x */
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "pxa27x.dtsi"
+
+/ {
+ model = "ICP DAS LP-8x4x programmable automation controller";
+ compatible = "marvell,lp8x4x", "marvell,pxa27x";
+
+ memory {
+ reg = <0xa0000000 0x08000000>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vmmc: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "vmmc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+
+ flash@00000000 {
+ compatible = "cfi-flash";
+ reg = <0x0 0x02000000>;
+ bank-width = <4>;
+ device-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ fs@0 {
+ label = "u-boot";
+ reg = <0 0x40000>;
+ };
+ fs@40000 {
+ label = "settings";
+ reg = <0x40000 0x40000>;
+ };
+ fs@80000 {
+ label = "kernel";
+ reg = <0x80000 0x280000>;
+ };
+ fs@300000 {
+ label = "root_fs";
+ reg = <0x300000 0x1d00000>;
+ };
+ };
+
+ flash@04000000 {
+ compatible = "cfi-flash";
+ reg = <0x04000000 0x02000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ pxabus {
+ pxairq: interrupt-controller@40d00000 {
+ marvell,intc-priority;
+ marvell,intc-nr-irqs = <34>;
+ };
+
+ uart@40100000 {
+ status = "okay";
+ };
+
+ uart@40200000 {
+ status = "okay";
+ };
+
+ uart@40700000 {
+ status = "okay";
+ };
+
+ mmc@41100000 {
+ status = "okay";
+ vmmc-supply = <&vmmc>;
+ marvell,dma-channels = <21 22>;
+ };
+
+ ohci@4c000000 {
+ status = "okay";
+ marvell,port-mode = <3>;
+ marvell,oc-mode-perport;
+ marvell,enable-port1;
+ };
+
+ eth0: eth@0c000000 {
+ compatible = "davicom,dm9000";
+ reg = <0x0c000000 0x2
+ 0x0c004000 0x2>;
+ interrupt-parent = <&gpio>;
+ interrupts = <9 IRQ_TYPE_EDGE_RISING>;
+ status = "okay";
+ };
+
+ eth1: eth@0d000000 {
+ compatible = "davicom,dm9000";
+ reg = <0x0d000000 0x2
+ 0x0d004000 0x2>;
+ interrupt-parent = <&gpio>;
+ interrupts = <82 IRQ_TYPE_EDGE_RISING>;
+ status = "okay";
+ };
+ };
+};
diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
new file mode 100644
index 0000000..faaa604
--- /dev/null
+++ b/arch/arm/configs/lp8x4x_defconfig
@@ -0,0 +1,162 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_RCU_BOOST=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_SHMEM is not set
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_LBDAF is not set
+CONFIG_BLK_CMDLINE_PARSER=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_PXA=y
+CONFIG_MACH_PXA27X_DT=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_FB=y
+CONFIG_FB_PXA=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_USB=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_SERIAL=m
+CONFIG_MMC=y
+CONFIG_MMC_PXA=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PXA=m
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=m
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
+CONFIG_REISERFS_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CODA_FS=m
+CONFIG_NLS_DEFAULT="cp855"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 96100db..f0c8f01 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -4,6 +4,20 @@ menu "Intel PXA2xx/PXA3xx Implementations"

comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"

+config MACH_PXA27X_DT
+ bool "Support PXA27x platforms from device tree"
+ select USE_OF
+ help
+ Include support for Marvell PXA27x based platforms using
+ the device tree.
+
+ While MACH_PXA27X_DT when enabled should boot any PXA27x
+ compatible machine, it still makes sense to select specific
+ machines. Those options will select required features and
+ provide per-machine errata workarounds.
+
+ If unsure, say Y.
+
config MACH_PXA3XX_DT
bool "Support PXA3xx platforms from device tree"
select CPU_PXA300
@@ -273,6 +287,23 @@ config MACH_VPAC270

comment "End-user Products (sorted by vendor name)"

+config MACH_LP8X4X
+ bool "ICP DAS LP-8X4X (device tree)"
+ depends on MACH_PXA27X_DT
+ select IWMMXT
+ select PXA27x
+ help
+ Say Y here if you intend to run this kernel on an ICP DAS
+ LP-8x4x programmable automation controller.
+
+ LP-8x4x is ARM-based and built around PXA270 SoC. The device
+ has 128 MiB SDRAM, 48 or 96 MiB NOR flash, VGA port with
+ 800x600 resolution, MMC card slot, 2 Ethernet ports, 1 USB
+ port, 5 serial ports (1 on them is wired internally to
+ expansion slots). The device has a range of digital and
+ analog expansion IO modules which can be installed in 1, 4 or
+ 8 slots depending on the model.
+
config MACH_H4700
bool "HP iPAQ hx4700"
select HAVE_PWM
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 648867a..adaa72a 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o
# NOTE: keep the order of boards in accordance to their order in Kconfig

# Device Tree support
+obj-$(CONFIG_MACH_PXA27X_DT) += pxa27x-dt.o
obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o

# Intel/Marvell Dev Platforms
diff --git a/arch/arm/mach-pxa/pxa27x-dt.c b/arch/arm/mach-pxa/pxa27x-dt.c
new file mode 100644
index 0000000..95c6ef4
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa27x-dt.c
@@ -0,0 +1,97 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa27x-dt.c
+ *
+ * Copyright (C) 2013 Sergei Ianovich
+ *
+ * based mostly on linux/arch/arm/mach-pxa/pxa-dt.c by Daniel Mack
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/irqs.h>
+#include <mach/pxa27x.h>
+
+#include "generic.h"
+
+#ifdef CONFIG_PXA27x
+extern void __init pxa27x_dt_init_irq(void);
+
+static const struct of_dev_auxdata pxa27x_auxdata_lookup[] __initconst = {
+ OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL),
+ OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL),
+ OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40700000, "pxa2xx-uart.2", NULL),
+ OF_DEV_AUXDATA("mrvl,pxa-uart", 0x41600000, "pxa2xx-uart.3", NULL),
+ OF_DEV_AUXDATA("marvell,pxa-mmc", 0x41100000, "pxa2xx-mci.0", NULL),
+ OF_DEV_AUXDATA("intel,pxa27x-gpio", 0x40e00000, "pxa27x-gpio", NULL),
+ OF_DEV_AUXDATA("marvell,pxa-ohci", 0x4c000000, "pxa27x-ohci", NULL),
+ OF_DEV_AUXDATA("mrvl,pxa-i2c", 0x40301680, "pxa2xx-i2c.0", NULL),
+ {}
+};
+
+static void __init pxa27x_init_early(void)
+{
+ pxa27x_skip_init();
+}
+
+static void __init pxa27x_dt_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table,
+ pxa27x_auxdata_lookup, NULL);
+}
+
+static const char *pxa27x_dt_board_compat[] __initdata = {
+ "marvell,pxa27x",
+ NULL,
+};
+
+#ifdef CONFIG_MACH_LP8X4X
+static const char *lp8x4x_dt_board_compat[] __initdata = {
+ "marvell,lp8x4x",
+ NULL,
+};
+
+static void lp8x4x_restart(enum reboot_mode mode, const char *cmd)
+{
+ /* Switch off fast-bus and turbo mode */
+ asm volatile("mcr p14, 0, %0, c6, c0, 0" : :
+ "r"(2));
+ /* SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) */
+ pxa_restart(REBOOT_SOFT, cmd);
+}
+#endif
+#endif
+
+#ifdef CONFIG_PXA27x
+DT_MACHINE_START(PXA27X_DT, "Marvell PXA27x (Device Tree Support)")
+ .map_io = pxa27x_map_io,
+ .init_irq = pxa27x_dt_init_irq,
+ .handle_irq = pxa27x_handle_irq,
+ .init_time = pxa_timer_init,
+ .restart = pxa_restart,
+ .init_early = pxa27x_init_early,
+ .init_machine = pxa27x_dt_init,
+ .dt_compat = pxa27x_dt_board_compat,
+MACHINE_END
+
+#ifdef CONFIG_MACH_LP8X4X
+DT_MACHINE_START(LP8X4X_DT, "ICP DAS LP-8X4X (Device Tree Support)")
+ .map_io = pxa27x_map_io,
+ .init_irq = pxa27x_dt_init_irq,
+ .handle_irq = pxa27x_handle_irq,
+ .init_time = pxa_timer_init,
+ .restart = lp8x4x_restart,
+ .init_early = pxa27x_init_early,
+ .init_machine = pxa27x_dt_init,
+ .dt_compat = lp8x4x_dt_board_compat,
+MACHINE_END
+#endif
+#endif

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:02 PM12/8/13
to
Non-dts implementation supply required DMA channel numbers as
IORESOURCE_DMA. However, there is was no way to get them from
device tree.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
Documentation/devicetree/bindings/mmc/pxa-mmc.txt | 2 +
arch/arm/boot/dts/pxa27x.dtsi | 4 ++
drivers/mmc/host/pxamci.c | 50 ++++++++++++++++++-----
3 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/pxa-mmc.txt b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt
index b7025de..27447ec 100644
--- a/Documentation/devicetree/bindings/mmc/pxa-mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt
@@ -5,6 +5,7 @@ Driver bindings for the PXA MCI (MMC/SDIO) interfaces
Required properties:
- compatible: Should be "marvell,pxa-mmc".
- vmmc-supply: A regulator for VMMC
+- marvell,dma-channels: 2 PXA DMA channels [0] for RX, [1] for TX

Optional properties:
- marvell,detect-delay-ms: sets the detection delay timeout in ms.
@@ -19,6 +20,7 @@ mmc0: mmc@41100000 {
compatible = "marvell,pxa-mmc";
reg = <0x41100000 0x1000>;
interrupts = <23>;
+ marvell,dma-channels = <21 22>;
cd-gpios = <&gpio 23 0>;
wp-gpios = <&gpio 24 0>;
};
diff --git a/arch/arm/boot/dts/pxa27x.dtsi b/arch/arm/boot/dts/pxa27x.dtsi
index 44df554..3f97520 100644
--- a/arch/arm/boot/dts/pxa27x.dtsi
+++ b/arch/arm/boot/dts/pxa27x.dtsi
@@ -16,5 +16,9 @@
interrupts = <8>, <9>, <10>;
interrupt-names = "gpio0", "gpio1", "gpio_mux";
};
+
+ mmc@41100000 {
+ marvell,dma-channels = <21 22>;
+ };
};
};
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 32fe113..8c7a110 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -613,11 +613,37 @@ static int pxamci_of_init(struct platform_device *pdev)

return 0;
}
+
+static int pxamci_of_init_dma(struct platform_device *pdev,
+ struct pxamci_host *host)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 tmp;
+ int ret;
+
+ ret = of_property_read_u32_index(np, "marvell,dma-channels", 0, &tmp);
+ if (ret < 0)
+ return ret;
+ host->dma_drcmrrx = tmp;
+
+ ret = of_property_read_u32_index(np, "marvell,dma-channels", 1, &tmp);
+ if (ret < 0)
+ return ret;
+ host->dma_drcmrtx = tmp;
+
+ return 0;
+}
#else
static int pxamci_of_init(struct platform_device *pdev)
{
return 0;
}
+
+static int pxamci_of_init_dma(struct platform_device *pdev,
+ struct pxamci_host *host)
+{
+ return -ENODATA;
+}
#endif

static int pxamci_probe(struct platform_device *pdev)
@@ -741,19 +767,21 @@ static int pxamci_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, mmc);

- dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmarx) {
- ret = -ENXIO;
- goto out;
- }
- host->dma_drcmrrx = dmarx->start;
+ if (pxamci_of_init_dma(pdev, host) < 0) {
+ dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmarx) {
+ ret = -ENXIO;
+ goto out;
+ }
+ host->dma_drcmrrx = dmarx->start;

- dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmatx) {
- ret = -ENXIO;
- goto out;
+ dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmatx) {
+ ret = -ENXIO;
+ goto out;
+ }
+ host->dma_drcmrtx = dmatx->start;
}
- host->dma_drcmrtx = dmatx->start;

if (host->pdata) {
gpio_cd = host->pdata->gpio_card_detect;

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:02 PM12/8/13
to
--->8---
$ make
CC [M] drivers/usb/host/ohci-pxa27x.o
drivers/usb/host/ohci-pxa27x.c: In function ‘ohci_pxa_of_init’:
drivers/usb/host/ohci-pxa27x.c:310:2: error: implicit declaration of function ‘dma_coerce_mask_and_coherent’ [-Werror=implicit-function-declaration]
drivers/usb/host/ohci-pxa27x.c:310:2: error: implicit declaration of function ‘DMA_BIT_MASK’ [-Werror=implicit-function-declaration]
--->8---

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Russell King - ARM Linux <li...@arm.linux.org.uk>

# Changes to be committed:
---
drivers/usb/host/ohci-pxa27x.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index e89ac4d..97983fd 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/dma-mapping.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:02 PM12/8/13
to
Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
arch/arm/boot/dts/pxa2xx.dtsi | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/pxa2xx.dtsi b/arch/arm/boot/dts/pxa2xx.dtsi
index a5e90f0..3419f87 100644
--- a/arch/arm/boot/dts/pxa2xx.dtsi
+++ b/arch/arm/boot/dts/pxa2xx.dtsi
@@ -18,7 +18,6 @@
serial1 = &btuart;
serial2 = &stuart;
serial3 = &hwuart;
- i2c0 = &pwri2c;
i2c1 = &pxai2c1;
};

@@ -113,14 +112,14 @@
};

usb0: ohci@4c000000 {
- compatible = "mrvl,pxa-ohci";
+ compatible = "marvell,pxa-ohci";
reg = <0x4c000000 0x10000>;
interrupts = <3>;
status = "disabled";
};

mmc0: mmc@41100000 {
- compatible = "mrvl,pxa-mmc";
+ compatible = "marvell,pxa-mmc";
reg = <0x41100000 0x1000>;
interrupts = <23>;
status = "disabled";

Sergei Ianovich

unread,
Dec 8, 2013, 6:00:02 PM12/8/13
to
Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
arch/arm/mach-pxa/include/mach/pxa27x.h | 3 +++
arch/arm/mach-pxa/pxa27x.c | 7 +++++++
2 files changed, 10 insertions(+)

diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/include/mach/pxa27x.h
index d62fc8f..64d0804 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/pxa27x.h
@@ -24,6 +24,9 @@ extern void __init pxa27x_init_irq(void);
extern int __init pxa27x_set_pwrmode(unsigned int mode);
extern void pxa27x_cpu_pm_enter(suspend_state_t state);
extern void __init pxa27x_skip_init(void);
+#ifdef CONFIG_OF
+extern void __init pxa27x_dt_init_irq(void);
+#endif /* CONFIG_OF */

#define pxa27x_handle_irq ichp_handle_irq

diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 98dea3a..1235201 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -398,6 +398,13 @@ void __init pxa27x_init_irq(void)
pxa_init_irq(34, pxa27x_set_wake);
}

+#ifdef CONFIG_OF
+void __init pxa27x_dt_init_irq(void)
+{
+ pxa_dt_irq_init(pxa27x_set_wake);
+}
+#endif /* CONFIG_OF */
+
static struct map_desc pxa27x_io_desc[] __initdata = {
{ /* Mem Ctl */
.virtual = (unsigned long)SMEMC_VIRT,

Arnd Bergmann

unread,
Dec 8, 2013, 8:00:02 PM12/8/13
to
On Sunday 08 December 2013, Sergei Ianovich wrote:
> On Sun, 2013-12-08 at 03:21 +0100, Arnd Bergmann wrote:
> > On Friday 06 December 2013, Sergei Ianovich wrote:
> > You have some rather unusual options in here. I'd suggest you go through
> > the reduced defconfig file and remove all options that look like they
> > are unnecessary for your system.
> >
> > It's probably based on some distro config that enables lots of modules
> > you don't actually want.
>
> I tried to future-proof the config, by enabling all partition tables and
> USB disks and modems that could be plugged into the device.
>
> I'll remove those. However, I would like to retain config options
> related to low latency and small kernel size. Keeping them will
> hopefully allow being notified about changes affecting the system.
>
> Will this fly?

Yes, of course, keep as many as you need. I was just trying to ensure
that you had put some thought in it, and e.g. the various USB serial
modules and some other things appeared to be fairly random, but I can
see them making sense now.

> > #define LP8X4X_EOI 0x0006
> > #define LP8X4X_INSINT 0x0008
> > ...
> >
> > and change the users to do e.g.
> >
> > readl(LP8X4X_FPGA_VIRT + LP8X4X_INSINT);
>
> I am trying to boot the system with device tree. If I manage, I'll move
> this code into drivers/irqchip/ as a platform device. Otherwise, I'll
> make this change.

Ok, cool. If you need help with the DT conversion, just ask here or on
IRC (#armlinux or #mvlinux on freenode.net, there might also be a
PXA specific channel I don't know).

Arnd

Arnd Bergmann

unread,
Dec 8, 2013, 8:20:02 PM12/8/13
to
On Sunday 08 December 2013, Sergei Ianovich wrote:
> +#ifdef CONFIG_OF
> +extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int));
> +#endif /* CONFIG_OF */
> +

In general, don't put declarations like this into #ifdef, unless you need
an #else clause like

static inline void pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int) {}

Same in patch 8.

Arnd

Arnd Bergmann

unread,
Dec 8, 2013, 8:40:01 PM12/8/13
to
On Sunday 08 December 2013, Sergei Ianovich wrote:
> Non-dts implementation supply required DMA channel numbers as
> IORESOURCE_DMA. However, there is was no way to get them from
> device tree.

I just wrote a lengthy reply to this email to explain in what ways
you got it wrong, but then I saw that Daniel has already done all
the work in the right way in August, so nevermind that.

It hasn't made it upstream yet, but see http://list-archives.org/2013/08/07/linux-mtd-lists-infradead-org/patch-00-20-arm-pxa-move-core-and-drivers-to-dmaengine/f/3444199144
for how it's done. Maybe Daniel can comment on the status of his
patches.

Arnd

Arnd Bergmann

unread,
Dec 8, 2013, 8:50:02 PM12/8/13
to
On Sunday 08 December 2013, Sergei Ianovich wrote:
> +
> +#ifdef CONFIG_PXA27x
> +extern void __init pxa27x_dt_init_irq(void);

This is not the right place to put an 'extern' declaration, it should go into
a header file if it's really needed. Ideally you would not need it at all
and just add an IRQCHIP_DECLARE() line into the driver to automatically
probe it.

> +static const struct of_dev_auxdata pxa27x_auxdata_lookup[] __initconst = {
> + OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL),
> + OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL),
> + OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40700000, "pxa2xx-uart.2", NULL),
> + OF_DEV_AUXDATA("mrvl,pxa-uart", 0x41600000, "pxa2xx-uart.3", NULL),
> + OF_DEV_AUXDATA("marvell,pxa-mmc", 0x41100000, "pxa2xx-mci.0", NULL),
> + OF_DEV_AUXDATA("intel,pxa27x-gpio", 0x40e00000, "pxa27x-gpio", NULL),
> + OF_DEV_AUXDATA("marvell,pxa-ohci", 0x4c000000, "pxa27x-ohci", NULL),
> + OF_DEV_AUXDATA("mrvl,pxa-i2c", 0x40301680, "pxa2xx-i2c.0", NULL),
> + {}
> +};

I guess these are needed only for clock management purposes at the moment?

> +static void __init pxa27x_init_early(void)
> +{
> + pxa27x_skip_init();
> +}

I would prefer not to have an init_early function at all, and instead
check "if (of_have_populated_dt())" in pxa27x_init, or to split
that function into two.

> +static const char *pxa27x_dt_board_compat[] __initdata = {
> + "marvell,pxa27x",
> + NULL,
> +};
> +
> +#ifdef CONFIG_MACH_LP8X4X
> +static const char *lp8x4x_dt_board_compat[] __initdata = {
> + "marvell,lp8x4x",
> + NULL,
> +};

Note that you should not have wildcards in any "compatible" strings.
Just list all the combinations here (pxa270, pxa271, pxa272, and whatever
you need for lp8x4x).

> +static void lp8x4x_restart(enum reboot_mode mode, const char *cmd)
> +{
> + /* Switch off fast-bus and turbo mode */
> + asm volatile("mcr p14, 0, %0, c6, c0, 0" : :
> + "r"(2));
> + /* SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) */
> + pxa_restart(REBOOT_SOFT, cmd);
> +}
> +#endif
> +#endif

Since the only difference here is the restart logic, I would prefer here to
have only a single DT_MACHINE_START() and do

static void pxa27x_restart(enum reboot_mode mode, const char *cmd)
{
/* Switch off fast-bus and turbo mode */
if (of_machine_is_compatible("marvell,lp8x4x"))
asm volatile("mcr p14, 0, %0, c6, c0, 0" : : "r"(2));

/* SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) */
if (of_machine_is_compatible("marvell,pxa270"))
pxa_restart(REBOOT_SOFT, cmd);
}

Arnd

Arnd Bergmann

unread,
Dec 8, 2013, 9:00:02 PM12/8/13
to
On Sunday 08 December 2013, Sergei Ianovich wrote:
>
> Except for defconfig, this is a completely new series. The first
> eight patches fix outstanding issues with device tree support
> in PXA. The 9th boots ICP DAS LP-8x4x.

Awesome! That was very quick. The main comment I have is for the
dmaengine support, you will need to rebase on Daniel's patches for
that. I also found few minor details.

Arnd

Heikki Krogerus

unread,
Dec 9, 2013, 3:40:01 AM12/9/13
to
Hi,

On Fri, Dec 06, 2013 at 01:09:31PM +0400, Sergei Ianovich wrote:
> pxa2xx-uart was a separate uart platform driver. It was declaring
> the same device names and numbers as 8250 driver. As a result,
> it was impossible to use 8250 driver on PXA SoCs.
>
> Upon closer examination pxa2xx-uart turned out to be a clone of
> 8250_core driver.
>
> Workaround for Erratum #19 according to Marvel(R) PXA270M Processor
> Specification Update (April 19, 2010) is dropped. 8250_core reads
> from FIFO immediately after checking DR bit in LSR.
>
> Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
> CC: Heikki Krogerus <heikki....@linux.intel.com>
> CC: Greg Kroah-Hartman <gre...@linuxfoundation.org>
> CC: James Cameron <qu...@laptop.org>
> ---
> changes v1..v2
> * actually implement workaround for E74 in dl_write as spooted
> by James Cameron
> * added comment about E19 in commit message

Nice job Sergei! I have a few minor nitpicks below, but if they are
the only comments, don't bother with v3. I'm fine with this. For what
it's worth:

Reviewed-by: Heikki Krogerus <heikki....@linux.intel.com>

> arch/arm/configs/am200epdkit_defconfig | 3 +-
> arch/arm/configs/cm_x2xx_defconfig | 3 +-
> arch/arm/configs/cm_x300_defconfig | 3 +-
> arch/arm/configs/colibri_pxa270_defconfig | 3 +-
> arch/arm/configs/colibri_pxa300_defconfig | 3 +-
> arch/arm/configs/corgi_defconfig | 4 +-
> arch/arm/configs/em_x270_defconfig | 3 +-
> arch/arm/configs/ezx_defconfig | 3 +-
> arch/arm/configs/h5000_defconfig | 3 +-
> arch/arm/configs/imote2_defconfig | 3 +-
> arch/arm/configs/lpd270_defconfig | 3 +-
> arch/arm/configs/lubbock_defconfig | 3 +-
> arch/arm/configs/mainstone_defconfig | 3 +-
> arch/arm/configs/mmp2_defconfig | 3 +-
> arch/arm/configs/pcm027_defconfig | 3 +-
> arch/arm/configs/pxa168_defconfig | 3 +-
> arch/arm/configs/pxa255-idp_defconfig | 3 +-
> arch/arm/configs/pxa3xx_defconfig | 3 +-
> arch/arm/configs/pxa910_defconfig | 3 +-
> arch/arm/configs/raumfeld_defconfig | 3 +-
> arch/arm/configs/spitz_defconfig | 4 +-
> arch/arm/configs/trizeps4_defconfig | 3 +-
> arch/arm/configs/viper_defconfig | 4 +-
> arch/arm/configs/xcep_defconfig | 3 +-
> drivers/tty/serial/8250/8250_pxa.c | 189 ++++++
> drivers/tty/serial/8250/Kconfig | 9 +
> drivers/tty/serial/8250/Makefile | 1 +
> drivers/tty/serial/Kconfig | 23 -
> drivers/tty/serial/Makefile | 1 -
> drivers/tty/serial/pxa.c | 971 ------------------------------
> 30 files changed, 247 insertions(+), 1022 deletions(-)
> create mode 100644 drivers/tty/serial/8250/8250_pxa.c
> delete mode 100644 drivers/tty/serial/pxa.c

<snip>

> diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
> new file mode 100644
> index 0000000..88ae73c
> --- /dev/null
> +++ b/drivers/tty/serial/8250/8250_pxa.c
> @@ -0,0 +1,189 @@
> +/*
> + * drivers/tty/serial/8250/8250_pxa.c -- driver for PXA on-board UARTS
> + * Copyright: (C) 2013 Sergei Ianovich <ynv...@gmail.com>
> + *
> + * replaces drivers/serial/pxa.c by Nicolas Pitre
> + * Created: Feb 20, 2003
> + * Copyright: (C) 2003 Monta Vista Software, Inc.
> + *
> + * Based on drivers/serial/8250.c by Russell King.
> + *
> + * 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/device.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/serial_8250.h>
> +#include <linux/serial_core.h>
> +#include <linux/serial_reg.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/pm_runtime.h>
> +
> +#include "8250.h"
> +
> +struct pxa8250_data {
> + int line;
> + struct clk *clk;
> +};
> +
> +#ifdef CONFIG_PM
> +static int serial_pxa_suspend(struct device *dev)
> +{
> + struct pxa8250_data *data = dev_get_drvdata(dev);
> +
> + serial8250_suspend_port(data->line);
> +
> + return 0;
> +}
> +
> +static int serial_pxa_resume(struct device *dev)
> +{
> + struct pxa8250_data *data = dev_get_drvdata(dev);
> +
> + serial8250_resume_port(data->line);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops serial_pxa_pm_ops = {
> + .suspend = serial_pxa_suspend,
> + .resume = serial_pxa_resume,
> +};

If you leave this structure outside the ifdef CONFIG_PM and use
SET_SYSTEM_SLEEP_PM_OPS() macro, you don't need the ifdef when you set
the driver pm ops below.

> +#endif
> +
> +static struct of_device_id serial_pxa_dt_ids[] = {
> + { .compatible = "mrvl,pxa-uart", },
> + { .compatible = "mrvl,mmp-uart", },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
> +
> +/* Uart divisor latch write */
> +static void serial_pxa_dl_write(struct uart_8250_port *up, int value)
> +{
> + unsigned int dll;
> +
> + serial_out(up, UART_DLL, value & 0xff);
> + /*
> + * work around Erratum #74 according to Marvel(R) PXA270M Processor
> + * Specification Update (April 19, 2010)
> + */
> + dll = serial_in(up, UART_DLL);
> + WARN_ON(dll != (value & 0xff));
> +
> + serial_out(up, UART_DLM, value >> 8 & 0xff);
> +}
> +
> +
> +static void serial_pxa_pm(struct uart_port *port, unsigned int state,
> + unsigned int oldstate)
> +{
> + struct pxa8250_data *data = port->private_data;
> +
> + if (!state)
> + clk_prepare_enable(data->clk);
> + else
> + clk_disable_unprepare(data->clk);
> +}
> +
> +static int serial_pxa_probe(struct platform_device *pdev)
> +{
> + struct uart_8250_port uart = {};
> + struct pxa8250_data *data;
> + struct resource *mmres, *irqres;
> + int ret;
> +
> + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (!mmres || !irqres)
> + return -ENODEV;
> +
> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + data->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(data->clk)) {
> + ret = PTR_ERR(data->clk);
> + goto err_free;

You can just return here.

> + }
> +
> + ret = clk_prepare(data->clk);
> + if (ret)
> + goto err_free_clk;

ditto

> + uart.port.type = PORT_XSCALE;
> + uart.port.iotype = UPIO_MEM32;
> + uart.port.mapbase = mmres->start;
> + uart.port.regshift = 2;
> + uart.port.irq = irqres->start;
> + uart.port.fifosize = 64;
> + uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST;
> + uart.port.dev = &pdev->dev;
> + uart.port.uartclk = clk_get_rate(data->clk);
> + uart.port.pm = serial_pxa_pm;
> + uart.port.private_data = data;
> + uart.dl_write = serial_pxa_dl_write;
> +
> + ret = serial8250_register_8250_port(&uart);
> + if (ret < 0)
> + goto err_clk;
> +
> + data->line = ret;
> +
> + platform_set_drvdata(pdev, data);
> +
> + return 0;
> +
> + err_clk:
> + clk_unprepare(data->clk);
> + err_free_clk:
> + devm_clk_put(&pdev->dev, data->clk);
> + err_free:
> + devm_kfree(&pdev->dev, data);

And there labels could be dropped.

> + return ret;
> +}
> +
> +static int serial_pxa_remove(struct platform_device *pdev)
> +{
> + struct pxa8250_data *data = platform_get_drvdata(pdev);
> +
> + serial8250_unregister_port(data->line);
> +
> + clk_unprepare(data->clk);
> + devm_clk_put(&pdev->dev, data->clk);
> + devm_kfree(&pdev->dev, data);

You also don't need to call these resource freeing functions here.

> + return 0;
> +}
> +
> +static struct platform_driver serial_pxa_driver = {
> + .probe = serial_pxa_probe,
> + .remove = serial_pxa_remove,
> +
> + .driver = {
> + .name = "pxa2xx-uart",
> + .owner = THIS_MODULE,
> +#ifdef CONFIG_PM
> + .pm = &serial_pxa_pm_ops,
> +#endif
> + .of_match_table = serial_pxa_dt_ids,
> + },
> +};
> +
> +module_platform_driver(serial_pxa_driver);
> +
> +MODULE_AUTHOR("Sergei Ianovich");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:pxa2xx-uart");


Thanks,

--
heikki

Sascha Hauer

unread,
Dec 9, 2013, 3:50:02 AM12/9/13
to
On Mon, Dec 09, 2013 at 10:38:15AM +0200, Heikki Krogerus wrote:
> Hi,
>
> > + return 0;
> > +
> > + err_clk:
> > + clk_unprepare(data->clk);
> > + err_free_clk:
> > + devm_clk_put(&pdev->dev, data->clk);
> > + err_free:
> > + devm_kfree(&pdev->dev, data);
>
> And there labels could be dropped.

This should really be fixed. Explicitly releasing devm_* allocated
resources invalidates the whole idea of the devm functions. People
looking for templates shouldn't find examples for this in the kernel.

Sascha

--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |

Daniel Mack

unread,
Dec 9, 2013, 4:00:02 AM12/9/13
to
On 12/08/2013 11:53 PM, Sergei Ianovich wrote:
> Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
> CC: Daniel Mack <zon...@gmail.com>
> ---
> arch/arm/mach-pxa/irq.c | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
> index b6cc181..432842c 100644
> --- a/arch/arm/mach-pxa/irq.c
> +++ b/arch/arm/mach-pxa/irq.c
> @@ -236,7 +236,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
> {
> struct device_node *node;
> const struct of_device_id *of_id;
> - struct pxa_intc_conf *conf;
> struct resource res;
> int n, ret;
>
> @@ -246,7 +245,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
> return;
> }
> of_id = of_match_node(intc_ids, node);
> - conf = of_id->data;

A similar patch was already merged by Haojian recently. You should
probably rebase your patch stack on top of his maintainer tree.


Daniel

Sergei Ianovich

unread,
Dec 9, 2013, 4:40:02 AM12/9/13
to
On Mon, 2013-12-09 at 10:04 +0100, Daniel Mack wrote:
> On 12/09/2013 02:33 AM, Arnd Bergmann wrote:
> > On Sunday 08 December 2013, Sergei Ianovich wrote:
> >> Non-dts implementation supply required DMA channel numbers as
> >> IORESOURCE_DMA. However, there is was no way to get them from
> >> device tree.
> >
> > I just wrote a lengthy reply to this email to explain in what ways
> > you got it wrong, but then I saw that Daniel has already done all
> > the work in the right way in August, so nevermind that.
> >
> > It hasn't made it upstream yet, but see http://list-archives.org/2013/08/07/linux-mtd-lists-infradead-org/patch-00-20-arm-pxa-move-core-and-drivers-to-dmaengine/f/3444199144
> > for how it's done. Maybe Daniel can comment on the status of his
> > patches.
>
> I recently rebased all my patches on top of 3.13-rc3, and will resend in
> couple of days.
>
> The real problem here is that by reworking the DMA related PXA bits, all
> drivers have to be changed at once, and a gradual transition seems
> impossible. For that, I was asking for help in areas where I don't have
> any hardware to test my patches on, but unfortunately, nobody got back
> to me yet.

Nice to have Daniel in this conversation. Your patch series is a big and
important work. However, I am not sure I will ever land as is exactly
for this reason.

DMA is a per-physical-device concept, not per-platform. Only the DMA
controller is per-platform. This means we need to rewrite all platform
drivers at once. This is roughly equivalent to adding a new platform
support in one patch, which is not going to work.

In patch 08/20 in the series above, you change 10% lines of the pxa mmc
driver. If we don't count boilerplate lines, this will amount to over
50%. In other word, the output is a new driver.

My proposal in to actually add new drivers for each platform device with
DMA and mark new ones EXPERIMENTAL. When they receive adequate testing
we remove the tag and mark the old one OBSOLETE. When we have a new
driver for every device presently supported, we will drop the whole old
series.

This should be very close to a gradual transition.

While we are in transition, I propose that we allow 'hackish' support
for device tree in the existing drivers. Platform devices are declared
in dtsi files, so when we move to a new driver we just change the
compatible string there. Actual devices with their one dts file won't
need any change. They will need a dtb recompile, though. This way we can
begin a migration to device tree in pxa immediately.

The patch series does just that.

Sergei Ianovich

unread,
Dec 9, 2013, 4:50:04 AM12/9/13
to
On Mon, 2013-12-09 at 09:56 +0100, Daniel Mack wrote:
> A similar patch was already merged by Haojian recently. You should
> probably rebase your patch stack on top of his maintainer tree.

I've just come across the patch you mention in the arm mailing list.

Could you please provide a link to Haojian's official public repository?

If possible, a link link to your repository will also be very helpful.

My tree is at https://github.com/yanovich/linux

Daniel Mack

unread,
Dec 9, 2013, 5:00:02 AM12/9/13
to
On 12/09/2013 10:42 AM, Sergei Ianovich wrote:
> On Mon, 2013-12-09 at 09:56 +0100, Daniel Mack wrote:
>> A similar patch was already merged by Haojian recently. You should
>> probably rebase your patch stack on top of his maintainer tree.
>
> I've just come across the patch you mention in the arm mailing list.
>
> Could you please provide a link to Haojian's official public repository?

According to MAINTAINERS, it's here:

git://github.com/hzhuang1/linux.git

But it seems it hasn't seen an update recently. Haojian?

> If possible, a link link to your repository will also be very helpful.

https://github.com/zonque/linux/tree/pxa-dma-v2


Daniel

Sergei Ianovich

unread,
Dec 9, 2013, 5:00:03 AM12/9/13
to
On Mon, 2013-12-09 at 13:34 +0400, Sergei Ianovich wrote:
> On Mon, 2013-12-09 at 10:04 +0100, Daniel Mack wrote:
> > On 12/09/2013 02:33 AM, Arnd Bergmann wrote:
> > > On Sunday 08 December 2013, Sergei Ianovich wrote:
> > >> Non-dts implementation supply required DMA channel numbers as
> > >> IORESOURCE_DMA. However, there is was no way to get them from
> > >> device tree.
> > >
> > > I just wrote a lengthy reply to this email to explain in what ways
> > > you got it wrong, but then I saw that Daniel has already done all
> > > the work in the right way in August, so nevermind that.
> > >
> > > It hasn't made it upstream yet, but see http://list-archives.org/2013/08/07/linux-mtd-lists-infradead-org/patch-00-20-arm-pxa-move-core-and-drivers-to-dmaengine/f/3444199144
> > > for how it's done. Maybe Daniel can comment on the status of his
> > > patches.
> >
> > I recently rebased all my patches on top of 3.13-rc3, and will resend in
> > couple of days.
> >
> > The real problem here is that by reworking the DMA related PXA bits, all
> > drivers have to be changed at once, and a gradual transition seems
> > impossible. For that, I was asking for help in areas where I don't have
> > any hardware to test my patches on, but unfortunately, nobody got back
> > to me yet.
>
> Nice to have Daniel in this conversation. Your patch series is a big and
> important work. However, I am not sure I will ever land as is exactly
> for this reason.

s/I will/it will/

> DMA is a per-physical-device concept, not per-platform. Only the DMA
> controller is per-platform. This means we need to rewrite all platform
> drivers at once. This is roughly equivalent to adding a new platform
> support in one patch, which is not going to work.
>
> In patch 08/20 in the series above, you change 10% lines of the pxa mmc
> driver. If we don't count boilerplate lines, this will amount to over
> 50%. In other word, the output is a new driver.

s/other word/other words/

> My proposal in to actually add new drivers for each platform device with
> DMA and mark new ones EXPERIMENTAL. When they receive adequate testing
> we remove the tag and mark the old one OBSOLETE. When we have a new
> driver for every device presently supported, we will drop the whole old
> series.

s/proposal in/proposal is/

> This should be very close to a gradual transition.
>
> While we are in transition, I propose that we allow 'hackish' support
> for device tree in the existing drivers. Platform devices are declared
> in dtsi files, so when we move to a new driver we just change the
> compatible string there. Actual devices with their one dts file won't
> need any change. They will need a dtb recompile, though. This way we can
> begin a migration to device tree in pxa immediately.

s/their one/their own/

> The patch series does just that.

Sorry for noise.

Daniel Mack

unread,
Dec 9, 2013, 5:30:02 AM12/9/13
to
On 12/09/2013 10:34 AM, Sergei Ianovich wrote:
> On Mon, 2013-12-09 at 10:04 +0100, Daniel Mack wrote:
>> On 12/09/2013 02:33 AM, Arnd Bergmann wrote:
>>> On Sunday 08 December 2013, Sergei Ianovich wrote:
>>>> Non-dts implementation supply required DMA channel numbers as
>>>> IORESOURCE_DMA. However, there is was no way to get them from
>>>> device tree.
>>>
>>> I just wrote a lengthy reply to this email to explain in what ways
>>> you got it wrong, but then I saw that Daniel has already done all
>>> the work in the right way in August, so nevermind that.
>>>
>>> It hasn't made it upstream yet, but see http://list-archives.org/2013/08/07/linux-mtd-lists-infradead-org/patch-00-20-arm-pxa-move-core-and-drivers-to-dmaengine/f/3444199144
>>> for how it's done. Maybe Daniel can comment on the status of his
>>> patches.
>>
>> I recently rebased all my patches on top of 3.13-rc3, and will resend in
>> couple of days.
>>
>> The real problem here is that by reworking the DMA related PXA bits, all
>> drivers have to be changed at once, and a gradual transition seems
>> impossible. For that, I was asking for help in areas where I don't have
>> any hardware to test my patches on, but unfortunately, nobody got back
>> to me yet.
>
> Nice to have Daniel in this conversation. Your patch series is a big and
> important work. However, I am not sure I will ever land as is exactly
> for this reason.

Well, I wouldn't be so certain about that statement. As I wrote in the
cover letter, most of the work is actually done, and I successfully
tested the new DMA support with a some of the drivers I ported. Others
were ported blindly, and in case of no reaction, I'd dare to merge them
and wait for people to report back in case of trouble.

The only real problem is the PXA camera driver, which does tricky things
like hot re-queuing of DMA descriptors. That one needs fixing before the
series can land.

> My proposal in to actually add new drivers for each platform device with
> DMA and mark new ones EXPERIMENTAL.

That would cause tree-wide cross-dependencies between drivers, because
the two DMA controllers can't be used at the same time, and the PXA
specific API will be unavailable when the mmp-dma driver is selected. My
patch series (and the DMA controller framework for that matter) aims for
the opposite - the unification of APIs and drivers.

> When they receive adequate testing
> we remove the tag and mark the old one OBSOLETE. When we have a new
> driver for every device presently supported, we will drop the whole old
> series.

Well, given the feedback I got for the series so far, I fear we'll be
off to maintain two drivers for each peripheral for a very long time.

I'd rather propose cracking the last nut that's left, and then get the
thing merged.

Arnd, Haojian? Any opinion here?



Daniel

Sergei Ianovich

unread,
Dec 9, 2013, 6:50:02 AM12/9/13
to
pxa2xx-uart was a separate uart platform driver. It was declaring
the same device names and numbers as 8250 driver. As a result,
it was impossible to use 8250 driver on PXA SoCs.

Upon closer examination pxa2xx-uart turned out to be a clone of
8250_core driver.

Workaround for Erratum #19 according to Marvel(R) PXA270M Processor
Specification Update (April 19, 2010) is dropped. 8250_core reads
from FIFO immediately after checking DR bit in LSR.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
Reviewed-by: Heikki Krogerus <heikki....@linux.intel.com>
Reviewed-by: James Cameron <qu...@laptop.org>
CC: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
changes v2..v3
* remove devm_free/put as suggested by Heikki Krogerus
* use SET_SYSTEM_SLEEP_PM_OPS macro to set pm ops as suggested
by Heikki Krogerus

changes v1..v2
* actually implement workaround for E74 in dl_write as spooted
by James Cameron
* added comment about E19 in commit message

arch/arm/configs/am200epdkit_defconfig | 3 +-
arch/arm/configs/cm_x2xx_defconfig | 3 +-
arch/arm/configs/cm_x300_defconfig | 3 +-
arch/arm/configs/colibri_pxa270_defconfig | 3 +-
arch/arm/configs/colibri_pxa300_defconfig | 3 +-
arch/arm/configs/corgi_defconfig | 4 +-
arch/arm/configs/em_x270_defconfig | 3 +-
arch/arm/configs/ezx_defconfig | 3 +-
arch/arm/configs/h5000_defconfig | 3 +-
arch/arm/configs/imote2_defconfig | 3 +-
arch/arm/configs/lpd270_defconfig | 3 +-
arch/arm/configs/lubbock_defconfig | 3 +-
arch/arm/configs/mainstone_defconfig | 3 +-
arch/arm/configs/mmp2_defconfig | 3 +-
arch/arm/configs/pcm027_defconfig | 3 +-
arch/arm/configs/pxa168_defconfig | 3 +-
arch/arm/configs/pxa255-idp_defconfig | 3 +-
arch/arm/configs/pxa3xx_defconfig | 3 +-
arch/arm/configs/pxa910_defconfig | 3 +-
arch/arm/configs/raumfeld_defconfig | 3 +-
arch/arm/configs/spitz_defconfig | 4 +-
arch/arm/configs/trizeps4_defconfig | 3 +-
arch/arm/configs/viper_defconfig | 4 +-
arch/arm/configs/xcep_defconfig | 3 +-
drivers/tty/serial/8250/8250_pxa.c | 178 ++++++
drivers/tty/serial/8250/Kconfig | 9 +
drivers/tty/serial/8250/Makefile | 1 +
drivers/tty/serial/Kconfig | 23 -
drivers/tty/serial/Makefile | 1 -
drivers/tty/serial/pxa.c | 971 ------------------------------
30 files changed, 236 insertions(+), 1022 deletions(-)
create mode 100644 drivers/tty/serial/8250/8250_pxa.c
delete mode 100644 drivers/tty/serial/pxa.c

diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig
index f0dea52..0cde234 100644
--- a/arch/arm/configs/am200epdkit_defconfig
+++ b/arch/arm/configs/am200epdkit_defconfig
@@ -60,8 +60,9 @@ CONFIG_BLK_DEV_IDECS=m
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_SMC91X=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/cm_x2xx_defconfig b/arch/arm/configs/cm_x2xx_defconfig
index a93ff8d..b9fbe65 100644
--- a/arch/arm/configs/cm_x2xx_defconfig
+++ b/arch/arm/configs/cm_x2xx_defconfig
@@ -96,8 +96,9 @@ CONFIG_KEYBOARD_PXA27x=m
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_UCB1400=m
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig
index f4b7672..53a82ae 100644
--- a/arch/arm/configs/cm_x300_defconfig
+++ b/arch/arm/configs/cm_x300_defconfig
@@ -80,8 +80,9 @@ CONFIG_TOUCHSCREEN_WM97XX=m
# CONFIG_TOUCHSCREEN_WM9713 is not set
# CONFIG_SERIO is not set
# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_PXA=y
diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig
index 2ef2c5e..1ce0409 100644
--- a/arch/arm/configs/colibri_pxa270_defconfig
+++ b/arch/arm/configs/colibri_pxa270_defconfig
@@ -103,8 +103,9 @@ CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/configs/colibri_pxa300_defconfig b/arch/arm/configs/colibri_pxa300_defconfig
index b985334..f96bda0 100644
--- a/arch/arm/configs/colibri_pxa300_defconfig
+++ b/arch/arm/configs/colibri_pxa300_defconfig
@@ -31,8 +31,9 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_MISC=y
CONFIG_INPUT_GPIO_ROTARY_ENCODER=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_DEBUG_GPIO=y
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig
index 1fd1d1d..bb4842d 100644
--- a/arch/arm/configs/corgi_defconfig
+++ b/arch/arm/configs/corgi_defconfig
@@ -131,10 +131,10 @@ CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
# CONFIG_SERIO is not set
-CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_CS=m
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_I2C=y
CONFIG_I2C_PXA=y
diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig
index 60a21e0..ec0ec54 100644
--- a/arch/arm/configs/em_x270_defconfig
+++ b/arch/arm/configs/em_x270_defconfig
@@ -90,8 +90,9 @@ CONFIG_TOUCHSCREEN_WM97XX=m
# CONFIG_TOUCHSCREEN_WM9705 is not set
# CONFIG_TOUCHSCREEN_WM9713 is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig
index d95763d..631e2ec 100644
--- a/arch/arm/configs/ezx_defconfig
+++ b/arch/arm/configs/ezx_defconfig
@@ -215,8 +215,9 @@ CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_PCAP=y
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=8
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/h5000_defconfig b/arch/arm/configs/h5000_defconfig
index 37903e3..655b735 100644
--- a/arch/arm/configs/h5000_defconfig
+++ b/arch/arm/configs/h5000_defconfig
@@ -47,8 +47,9 @@ CONFIG_MTD_PHYSMAP=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=32
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/imote2_defconfig b/arch/arm/configs/imote2_defconfig
index fd996bb..49d45e9 100644
--- a/arch/arm/configs/imote2_defconfig
+++ b/arch/arm/configs/imote2_defconfig
@@ -193,8 +193,9 @@ CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_LEGACY_PTY_COUNT=8
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/lpd270_defconfig b/arch/arm/configs/lpd270_defconfig
index 1c8c9ee..c3927b6 100644
--- a/arch/arm/configs/lpd270_defconfig
+++ b/arch/arm/configs/lpd270_defconfig
@@ -38,8 +38,9 @@ CONFIG_SMC91X=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_HW_RANDOM is not set
CONFIG_FB=y
CONFIG_FB_PXA=y
diff --git a/arch/arm/configs/lubbock_defconfig b/arch/arm/configs/lubbock_defconfig
index c4ba274..c8b0436 100644
--- a/arch/arm/configs/lubbock_defconfig
+++ b/arch/arm/configs/lubbock_defconfig
@@ -37,8 +37,9 @@ CONFIG_PCMCIA_PCNET=y
CONFIG_INPUT_EVDEV=y
# CONFIG_SERIO_SERPORT is not set
CONFIG_SERIO_SA1111=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_USB_GADGET=y
CONFIG_USB_G_SERIAL=m
diff --git a/arch/arm/configs/mainstone_defconfig b/arch/arm/configs/mainstone_defconfig
index 04efa1b..768892c 100644
--- a/arch/arm/configs/mainstone_defconfig
+++ b/arch/arm/configs/mainstone_defconfig
@@ -34,8 +34,9 @@ CONFIG_SMC91X=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_PXA=y
# CONFIG_VGA_CONSOLE is not set
diff --git a/arch/arm/configs/mmp2_defconfig b/arch/arm/configs/mmp2_defconfig
index f1cb95e..1ced9df 100644
--- a/arch/arm/configs/mmp2_defconfig
+++ b/arch/arm/configs/mmp2_defconfig
@@ -44,8 +44,9 @@ CONFIG_SMC91X=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig
index 2f136c3..1280128 100644
--- a/arch/arm/configs/pcm027_defconfig
+++ b/arch/arm/configs/pcm027_defconfig
@@ -60,8 +60,9 @@ CONFIG_SMC91X=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/pxa168_defconfig b/arch/arm/configs/pxa168_defconfig
index 74d7e01..1668dac 100644
--- a/arch/arm/configs/pxa168_defconfig
+++ b/arch/arm/configs/pxa168_defconfig
@@ -40,8 +40,9 @@ CONFIG_SMC91X=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/pxa255-idp_defconfig b/arch/arm/configs/pxa255-idp_defconfig
index 917a070..399a706 100644
--- a/arch/arm/configs/pxa255-idp_defconfig
+++ b/arch/arm/configs/pxa255-idp_defconfig
@@ -35,8 +35,9 @@ CONFIG_SMC91X=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_PXA=y
# CONFIG_VGA_CONSOLE is not set
diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig
index 60e3138..7c3e052 100644
--- a/arch/arm/configs/pxa3xx_defconfig
+++ b/arch/arm/configs/pxa3xx_defconfig
@@ -56,8 +56,9 @@ CONFIG_KEYBOARD_PXA27x=y
CONFIG_KEYBOARD_PXA930_ROTARY=y
CONFIG_MOUSE_PXA930_TRKBALL=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
diff --git a/arch/arm/configs/pxa910_defconfig b/arch/arm/configs/pxa910_defconfig
index 3bb7771..cdacfcb 100644
--- a/arch/arm/configs/pxa910_defconfig
+++ b/arch/arm/configs/pxa910_defconfig
@@ -40,8 +40,9 @@ CONFIG_SMC91X=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_SPI=y
CONFIG_FB=y
CONFIG_MMP_DISP=y
diff --git a/arch/arm/configs/raumfeld_defconfig b/arch/arm/configs/raumfeld_defconfig
index f7caa90..f1e16f2 100644
--- a/arch/arm/configs/raumfeld_defconfig
+++ b/arch/arm/configs/raumfeld_defconfig
@@ -67,8 +67,9 @@ CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_EETI=m
CONFIG_INPUT_MISC=y
CONFIG_INPUT_GPIO_ROTARY_ENCODER=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig
index 2e0419d..b6efcf5 100644
--- a/arch/arm/configs/spitz_defconfig
+++ b/arch/arm/configs/spitz_defconfig
@@ -128,10 +128,10 @@ CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
# CONFIG_SERIO is not set
-CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_CS=m
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_SPI=y
CONFIG_SPI_PXA2XX=y
diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig
index 3162173..453c79c 100644
--- a/arch/arm/configs/trizeps4_defconfig
+++ b/arch/arm/configs/trizeps4_defconfig
@@ -132,8 +132,9 @@ CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/configs/viper_defconfig b/arch/arm/configs/viper_defconfig
index d36e0d3..4efac06 100644
--- a/arch/arm/configs/viper_defconfig
+++ b/arch/arm/configs/viper_defconfig
@@ -101,11 +101,11 @@ CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
# CONFIG_CONSOLE_TRANSLATIONS is not set
# CONFIG_VT_CONSOLE is not set
-CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=5
CONFIG_SERIAL_8250_RUNTIME_UARTS=5
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm/configs/xcep_defconfig b/arch/arm/configs/xcep_defconfig
index 721832f..b67aeaf 100644
--- a/arch/arm/configs/xcep_defconfig
+++ b/arch/arm/configs/xcep_defconfig
@@ -60,8 +60,9 @@ CONFIG_NET_ETHERNET=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_PXA=y
-CONFIG_SERIAL_PXA_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=m
diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
new file mode 100644
index 0000000..0da0d40
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -0,0 +1,178 @@
+ return 0;
+}
+
+static int serial_pxa_resume(struct device *dev)
+{
+ struct pxa8250_data *data = dev_get_drvdata(dev);
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops serial_pxa_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(serial_pxa_suspend, serial_pxa_resume)
+};
+ return PTR_ERR(data->clk);
+
+ ret = clk_prepare(data->clk);
+ if (ret)
+ return ret;
+
+ uart.port.type = PORT_XSCALE;
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.mapbase = mmres->start;
+ uart.port.regshift = 2;
+ uart.port.irq = irqres->start;
+ uart.port.fifosize = 64;
+ uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST;
+ uart.port.dev = &pdev->dev;
+ uart.port.uartclk = clk_get_rate(data->clk);
+ uart.port.pm = serial_pxa_pm;
+ uart.port.private_data = data;
+ uart.dl_write = serial_pxa_dl_write;
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0)
+ goto err_clk;
+
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+ err_clk:
+ clk_unprepare(data->clk);
+ return ret;
+}
+
+static int serial_pxa_remove(struct platform_device *pdev)
+{
+ struct pxa8250_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+
+ clk_unprepare(data->clk);
+
+ return 0;
+}
+
+static struct platform_driver serial_pxa_driver = {
+ .probe = serial_pxa_probe,
+ .remove = serial_pxa_remove,
+
+ .driver = {
+ .name = "pxa2xx-uart",
+ .owner = THIS_MODULE,
+ .pm = &serial_pxa_pm_ops,
+ .of_match_table = serial_pxa_dt_ids,
+ },
+};
+
+module_platform_driver(serial_pxa_driver);
+
+MODULE_AUTHOR("Sergei Ianovich");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-uart");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 2332991..81bd7c9 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -302,3 +302,12 @@ config SERIAL_8250_RT288X
If you have a Ralink RT288x/RT305x SoC based board and want to use the
serial port, say Y to this option. The driver can handle up to 2 serial
ports. If unsure, say N.
+
+config SERIAL_PXA
+ tristate "PXA serial port support"
+ depends on SERIAL_8250 && (ARCH_PXA || ARCH_MMP)
+ help
+ If you have a machine based on an Intel XScale PXA2xx CPU you
+ can enable its onboard serial ports by enabling this option.
+
+ If you choose M here, the module name will be 8250_pxa.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 36d68d0..b7d1b61 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
+obj-$(CONFIG_SERIAL_PXA) += 8250_pxa.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index a3817ab..2ad7184b 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -396,29 +396,6 @@ config SERIAL_MPSC_CONSOLE
help
Say Y here if you want to support a serial console on a Marvell MPSC.

-config SERIAL_PXA
- bool "PXA serial port support"
- depends on ARCH_PXA || ARCH_MMP
- select SERIAL_CORE
- help
- If you have a machine based on an Intel XScale PXA2xx CPU you
- can enable its onboard serial ports by enabling this option.
-
-config SERIAL_PXA_CONSOLE
- bool "Console on PXA serial port"
- depends on SERIAL_PXA
- select SERIAL_CORE_CONSOLE
- help
- If you have enabled the serial port on the Intel XScale PXA
- CPU you can make it the console by answering Y to this option.
-
- Even if you say Y here, the currently visible virtual console
- (/dev/tty0) will still be used as the system console by default, but
- you can alter that using a kernel command line option such as
- "console=ttySA0". (Try "man bootparam" or see the documentation of
- your boot loader (lilo or loadlin) about how to pass options to the
- kernel at boot time.)
-
config SERIAL_SA1100
bool "SA1100 serial port support"
depends on ARCH_SA1100
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 3068c77..4ac337b 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_SERIAL_8250) += 8250/
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
-obj-$(CONFIG_SERIAL_PXA) += pxa.o
obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
deleted file mode 100644
index f9f20f3..0000000
--- a/drivers/tty/serial/pxa.c
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- * Based on drivers/serial/8250.c by Russell King.
- *
- * Author: Nicolas Pitre
- * Created: Feb 20, 2003
- * Copyright: (C) 2003 Monta Vista Software, Inc.
- *
- * 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.
- *
- * Note 1: This driver is made separate from the already too overloaded
- * 8250.c because it needs some kirks of its own and that'll make it
- * easier to add DMA support.
- *
- * Note 2: I'm too sick of device allocation policies for serial ports.
- * If someone else wants to request an "official" allocation of major/minor
- * for this driver please be my guest. And don't forget that new hardware
- * to come from Intel might have more than 3 or 4 of those UARTs. Let's
- * hope for a better port registration and dynamic device allocation scheme
- * with the serial core maintainer satisfaction to appear soon.
- */
-
-
-#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#define PXA_NAME_LEN 8
-
-struct uart_pxa_port {
- struct uart_port port;
- unsigned char ier;
- unsigned char lcr;
- unsigned char mcr;
- unsigned int lsr_break_flag;
- struct clk *clk;
- char name[PXA_NAME_LEN];
-};
-
-static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
-{
- offset <<= 2;
- return readl(up->port.membase + offset);
-}
-
-static inline void serial_out(struct uart_pxa_port *up, int offset, int value)
-{
- offset <<= 2;
- writel(value, up->port.membase + offset);
-}
-
-static void serial_pxa_enable_ms(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- up->ier |= UART_IER_MSI;
- serial_out(up, UART_IER, up->ier);
-}
-
-static void serial_pxa_stop_tx(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- if (up->ier & UART_IER_THRI) {
- up->ier &= ~UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
- }
-}
-
-static void serial_pxa_stop_rx(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- up->ier &= ~UART_IER_RLSI;
- up->port.read_status_mask &= ~UART_LSR_DR;
- serial_out(up, UART_IER, up->ier);
-}
-
-static inline void receive_chars(struct uart_pxa_port *up, int *status)
-{
- unsigned int ch, flag;
- int max_count = 256;
-
- do {
- /* work around Errata #20 according to
- * Intel(R) PXA27x Processor Family
- * Specification Update (May 2005)
- *
- * Step 2
- * Disable the Reciever Time Out Interrupt via IER[RTOEI]
- */
- up->ier &= ~UART_IER_RTOIE;
- serial_out(up, UART_IER, up->ier);
-
- ch = serial_in(up, UART_RX);
- flag = TTY_NORMAL;
- up->port.icount.rx++;
-
- if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE))) {
- /*
- * For statistics only
- */
- if (*status & UART_LSR_BI) {
- *status &= ~(UART_LSR_FE | UART_LSR_PE);
- up->port.icount.brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
- if (uart_handle_break(&up->port))
- goto ignore_char;
- } else if (*status & UART_LSR_PE)
- up->port.icount.parity++;
- else if (*status & UART_LSR_FE)
- up->port.icount.frame++;
- if (*status & UART_LSR_OE)
- up->port.icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- *status &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
- if (up->port.line == up->port.cons->index) {
- /* Recover the break flag from console xmit */
- *status |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
- }
-#endif
- if (*status & UART_LSR_BI) {
- flag = TTY_BREAK;
- } else if (*status & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (*status & UART_LSR_FE)
- flag = TTY_FRAME;
- }
-
- if (uart_handle_sysrq_char(&up->port, ch))
- goto ignore_char;
-
- uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
-
- ignore_char:
- *status = serial_in(up, UART_LSR);
- } while ((*status & UART_LSR_DR) && (max_count-- > 0));
- tty_flip_buffer_push(&up->port.state->port);
-
- /* work around Errata #20 according to
- * Intel(R) PXA27x Processor Family
- * Specification Update (May 2005)
- *
- * Step 6:
- * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
- */
- up->ier |= UART_IER_RTOIE;
- serial_out(up, UART_IER, up->ier);
-}
-
-static void transmit_chars(struct uart_pxa_port *up)
-{
- struct circ_buf *xmit = &up->port.state->xmit;
- int count;
-
- if (up->port.x_char) {
- serial_out(up, UART_TX, up->port.x_char);
- up->port.icount.tx++;
- up->port.x_char = 0;
- return;
- }
- if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- serial_pxa_stop_tx(&up->port);
- return;
- }
-
- count = up->port.fifosize / 2;
- do {
- serial_out(up, UART_TX, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- up->port.icount.tx++;
- if (uart_circ_empty(xmit))
- break;
- } while (--count > 0);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&up->port);
-
-
- if (uart_circ_empty(xmit))
- serial_pxa_stop_tx(&up->port);
-}
-
-static void serial_pxa_start_tx(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- if (!(up->ier & UART_IER_THRI)) {
- up->ier |= UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
- }
-}
-
-static inline void check_modem_status(struct uart_pxa_port *up)
-{
- int status;
-
- status = serial_in(up, UART_MSR);
-
- if ((status & UART_MSR_ANY_DELTA) == 0)
- return;
-
- if (status & UART_MSR_TERI)
- up->port.icount.rng++;
- if (status & UART_MSR_DDSR)
- up->port.icount.dsr++;
- if (status & UART_MSR_DDCD)
- uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
- if (status & UART_MSR_DCTS)
- uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
-
- wake_up_interruptible(&up->port.state->port.delta_msr_wait);
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
-{
- struct uart_pxa_port *up = dev_id;
- unsigned int iir, lsr;
-
- iir = serial_in(up, UART_IIR);
- if (iir & UART_IIR_NO_INT)
- return IRQ_NONE;
- lsr = serial_in(up, UART_LSR);
- if (lsr & UART_LSR_DR)
- receive_chars(up, &lsr);
- check_modem_status(up);
- if (lsr & UART_LSR_THRE)
- transmit_chars(up);
- return IRQ_HANDLED;
-}
-
-static unsigned int serial_pxa_tx_empty(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
- unsigned int ret;
-
- spin_lock_irqsave(&up->port.lock, flags);
- ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- return ret;
-}
-
-static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned char status;
- unsigned int ret;
-
- status = serial_in(up, UART_MSR);
-
- ret = 0;
- if (status & UART_MSR_DCD)
- ret |= TIOCM_CAR;
- if (status & UART_MSR_RI)
- ret |= TIOCM_RNG;
- if (status & UART_MSR_DSR)
- ret |= TIOCM_DSR;
- if (status & UART_MSR_CTS)
- ret |= TIOCM_CTS;
- return ret;
-}
-
-static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned char mcr = 0;
-
- if (mctrl & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (mctrl & TIOCM_DTR)
- mcr |= UART_MCR_DTR;
- if (mctrl & TIOCM_OUT1)
- mcr |= UART_MCR_OUT1;
- if (mctrl & TIOCM_OUT2)
- mcr |= UART_MCR_OUT2;
- if (mctrl & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
-
- mcr |= up->mcr;
-
- serial_out(up, UART_MCR, mcr);
-}
-
-static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
-
- spin_lock_irqsave(&up->port.lock, flags);
- if (break_state == -1)
- up->lcr |= UART_LCR_SBC;
- else
- up->lcr &= ~UART_LCR_SBC;
- serial_out(up, UART_LCR, up->lcr);
- spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static int serial_pxa_startup(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
- int retval;
-
- if (port->line == 3) /* HWUART */
- up->mcr |= UART_MCR_AFE;
- else
- up->mcr = 0;
-
- up->port.uartclk = clk_get_rate(up->clk);
-
- /*
- * Allocate the IRQ
- */
- retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
- if (retval)
- return retval;
-
- /*
- * Clear the FIFO buffers and disable them.
- * (they will be reenabled in set_termios())
- */
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_out(up, UART_FCR, 0);
-
- /*
- * Clear the interrupt registers.
- */
- (void) serial_in(up, UART_LSR);
- (void) serial_in(up, UART_RX);
- (void) serial_in(up, UART_IIR);
- (void) serial_in(up, UART_MSR);
-
- /*
- * Now, initialize the UART
- */
- serial_out(up, UART_LCR, UART_LCR_WLEN8);
-
- spin_lock_irqsave(&up->port.lock, flags);
- up->port.mctrl |= TIOCM_OUT2;
- serial_pxa_set_mctrl(&up->port, up->port.mctrl);
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- /*
- * Finally, enable interrupts. Note: Modem status interrupts
- * are set via set_termios(), which will be occurring imminently
- * anyway, so we don't enable them here.
- */
- up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
- serial_out(up, UART_IER, up->ier);
-
- /*
- * And clear the interrupt registers again for luck.
- */
- (void) serial_in(up, UART_LSR);
- (void) serial_in(up, UART_RX);
- (void) serial_in(up, UART_IIR);
- (void) serial_in(up, UART_MSR);
-
- return 0;
-}
-
-static void serial_pxa_shutdown(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
-
- free_irq(up->port.irq, up);
-
- /*
- * Disable interrupts from this port
- */
- up->ier = 0;
- serial_out(up, UART_IER, 0);
-
- spin_lock_irqsave(&up->port.lock, flags);
- up->port.mctrl &= ~TIOCM_OUT2;
- serial_pxa_set_mctrl(&up->port, up->port.mctrl);
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- /*
- * Disable break condition and FIFOs
- */
- serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT);
- serial_out(up, UART_FCR, 0);
-}
-
-static void
-serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned char cval, fcr = 0;
- unsigned long flags;
- unsigned int baud, quot;
- unsigned int dll;
-
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- cval = UART_LCR_WLEN5;
- break;
- case CS6:
- cval = UART_LCR_WLEN6;
- break;
- case CS7:
- cval = UART_LCR_WLEN7;
- break;
- default:
- case CS8:
- cval = UART_LCR_WLEN8;
- break;
- }
-
- if (termios->c_cflag & CSTOPB)
- cval |= UART_LCR_STOP;
- if (termios->c_cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(termios->c_cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
- /*
- * Ask the core to calculate the divisor for us.
- */
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- quot = uart_get_divisor(port, baud);
-
- if ((up->port.uartclk / quot) < (2400 * 16))
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
- else if ((up->port.uartclk / quot) < (230400 * 16))
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
- else
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
-
- /*
- * Ok, we're now changing the port state. Do it with
- * interrupts disabled.
- */
- spin_lock_irqsave(&up->port.lock, flags);
-
- /*
- * Ensure the port will be enabled.
- * This is required especially for serial console.
- */
- up->ier |= UART_IER_UUE;
-
- /*
- * Update the per-port timeout.
- */
- uart_update_timeout(port, termios->c_cflag, baud);
-
- up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (termios->c_iflag & INPCK)
- up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
- up->port.read_status_mask |= UART_LSR_BI;
-
- /*
- * Characters to ignore
- */
- up->port.ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
- if (termios->c_iflag & IGNBRK) {
- up->port.ignore_status_mask |= UART_LSR_BI;
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns too (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- up->port.ignore_status_mask |= UART_LSR_OE;
- }
-
- /*
- * ignore all characters if CREAD is not set
- */
- if ((termios->c_cflag & CREAD) == 0)
- up->port.ignore_status_mask |= UART_LSR_DR;
-
- /*
- * CTS flow control flag and modem status interrupts
- */
- up->ier &= ~UART_IER_MSI;
- if (UART_ENABLE_MS(&up->port, termios->c_cflag))
- up->ier |= UART_IER_MSI;
-
- serial_out(up, UART_IER, up->ier);
-
- if (termios->c_cflag & CRTSCTS)
- up->mcr |= UART_MCR_AFE;
- else
- up->mcr &= ~UART_MCR_AFE;
-
- serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
- serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
-
- /*
- * work around Errata #75 according to Intel(R) PXA27x Processor Family
- * Specification Update (Nov 2005)
- */
- dll = serial_in(up, UART_DLL);
- WARN_ON(dll != (quot & 0xff));
-
- serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
- serial_out(up, UART_LCR, cval); /* reset DLAB */
- up->lcr = cval; /* Save LCR */
- serial_pxa_set_mctrl(&up->port, up->port.mctrl);
- serial_out(up, UART_FCR, fcr);
- spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-static void
-serial_pxa_pm(struct uart_port *port, unsigned int state,
- unsigned int oldstate)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- if (!state)
- clk_prepare_enable(up->clk);
- else
- clk_disable_unprepare(up->clk);
-}
-
-static void serial_pxa_release_port(struct uart_port *port)
-{
-}
-
-static int serial_pxa_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-static void serial_pxa_config_port(struct uart_port *port, int flags)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- up->port.type = PORT_PXA;
-}
-
-static int
-serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
- /* we don't want the core code to modify any port params */
- return -EINVAL;
-}
-
-static const char *
-serial_pxa_type(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- return up->name;
-}
-
-static struct uart_pxa_port *serial_pxa_ports[4];
-static struct uart_driver serial_pxa_reg;
-
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- * Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_pxa_port *up)
-{
- unsigned int status, tmout = 10000;
-
- /* Wait up to 10ms for the character(s) to be sent. */
- do {
- status = serial_in(up, UART_LSR);
-
- if (status & UART_LSR_BI)
- up->lsr_break_flag = UART_LSR_BI;
-
- if (--tmout == 0)
- break;
- udelay(1);
- } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
-
- /* Wait up to 1s for flow control if necessary */
- if (up->port.flags & UPF_CONS_FLOW) {
- tmout = 1000000;
- while (--tmout &&
- ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
- udelay(1);
- }
-}
-
-static void serial_pxa_console_putchar(struct uart_port *port, int ch)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- wait_for_xmitr(up);
- serial_out(up, UART_TX, ch);
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- * The console_lock must be held when we get here.
- */
-static void
-serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct uart_pxa_port *up = serial_pxa_ports[co->index];
- unsigned int ier;
- unsigned long flags;
- int locked = 1;
-
- clk_enable(up->clk);
- local_irq_save(flags);
- if (up->port.sysrq)
- locked = 0;
- else if (oops_in_progress)
- locked = spin_trylock(&up->port.lock);
- else
- spin_lock(&up->port.lock);
-
- /*
- * First save the IER then disable the interrupts
- */
- ier = serial_in(up, UART_IER);
- serial_out(up, UART_IER, UART_IER_UUE);
-
- uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
-
- /*
- * Finally, wait for transmitter to become empty
- * and restore the IER
- */
- wait_for_xmitr(up);
- serial_out(up, UART_IER, ier);
-
- if (locked)
- spin_unlock(&up->port.lock);
- local_irq_restore(flags);
- clk_disable(up->clk);
-
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-/*
- * Console polling routines for writing and reading from the uart while
- * in an interrupt or debug context.
- */
-
-static int serial_pxa_get_poll_char(struct uart_port *port)
-{
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned char lsr = serial_in(up, UART_LSR);
-
- while (!(lsr & UART_LSR_DR))
- lsr = serial_in(up, UART_LSR);
-
- return serial_in(up, UART_RX);
-}
-
-
-static void serial_pxa_put_poll_char(struct uart_port *port,
- unsigned char c)
-{
- unsigned int ier;
- struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-
- /*
- * First save the IER then disable the interrupts
- */
- ier = serial_in(up, UART_IER);
- serial_out(up, UART_IER, UART_IER_UUE);
-
- wait_for_xmitr(up);
- /*
- * Send the character out.
- * If a LF, also do CR...
- */
- serial_out(up, UART_TX, c);
- if (c == 10) {
- wait_for_xmitr(up);
- serial_out(up, UART_TX, 13);
- }
-
- /*
- * Finally, wait for transmitter to become empty
- * and restore the IER
- */
- wait_for_xmitr(up);
- serial_out(up, UART_IER, ier);
-}
-
-#endif /* CONFIG_CONSOLE_POLL */
-
-static int __init
-serial_pxa_console_setup(struct console *co, char *options)
-{
- struct uart_pxa_port *up;
- int baud = 9600;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- if (co->index == -1 || co->index >= serial_pxa_reg.nr)
- co->index = 0;
- up = serial_pxa_ports[co->index];
- if (!up)
- return -ENODEV;
-
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
-
- return uart_set_options(&up->port, co, baud, parity, bits, flow);
-}
-
-static struct console serial_pxa_console = {
- .name = "ttyS",
- .write = serial_pxa_console_write,
- .device = uart_console_device,
- .setup = serial_pxa_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &serial_pxa_reg,
-};
-
-#define PXA_CONSOLE &serial_pxa_console
-#else
-#define PXA_CONSOLE NULL
-#endif
-
-static struct uart_ops serial_pxa_pops = {
- .tx_empty = serial_pxa_tx_empty,
- .set_mctrl = serial_pxa_set_mctrl,
- .get_mctrl = serial_pxa_get_mctrl,
- .stop_tx = serial_pxa_stop_tx,
- .start_tx = serial_pxa_start_tx,
- .stop_rx = serial_pxa_stop_rx,
- .enable_ms = serial_pxa_enable_ms,
- .break_ctl = serial_pxa_break_ctl,
- .startup = serial_pxa_startup,
- .shutdown = serial_pxa_shutdown,
- .set_termios = serial_pxa_set_termios,
- .pm = serial_pxa_pm,
- .type = serial_pxa_type,
- .release_port = serial_pxa_release_port,
- .request_port = serial_pxa_request_port,
- .config_port = serial_pxa_config_port,
- .verify_port = serial_pxa_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
- .poll_get_char = serial_pxa_get_poll_char,
- .poll_put_char = serial_pxa_put_poll_char,
-#endif
-};
-
-static struct uart_driver serial_pxa_reg = {
- .owner = THIS_MODULE,
- .driver_name = "PXA serial",
- .dev_name = "ttyS",
- .major = TTY_MAJOR,
- .minor = 64,
- .nr = 4,
- .cons = PXA_CONSOLE,
-};
-
-#ifdef CONFIG_PM
-static int serial_pxa_suspend(struct device *dev)
-{
- struct uart_pxa_port *sport = dev_get_drvdata(dev);
-
- if (sport)
- uart_suspend_port(&serial_pxa_reg, &sport->port);
-
- return 0;
-}
-
-static int serial_pxa_resume(struct device *dev)
-{
- struct uart_pxa_port *sport = dev_get_drvdata(dev);
-
- if (sport)
- uart_resume_port(&serial_pxa_reg, &sport->port);
-
- return 0;
-}
-
-static const struct dev_pm_ops serial_pxa_pm_ops = {
- .suspend = serial_pxa_suspend,
- .resume = serial_pxa_resume,
-};
-#endif
-
-static struct of_device_id serial_pxa_dt_ids[] = {
- { .compatible = "mrvl,pxa-uart", },
- { .compatible = "mrvl,mmp-uart", },
- {}
-};
-MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
-
-static int serial_pxa_probe_dt(struct platform_device *pdev,
- struct uart_pxa_port *sport)
-{
- struct device_node *np = pdev->dev.of_node;
- int ret;
-
- if (!np)
- return 1;
-
- ret = of_alias_get_id(np, "serial");
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
- return ret;
- }
- sport->port.line = ret;
- return 0;
-}
-
-static int serial_pxa_probe(struct platform_device *dev)
-{
- struct uart_pxa_port *sport;
- struct resource *mmres, *irqres;
- int ret;
-
- mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
- irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
- if (!mmres || !irqres)
- return -ENODEV;
-
- sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
- if (!sport)
- return -ENOMEM;
-
- sport->clk = clk_get(&dev->dev, NULL);
- if (IS_ERR(sport->clk)) {
- ret = PTR_ERR(sport->clk);
- goto err_free;
- }
-
- ret = clk_prepare(sport->clk);
- if (ret) {
- clk_put(sport->clk);
- goto err_free;
- }
-
- sport->port.type = PORT_PXA;
- sport->port.iotype = UPIO_MEM;
- sport->port.mapbase = mmres->start;
- sport->port.irq = irqres->start;
- sport->port.fifosize = 64;
- sport->port.ops = &serial_pxa_pops;
- sport->port.dev = &dev->dev;
- sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
- sport->port.uartclk = clk_get_rate(sport->clk);
-
- ret = serial_pxa_probe_dt(dev, sport);
- if (ret > 0)
- sport->port.line = dev->id;
- else if (ret < 0)
- goto err_clk;
- snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
-
- sport->port.membase = ioremap(mmres->start, resource_size(mmres));
- if (!sport->port.membase) {
- ret = -ENOMEM;
- goto err_clk;
- }
-
- serial_pxa_ports[sport->port.line] = sport;
-
- uart_add_one_port(&serial_pxa_reg, &sport->port);
- platform_set_drvdata(dev, sport);
-
- return 0;
-
- err_clk:
- clk_unprepare(sport->clk);
- clk_put(sport->clk);
- err_free:
- kfree(sport);
- return ret;
-}
-
-static int serial_pxa_remove(struct platform_device *dev)
-{
- struct uart_pxa_port *sport = platform_get_drvdata(dev);
-
- uart_remove_one_port(&serial_pxa_reg, &sport->port);
-
- clk_unprepare(sport->clk);
- clk_put(sport->clk);
- kfree(sport);
-
- return 0;
-}
-
-static struct platform_driver serial_pxa_driver = {
- .probe = serial_pxa_probe,
- .remove = serial_pxa_remove,
-
- .driver = {
- .name = "pxa2xx-uart",
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &serial_pxa_pm_ops,
-#endif
- .of_match_table = serial_pxa_dt_ids,
- },
-};
-
-static int __init serial_pxa_init(void)
-{
- int ret;
-
- ret = uart_register_driver(&serial_pxa_reg);
- if (ret != 0)
- return ret;
-
- ret = platform_driver_register(&serial_pxa_driver);
- if (ret != 0)
- uart_unregister_driver(&serial_pxa_reg);
-
- return ret;
-}
-
-static void __exit serial_pxa_exit(void)
-{
- platform_driver_unregister(&serial_pxa_driver);
- uart_unregister_driver(&serial_pxa_reg);
-}
-
-module_init(serial_pxa_init);
-module_exit(serial_pxa_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pxa2xx-uart");
--
1.8.4.2

Sergei Ianovich

unread,
Dec 9, 2013, 7:10:02 AM12/9/13
to
On Mon, 2013-12-09 at 11:21 +0100, Daniel Mack wrote:
> On 12/09/2013 10:34 AM, Sergei Ianovich wrote:
> > Nice to have Daniel in this conversation. Your patch series is a big and
> > important work. However, I am not sure I will ever land as is exactly
> > for this reason.
>
> Well, I wouldn't be so certain about that statement. As I wrote in the
> cover letter, most of the work is actually done, and I successfully
> tested the new DMA support with a some of the drivers I ported. Others
> were ported blindly, and in case of no reaction, I'd dare to merge them
> and wait for people to report back in case of trouble.

If breaking things is an option, I am definitely wrong. I assumed the
opposite.

> > My proposal in to actually add new drivers for each platform device with
> > DMA and mark new ones EXPERIMENTAL.
>
> That would cause tree-wide cross-dependencies between drivers, because
> the two DMA controllers can't be used at the same time, and the PXA
> specific API will be unavailable when the mmp-dma driver is selected. My
> patch series (and the DMA controller framework for that matter) aims for
> the opposite - the unification of APIs and drivers.

Not sure I got this point. My proposal is to keep the existing DMA
intact until we are ready to remove it. I understand this approach
requires considerably more work inside DMA to allow both driver to
coexist than wholesale replacement. I still think big change is risky.

Sergei Ianovich

unread,
Dec 9, 2013, 8:20:03 AM12/9/13
to
On Mon, 2013-12-09 at 11:21 +0100, Daniel Mack wrote:
> On 12/09/2013 10:34 AM, Sergei Ianovich wrote:
> > On Mon, 2013-12-09 at 10:04 +0100, Daniel Mack wrote:
> >> On 12/09/2013 02:33 AM, Arnd Bergmann wrote:
> >>> It hasn't made it upstream yet, but see http://list-archives.org/2013/08/07/linux-mtd-lists-infradead-org/patch-00-20-arm-pxa-move-core-and-drivers-to-dmaengine/f/3444199144
> >>> for how it's done. Maybe Daniel can comment on the status of his
> >>> patches.
> >>
...
> The only real problem is the PXA camera driver, which does tricky things
> like hot re-queuing of DMA descriptors. That one needs fixing before the
> series can land.

My impression is that his series is hard to land. I've expressed my
concerns about big changes in a separate mail.

PXA device tree support issue is practically orthogonal. As of August
2013, Daniel's dma series doesn't add any dt support. After new DMA is
working, we will need to add dt support in the same drivers.

Basically we have three options:
A. Wait for Daniel DMA, than for PXA clock, than do dt support
pros:
* correct order
cons:
* need to wait, possibly a long time
* dt boot not possible, while we wait

B. Provide 'hackish' support to dt, than correct hacks when DMA is
merged.
pros:
* parallel development
* healthier kernel code (current PXA usb driver won't compile with dt
enabled)
cons:
* wrong concept (like my patch 5/9) until DMA is working
* need to recompile dtb files when kernel changes

C. Use 'fake' DMA provider dt binding to emulate existing DMA until new
DMA is merged, than
pros:
* parallel development
* healthier kernel code
* correct device trees from the beginning
cons:
* more work
* still need to recompile dtbs when clock support is merged

Any ideas?

Sergei Ianovich

unread,
Dec 9, 2013, 9:50:02 AM12/9/13
to
On Mon, 2013-12-09 at 14:26 +0000, Steve Cotton wrote:
> There's already a different patch for this
> in the linux-next/master and gregkh/usb/usb-linus trees, but
> not in the linux-next/stable or gregkh/usb/usb-next trees.
>
> It adds that include 3 lines higher up, to keep the includes in
> alphabetical order.

Thanks.

Steve Cotton

unread,
Dec 9, 2013, 10:00:02 AM12/9/13
to
Hi Sergei,

There's already a different patch for this
in the linux-next/master and gregkh/usb/usb-linus trees, but
not in the linux-next/stable or gregkh/usb/usb-next trees.

It adds that include 3 lines higher up, to keep the includes in
alphabetical order.

commit 9876388edfa553960815110acae4544359b385b5
Author: Daniel Mack <zon...@gmail.com>
AuthorDate: Fri Nov 15 14:19:02 2013 +0100
Commit: Greg Kroah-Hartman <gre...@linuxfoundation.org>
CommitDate: Wed Dec 4 16:57:46 2013 -0800

Cheers,
Steve

Sergei Ianovich

unread,
Dec 9, 2013, 10:20:02 AM12/9/13
to
On Mon, 2013-12-09 at 02:47 +0100, Arnd Bergmann wrote:
> On Sunday 08 December 2013, Sergei Ianovich wrote:
> > +
> > +#ifdef CONFIG_PXA27x
> > +extern void __init pxa27x_dt_init_irq(void);

> This is not the right place to put an 'extern' declaration, it should go into
> a header file if it's really needed. Ideally you would not need it at all
> and just add an IRQCHIP_DECLARE() line into the driver to automatically
> probe it.

I thought I moved it to the header in patch 6/9. I'll just drop the
line.

IRQCHIP_DECLARE isn't used on pxa_internal_irq_chip in
arch/arm/mach-pxa/irq.c, probably for a reason.

> > +static const struct of_dev_auxdata pxa27x_auxdata_lookup[] __initconst = {
> > + OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL),
> > + OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL),
> > + OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40700000, "pxa2xx-uart.2", NULL),
> > + OF_DEV_AUXDATA("mrvl,pxa-uart", 0x41600000, "pxa2xx-uart.3", NULL),
> > + OF_DEV_AUXDATA("marvell,pxa-mmc", 0x41100000, "pxa2xx-mci.0", NULL),
> > + OF_DEV_AUXDATA("intel,pxa27x-gpio", 0x40e00000, "pxa27x-gpio", NULL),
> > + OF_DEV_AUXDATA("marvell,pxa-ohci", 0x4c000000, "pxa27x-ohci", NULL),
> > + OF_DEV_AUXDATA("mrvl,pxa-i2c", 0x40301680, "pxa2xx-i2c.0", NULL),
> > + {}
> > +};
>
> I guess these are needed only for clock management purposes at the moment?

Absolutely.

> > +static void __init pxa27x_init_early(void)
> > +{
> > + pxa27x_skip_init();
> > +}
>
> I would prefer not to have an init_early function at all, and instead
> check "if (of_have_populated_dt())" in pxa27x_init, or to split
> that function into two.

Device tree is populated in init_machine. However, pxa27x_init is
executed before via postcore_initcall. The only chance to run before is
to use init_early. What's wrong with this function?

> > +static const char *pxa27x_dt_board_compat[] __initdata = {
> > + "marvell,pxa27x",
> > + NULL,
> > +};
> > +
> > +#ifdef CONFIG_MACH_LP8X4X
> > +static const char *lp8x4x_dt_board_compat[] __initdata = {
> > + "marvell,lp8x4x",
> > + NULL,
> > +};
>
> Note that you should not have wildcards in any "compatible" strings.
> Just list all the combinations here (pxa270, pxa271, pxa272, and whatever
> you need for lp8x4x).

Will do.

> > +static void lp8x4x_restart(enum reboot_mode mode, const char *cmd)
> > +{
> > + /* Switch off fast-bus and turbo mode */
> > + asm volatile("mcr p14, 0, %0, c6, c0, 0" : :
> > + "r"(2));
> > + /* SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) */
> > + pxa_restart(REBOOT_SOFT, cmd);
> > +}
> > +#endif
> > +#endif
>
> Since the only difference here is the restart logic, I would prefer here to
> have only a single DT_MACHINE_START() and do
>
> static void pxa27x_restart(enum reboot_mode mode, const char *cmd)
> {
> /* Switch off fast-bus and turbo mode */
> if (of_machine_is_compatible("marvell,lp8x4x"))
> asm volatile("mcr p14, 0, %0, c6, c0, 0" : : "r"(2));
>
> /* SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) */
> if (of_machine_is_compatible("marvell,pxa270"))
> pxa_restart(REBOOT_SOFT, cmd);
> }

Nice tip, thanks. I've spent 30 minutes to find something like that.

If the device has fast SDRAM, which can reset itself in up to 8ms, the
device is not affected by E71. So both checks are per-device.

Dmitry Eremin-Solenikov

unread,
Dec 9, 2013, 10:30:02 AM12/9/13
to
Hello,

On Mon, 09 Dec 2013 02:53:47 +0400, Sergei Ianovich wrote:

> Static plaform devices are created from postcore_initcall(). The status
> quo remains for non-device tree machines.
>
> Device tree machine now have a chance to prevent spawning of static
> devices by calling pxa27x_skip_init().
>
> Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
> CC: Russell King - ARM Linux <li...@arm.linux.org.uk>
> CC: Daniel Mack <zon...@gmail.com>
> CC: Arnd Bergmann <ar...@arndb.de>
> ---
> arch/arm/mach-pxa/include/mach/pxa27x.h | 1 +
> arch/arm/mach-pxa/pxa27x.c | 10 ++++++++++ 2 files
> changed, 11 insertions(+)

I would suggest to copy the corresponding code from pxa3xx.c - use
of_have_populated_dt() instead of adding extra static variable.

--
With best wishes
Dmitry

Sergei Ianovich

unread,
Dec 9, 2013, 11:00:02 AM12/9/13
to
On Mon, 2013-12-09 at 19:16 +0400, Sergei Ianovich wrote:
> On Mon, 2013-12-09 at 02:47 +0100, Arnd Bergmann wrote:
> > On Sunday 08 December 2013, Sergei Ianovich wrote:
> > > +
> > > +#ifdef CONFIG_PXA27x
> > > +extern void __init pxa27x_dt_init_irq(void);
>
> > > +static void __init pxa27x_init_early(void)
> > > +{
> > > + pxa27x_skip_init();
> > > +}
> >
> > I would prefer not to have an init_early function at all, and instead
> > check "if (of_have_populated_dt())" in pxa27x_init, or to split
> > that function into two.

Although this is counterintuitive, it works. Since of_populate_dt() is
not required for of_have_populated_dt() to return true, should we rename
of_have_populated_dt() to of_have_dt()?

> Device tree is populated in init_machine. However, pxa27x_init is
> executed before via postcore_initcall. The only chance to run before is
> to use init_early. What's wrong with this function?

I was wrong.

Arnd Bergmann

unread,
Dec 9, 2013, 11:30:02 AM12/9/13
to
On Monday 09 December 2013, Sergei Ianovich wrote:
> On Mon, 2013-12-09 at 02:47 +0100, Arnd Bergmann wrote:
> > On Sunday 08 December 2013, Sergei Ianovich wrote:
> > > +
> > > +#ifdef CONFIG_PXA27x
> > > +extern void __init pxa27x_dt_init_irq(void);
>
> > This is not the right place to put an 'extern' declaration, it should go into
> > a header file if it's really needed. Ideally you would not need it at all
> > and just add an IRQCHIP_DECLARE() line into the driver to automatically
> > probe it.
>
> I thought I moved it to the header in patch 6/9. I'll just drop the
> line.

Ok.

> IRQCHIP_DECLARE isn't used on pxa_internal_irq_chip in
> arch/arm/mach-pxa/irq.c, probably for a reason.

Yes, you can only use it from drivers in drivers/irqchip/.

> > > +static void __init pxa27x_init_early(void)
> > > +{
> > > + pxa27x_skip_init();
> > > +}
> >
> > I would prefer not to have an init_early function at all, and instead
> > check "if (of_have_populated_dt())" in pxa27x_init, or to split
> > that function into two.
>
> Device tree is populated in init_machine. However, pxa27x_init is
> executed before via postcore_initcall.

The device tree is populated in unflatten_device_tree(), which gets
called before init_early.

> The only chance to run before is
> to use init_early. What's wrong with this function?

I generally dislike adding any platform specific hooks to "early"
functions, i.e. stuff that runs before init_machine, and I'm pretty
sure it's not necessary here.

> > static void pxa27x_restart(enum reboot_mode mode, const char *cmd)
> > {
> > /* Switch off fast-bus and turbo mode */
> > if (of_machine_is_compatible("marvell,lp8x4x"))
> > asm volatile("mcr p14, 0, %0, c6, c0, 0" : : "r"(2));
> >
> > /* SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) */
> > if (of_machine_is_compatible("marvell,pxa270"))
> > pxa_restart(REBOOT_SOFT, cmd);
> > }
>
> Nice tip, thanks. I've spent 30 minutes to find something like that.
>
> If the device has fast SDRAM, which can reset itself in up to 8ms, the
> device is not affected by E71. So both checks are per-device.

Ok.

Arnd

Arnd Bergmann

unread,
Dec 9, 2013, 11:40:03 AM12/9/13
to
On Monday 09 December 2013, Sergei Ianovich wrote:
> anovich wrote:
> > On Mon, 2013-12-09 at 02:47 +0100, Arnd Bergmann wrote:
> > > On Sunday 08 December 2013, Sergei Ianovich wrote:
> > > > +
> > > > +#ifdef CONFIG_PXA27x
> > > > +extern void __init pxa27x_dt_init_irq(void);
> >
> > > > +static void __init pxa27x_init_early(void)
> > > > +{
> > > > + pxa27x_skip_init();
> > > > +}
> > >
> > > I would prefer not to have an init_early function at all, and instead
> > > check "if (of_have_populated_dt())" in pxa27x_init, or to split
> > > that function into two.
>
> Although this is counterintuitive, it works. Since of_populate_dt() is
> not required for of_have_populated_dt() to return true, should we rename
> of_have_populated_dt() to of_have_dt()?

I don't think it's worth the change. The explanation for the current
terminoligy is that of_unflatten() populates the DT device_node structures
in the kernel from the FTD blob, while of_platform_populate populates the
platform_device infrastructure from the device nodes.

Arnd

Sergei Ianovich

unread,
Dec 9, 2013, 1:50:02 PM12/9/13
to
On Mon, 2013-12-09 at 02:51 +0100, Arnd Bergmann wrote:
> On Sunday 08 December 2013, Sergei Ianovich wrote:
> >
> > Except for defconfig, this is a completely new series. The first
> > eight patches fix outstanding issues with device tree support
> > in PXA. The 9th boots ICP DAS LP-8x4x.
>
> Awesome! That was very quick. The main comment I have is for the
> dmaengine support, you will need to rebase on Daniel's patches for
> that. I also found few minor details.

Thanks for review.

I've applied and tested changes to meet review remarks for all patches,
except 5/9. However, there is no point to respin the series until the
decision about DMA is made.

Daniel, could please CC me when you post update pxa-dma series?

Arnd Bergmann

unread,
Dec 9, 2013, 7:30:01 PM12/9/13
to
On Monday 09 December 2013, Sergei Ianovich wrote:
> On Mon, 2013-12-09 at 11:21 +0100, Daniel Mack wrote:
> > On 12/09/2013 10:34 AM, Sergei Ianovich wrote:
> > > Nice to have Daniel in this conversation. Your patch series is a big and
> > > important work. However, I am not sure I will ever land as is exactly
> > > for this reason.
> >
> > Well, I wouldn't be so certain about that statement. As I wrote in the
> > cover letter, most of the work is actually done, and I successfully
> > tested the new DMA support with a some of the drivers I ported. Others
> > were ported blindly, and in case of no reaction, I'd dare to merge them
> > and wait for people to report back in case of trouble.
>
> If breaking things is an option, I am definitely wrong. I assumed the
> opposite.

We never intentionally break things that people are using, but there are
cases where doing blind changes is the best way forward. We should
always try to find people to test patches on real hardware if possible,
which is only possible if there are people around that have the hardware
and that are going to run new kernels on them.

In case of PXA dmaengine support, I think the benefits of applying the
series far outweigh the breakage potential. A lot of the drivers are
shared with MMP, which is going to be DT-only eventually and will require
the new dmaengine code. Some PXA drivers may be shared with SA1100,
which has also converted to dmaengine although there are no plans to
ever support DT on sa1100.

> > > My proposal in to actually add new drivers for each platform device with
> > > DMA and mark new ones EXPERIMENTAL.
> >
> > That would cause tree-wide cross-dependencies between drivers, because
> > the two DMA controllers can't be used at the same time, and the PXA
> > specific API will be unavailable when the mmp-dma driver is selected. My
> > patch series (and the DMA controller framework for that matter) aims for
> > the opposite - the unification of APIs and drivers.
>
> Not sure I got this point. My proposal is to keep the existing DMA
> intact until we are ready to remove it. I understand this approach
> requires considerably more work inside DMA to allow both driver to
> coexist than wholesale replacement. I still think big change is risky.

We certainly need to be extra careful if we want to move things over
at once and cannot test all the drivers. I'd be happier if it could
be done gradually by having some drivers use the new interface and
other drivers use the old one, but I don't see how that can be done
here.

Arnd

Sergei Ianovich

unread,
Dec 9, 2013, 11:30:02 PM12/9/13
to
On Tue, 2013-12-10 at 01:25 +0100, Arnd Bergmann wrote:
> We never intentionally break things that people are using, but there are
> cases where doing blind changes is the best way forward. We should
> always try to find people to test patches on real hardware if possible,
> which is only possible if there are people around that have the hardware
> and that are going to run new kernels on them.
>
> In case of PXA dmaengine support, I think the benefits of applying the
> series far outweigh the breakage potential. A lot of the drivers are
> shared with MMP, which is going to be DT-only eventually and will require
> the new dmaengine code. Some PXA drivers may be shared with SA1100,
> which has also converted to dmaengine although there are no plans to
> ever support DT on sa1100.
>
> We certainly need to be extra careful if we want to move things over
> at once and cannot test all the drivers. I'd be happier if it could
> be done gradually by having some drivers use the new interface and
> other drivers use the old one, but I don't see how that can be done
> here.

Thanks for detailed explanation. I see there is strong support for the
big change. Lets hope it'll be smooth. I'll strest test Daniel's changes
and report the results.

Linus Walleij

unread,
Dec 10, 2013, 7:40:02 AM12/10/13
to
On Fri, Dec 6, 2013 at 6:14 PM, Arnd Bergmann <ar...@arndb.de> wrote:
> On Friday 06 December 2013, Sergei Ianovich wrote:
>> On Fri, 2013-12-06 at 01:40 +0100, Arnd Bergmann wrote:
>>
>> > > +
>> > > +static struct irq_chip lp8x4x_irq_chip = {
>> > > + .name = "FPGA",
>> > > + .irq_ack = lp8x4x_ack_irq,
>> > > + .irq_mask = lp8x4x_mask_irq,
>> > > + .irq_unmask = lp8x4x_unmask_irq,
>> > > +};
>> >
>> > Please try to move the irqchip code to drivers/irqchip/.
>>
>> CONFIG_IRQCHIP depends on CONFIG_OF_IRQ which in turn depends on Open
>> Firmware.
>
> Hmm, I wonder if we should try to change Kconfig then. Let's leave it
> alone for now, maybe Linus Walleij has some comments since he has
> been looking into moving drivers out in the past.

I don't get this, if the subarch has deps in place for IRQCHIP and
OF_IRQ just move the implementation to drivers/irqchip/foo.c
edit drivers/irqchip/Makefile to compile the file for ARCH_FOO.
What would the problem be? It's not like having the irqchip in the
object is optional...

I would prefer if you augment the code to use
IRQCHIP_DECLARE() so you can get rid of all the criss-cross
calls, but this init contains a comment saying that GPIO
has to be up before you initialize the irq_chip, can you please
explain why it's like that?

Another way is to create a separate Kconfig entry for it in
drivers/irqchip/Kconfig if you want the set-up to be more
distributed, but that is usually just done when the irqchip is
used on more than one platform.

Yours,
Linus Walleij

Sergei Ianovich

unread,
Dec 10, 2013, 7:50:02 AM12/10/13
to
On Tue, 2013-12-10 at 13:43 +0100, Linus Walleij wrote:
> Argh! Now you're adding another user for a legacy custom pin control
> implementation. But if noone is going to modernize PXA2xx what
> can we do :-/

I've rewritten the device to use device tree and posted patch series for
that.

I will also implement LP-8x4x custom irq controller in drivers/irqchip/

Linus Walleij

unread,
Dec 10, 2013, 7:50:02 AM12/10/13
to
On Fri, Dec 6, 2013 at 5:48 PM, Sergei Ianovich <ynv...@gmail.com> wrote:

> ICP DAS calls LP-8x4x 'programmable automation controller'. It is
> an industrial computer based on PXA270 SoC. They ship it with a 2.6.19
> kernel and proprietary kernel module and userspace library to access
> its industrial IO.

OK... so we only have device tree support for PXA3xx and noone is
working on PXA2xx. And now we pile up some more legacy code.
Such is life. But this:

> +static unsigned long lp8x4x_pin_config[] = {
> + /* MMC */
> + GPIO32_MMC_CLK,
> + GPIO112_MMC_CMD,
> + GPIO92_MMC_DAT_0,
> + GPIO109_MMC_DAT_1,
> + GPIO110_MMC_DAT_2,
> + GPIO111_MMC_DAT_3,
> +
> + /* USB Host Port 1 */
> + GPIO88_USBH1_PWR,
> + GPIO89_USBH1_PEN,
> +};

(...)
> +static void __init lp8x4x_init(void)
> +{
> + pxa2xx_mfp_config(ARRAY_AND_SIZE(lp8x4x_pin_config));
(...)

Argh! Now you're adding another user for a legacy custom pin control
implementation. But if noone is going to modernize PXA2xx what
can we do :-/

Yours,
Linus Walleij

Vasily Khoruzhick

unread,
Dec 10, 2013, 8:00:03 AM12/10/13
to
I tried a ~year ago, but it's not so trivial. PXA2xx has no separate
pin control module, it's
highly integrated into GPIO controller. I've asked the maillist what
should I do for that case, but AFAIR no one answered.

Regards
Vasily

> Yours,
> Linus Walleij
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-ar...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Sergei Ianovich

unread,
Dec 10, 2013, 3:30:02 PM12/10/13
to
On Tue, 2013-12-10 at 13:33 +0100, Linus Walleij wrote:
> On Fri, Dec 6, 2013 at 6:14 PM, Arnd Bergmann <ar...@arndb.de> wrote:
> > On Friday 06 December 2013, Sergei Ianovich wrote:
> >> On Fri, 2013-12-06 at 01:40 +0100, Arnd Bergmann wrote:
> >>
> >> > > +
> >> > > +static struct irq_chip lp8x4x_irq_chip = {
> >> > > + .name = "FPGA",
> >> > > + .irq_ack = lp8x4x_ack_irq,
> >> > > + .irq_mask = lp8x4x_mask_irq,
> >> > > + .irq_unmask = lp8x4x_unmask_irq,
> >> > > +};
> >> >
> >> > Please try to move the irqchip code to drivers/irqchip/.
> >>
> >> CONFIG_IRQCHIP depends on CONFIG_OF_IRQ which in turn depends on Open
> >> Firmware.
> >
> > Hmm, I wonder if we should try to change Kconfig then. Let's leave it
> > alone for now, maybe Linus Walleij has some comments since he has
> > been looking into moving drivers out in the past.
>
> I don't get this, if the subarch has deps in place for IRQCHIP and
> OF_IRQ just move the implementation to drivers/irqchip/foo.c
> edit drivers/irqchip/Makefile to compile the file for ARCH_FOO.
> What would the problem be? It's not like having the irqchip in the
> object is optional...

This chip is used only of one machine and only required for
machine-special devices. If those devices are not selected, the chip
will just waist memory.

> I would prefer if you augment the code to use
> IRQCHIP_DECLARE() so you can get rid of all the criss-cross
> calls, but this init contains a comment saying that GPIO
> has to be up before you initialize the irq_chip, can you please
> explain why it's like that?

This is a tertiary irq chip (primary is on CPU, secondary is GPIO). It
triggers a GPIO interrupt if it detects one of its own.

> Another way is to create a separate Kconfig entry for it in
> drivers/irqchip/Kconfig if you want the set-up to be more
> distributed, but that is usually just done when the irqchip is
> used on more than one platform.

Please consult, how to approach this driver using device tree. If I
assign an "interrupts" property in the node, and the property will point
to pxa-gpio interrupt controller using a phandle, is there a guaranty
that my device will be probed later than pxa-gpio interrupt controller?

Or how could that be achieved?

Arnd Bergmann

unread,
Dec 10, 2013, 5:00:02 PM12/10/13
to
It should be possible to make it a loadable module, with deferred
probing etc. You wouldn't use IRQCHIP_DECLARE() for this though,
but instead have a platform driver that sets up the irq domain.

It probably makes sense to have a single driver file for the
FPGA device that does this, and only split out the other devices
from it that consume the irqs.

> > Another way is to create a separate Kconfig entry for it in
> > drivers/irqchip/Kconfig if you want the set-up to be more
> > distributed, but that is usually just done when the irqchip is
> > used on more than one platform.
>
> Please consult, how to approach this driver using device tree. If I
> assign an "interrupts" property in the node, and the property will point
> to pxa-gpio interrupt controller using a phandle, is there a guaranty
> that my device will be probed later than pxa-gpio interrupt controller?

Yes, the interrupt controllers get probed in the right order based
on their "interrupt-parent" properties, starting with the root
controller.

If you have a platform driver rather than IRQCHIP_DECLARE(), that gets
initialized after all IRQCHIP_DECLARE() calls, so it's not a problem.

If both the gpio chip and the fpga are loadable modules, it's still
fine, but the probe() function for the fpga needs to call
irq_of_parse_and_map() to get the parent IRQ and bail out of
-EPROBE_DEFER if it gets this error while trying to map the
gpio IRQ.

Arnd

Dmitry Eremin-Solenikov

unread,
Dec 10, 2013, 5:30:02 PM12/10/13
to
On Tue, 10 Dec 2013 13:43:27 +0100, Linus Walleij wrote:

> Argh! Now you're adding another user for a legacy custom pin control
> implementation. But if noone is going to modernize PXA2xx what can we do
> :-/

I plan to work on pxa2xx (pxa25x to be precise) after finishing with
sa1100 - my second (well, first) PDA is Sharp SL-6000 (pxa255).

StrongARM somewhat resembles pxa2xx, so some of the drivers will be
shared, some expertise will be shared, etc. I tried doing pxa first, but
later found that it might be easier to update sa1100.

--
With best wishes
Dmitry

Sergei Ianovich

unread,
Dec 10, 2013, 11:40:02 PM12/10/13
to
On Tue, 2013-12-10 at 22:57 +0100, Arnd Bergmann wrote:
> It should be possible to make it a loadable module, with deferred
> probing etc. You wouldn't use IRQCHIP_DECLARE() for this though,
> but instead have a platform driver that sets up the irq domain.

Thanks for explaning.

> It probably makes sense to have a single driver file for the
> FPGA device that does this, and only split out the other devices
> from it that consume the irqs.

Is drivers/irqchip/ the right place this driver?

I am asking because there is no tristate config options in
drivers/irqchip/Kconfig at the moment.

Arnd Bergmann

unread,
Dec 11, 2013, 12:20:01 AM12/11/13
to
On Wednesday 11 December 2013, Sergei Ianovich wrote:
> > It probably makes sense to have a single driver file for the
> > FPGA device that does this, and only split out the other devices
> > from it that consume the irqs.
>
> Is drivers/irqchip/ the right place this driver?
>
> I am asking because there is no tristate config options in
> drivers/irqchip/Kconfig at the moment.
>

It depends: if the driver is for the entire FPGA and does
the irqchip stuff in addition, it should probably live
in drivers/mfd. If it's a pure irqchip driver, drivers/irqchip
is better. You have to be careful in the second case though
because devices pointing to this irqchip in DT won't get
an IRQ resource assigned automatically but have to use
irq_of_parse_and_map instead. This may have been fixed since
I last looked though, I would consider that behavior a
bug in the of_platform handling.

Arnd

Sergei Ianovich

unread,
Dec 11, 2013, 12:50:01 AM12/11/13
to
On Wed, 2013-12-11 at 06:11 +0100, Arnd Bergmann wrote:
> It depends: if the driver is for the entire FPGA and does
> the irqchip stuff in addition, it should probably live
> in drivers/mfd. If it's a pure irqchip driver, drivers/irqchip
> is better. You have to be careful in the second case though
> because devices pointing to this irqchip in DT won't get
> an IRQ resource assigned automatically but have to use
> irq_of_parse_and_map instead. This may have been fixed since
> I last looked though, I would consider that behavior a
> bug in the of_platform handling.

Thanks again for explaining.

Although FPGA is a MFD, its irq are used mostly by 8250 serial ports. It
will be enough to embed irqchip into serial driver for now.

If there is a need to use the chip in another driver, it will be
possible to introduce an artificial dependency there for the serial
driver to ensure the serial driver is loaded before the other one.

Is this plan acceptable?

Robert Jarzmik

unread,
Dec 11, 2013, 3:30:01 AM12/11/13
to
Daniel Mack <zon...@gmail.com> writes:

> In particular, the pxa camera driver is something Robert (cc) wanted to
> have a look at. Robert, any updates on this?
Oh yes, sorry, it's been monthes, I've been very busy.

This is my last status :
- my current patch is in (1)

- this patch doesn't work yet

- if my memory serves me well, I have reached the conclusion that dmaengine
pxa-mpp driver doesn't allow pxa_camera to work properly in the current
state. This is a long time since I checked, so take the following with
caution until I have checked again.

This assertion is based on this required behaviour :
- video buffers are queued, let's say 5
=> 5 dma are "prepared"

- video buffers are submitted
=> 5 dma xfers are submitted

- the userspace polls for each finished frame (ie. dma xfer termination), and
on the third one, resubmits the 2 finished frames
=> scatter-gathers should mot be recomputed, just xfer should be
resubmitted, with cache sync operations and first/last descriptors chaining

- the pxa_camera driver needs a way to know if a dma channel is still running,
for missed chaining transfers, because if a channel stopped, the dma xfers
should not be submitted until IRQ "begin of frame" is encoutered. I didn't
find a way for that.

Now, I will retry this weekend, but if I remember correctly the issues I had
were :
- a transfer cannot be resubmitted, it has to be freed and recreated
- if it is resubmitted, the completion is not signaled by the tasklet

Cheers.

--
Robert

(1)
commit 4741ba6 (pxa_camera_dmaengine, backup/pxa_camera_dmaengine)
Author: Robert Jarzmik <robert....@free.fr>
Date: Sat Aug 24 21:13:38 2013 +0200

WIP: pxa_camera dmaengine conversion

Only slightly tested, without much success.

Signed-off-by: Robert Jarzmik <robert....@free.fr>

diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index d4df305..903ea03 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -9,7 +9,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-
+#define DEBUG 1
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
@@ -28,6 +28,9 @@
#include <linux/clk.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/mmp-pdma.h>

#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
@@ -37,7 +40,6 @@

#include <linux/videodev2.h>

-#include <mach/dma.h>
#include <linux/platform_data/camera-pxa.h>

#define PXA_CAM_VERSION "0.0.6"
@@ -174,21 +176,13 @@ enum pxa_camera_active_dma {
DMA_V = 0x4,
};

-/* descriptor needed for the PXA DMA engine */
-struct pxa_cam_dma {
- dma_addr_t sg_dma;
- struct pxa_dma_desc *sg_cpu;
- size_t sg_size;
- int sglen;
-};
-
/* buffer for one video frame */
struct pxa_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
enum v4l2_mbus_pixelcode code;
/* our descriptor lists for Y, U and V channels */
- struct pxa_cam_dma dmas[3];
+ struct dma_async_tx_descriptor *descs[3];
int inwork;
enum pxa_camera_active_dma active_dma;
};
@@ -206,7 +200,7 @@ struct pxa_camera_dev {
void __iomem *base;

int channels;
- unsigned int dma_chans[3];
+ struct dma_chan *dma_chans[3];

struct pxacamera_platform_data *pdata;
struct resource *res;
@@ -221,7 +215,6 @@ struct pxa_camera_dev {
spinlock_t lock;

struct pxa_buffer *active;
- struct pxa_dma_desc *sg_tail[3];

u32 save_cicr[5];
};
@@ -273,40 +266,70 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
videobuf_waiton(vq, &buf->vb, 0, 0);
videobuf_dma_unmap(vq->dev, dma);
videobuf_dma_free(dma);
-
- for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
- if (buf->dmas[i].sg_cpu)
- dma_free_coherent(ici->v4l2_dev.dev,
- buf->dmas[i].sg_size,
- buf->dmas[i].sg_cpu,
- buf->dmas[i].sg_dma);
- buf->dmas[i].sg_cpu = NULL;
- }
+ /* FIXME: free buf->descs[0..2] */

buf->vb.state = VIDEOBUF_NEEDS_INIT;
+
+ dev_dbg(icd->parent, "%s end (vb=0x%p) 0x%08lx %d\n", __func__,
+ &buf->vb, buf->vb.baddr, buf->vb.bsize);
}

-static int calculate_dma_sglen(struct scatterlist *sglist, int sglen,
- int sg_first_ofs, int size)
+static struct scatterlist *videobuf_sg_splice(struct scatterlist *sglist,
+ int sglen, int offset, int size,
+ int *new_sg_len)
{
- int i, offset, dma_len, xfer_len;
- struct scatterlist *sg;
+ struct scatterlist *sg0, *sg;
+ int nfirst, i, dma_len, xfer_len;

- offset = sg_first_ofs;
- for_each_sg(sglist, sg, sglen, i) {
+ sg0 = kmalloc(sizeof(struct scatterlist) * sglen, GFP_KERNEL);
+ if (!sg0)
+ return NULL;
+ for_each_sg(sglist, sg, sglen, nfirst) {
dma_len = sg_dma_len(sg);
-
+ if (offset < dma_len)
+ break;
/* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
- xfer_len = roundup(min(dma_len - offset, size), 8);
-
- size = max(0, size - xfer_len);
- offset = 0;
- if (size == 0)
+ xfer_len = roundup(min(dma_len - offset, offset), 8);
+ offset = max(0, offset - xfer_len);
+ }
+ BUG_ON(sg_is_last(&sglist[nfirst]));
+ for_each_sg(&sglist[nfirst], sg, sglen - nfirst, i) {
+ sg0[i] = sglist[nfirst];
+ sg0[i].offset = offset;
+ sg_dma_len(&sg0[i]) -= offset;
+ if (size <= sg_dma_len(sg))
break;
+ offset = 0;
+ size -= roundup(sg_dma_len(sg), 8);
+ }
+ if (size) {
+ sg_dma_len(&sg0[i]) = size;
+ *new_sg_len = i + 1;
+ } else {
+ *new_sg_len = i;
}

- BUG_ON(size != 0);
- return i + 1;
+ return sg0;
+}
+static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev,
+ enum pxa_camera_active_dma act_dma);
+
+static void pxa_camera_dma_irq_y(void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(pcdev, DMA_Y);
+}
+
+static void pxa_camera_dma_irq_u(void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(pcdev, DMA_U);
+}
+
+static void pxa_camera_dma_irq_v(void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(pcdev, DMA_V);
}

/**
@@ -317,91 +340,68 @@ static int calculate_dma_sglen(struct scatterlist *sglist, int sglen,
* @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V')
* @cibr: camera Receive Buffer Register
* @size: bytes to transfer
- * @sg_first: first element of sg_list
- * @sg_first_ofs: offset in first element of sg_list
+ * @offset: offset in videobuffer of the first byte to transfer
*
* Prepares the pxa dma descriptors to transfer one camera channel.
- * Beware sg_first and sg_first_ofs are both input and output parameters.
*
- * Returns 0 or -ENOMEM if no coherent memory is available
+ * Returns 0 if success or -ENOMEM if no memory is available
*/
static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
struct pxa_buffer *buf,
struct videobuf_dmabuf *dma, int channel,
- int cibr, int size,
- struct scatterlist **sg_first, int *sg_first_ofs)
+ int cibr, int size, int offset)
{
- struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
- struct device *dev = pcdev->soc_host.v4l2_dev.dev;
- struct scatterlist *sg;
- int i, offset, sglen;
- int dma_len = 0, xfer_len = 0;
+ struct dma_chan *dma_chan = pcdev->dma_chans[channel];
+ struct scatterlist *sg = NULL;
+ int ret, sglen;
+ struct dma_slave_config config;
+ struct dma_async_tx_descriptor *tx;

- if (pxa_dma->sg_cpu)
- dma_free_coherent(dev, pxa_dma->sg_size,
- pxa_dma->sg_cpu, pxa_dma->sg_dma);
+ dmaengine_terminate_all(dma_chan);

- sglen = calculate_dma_sglen(*sg_first, dma->sglen,
- *sg_first_ofs, size);
-
- pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
- pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size,
- &pxa_dma->sg_dma, GFP_KERNEL);
- if (!pxa_dma->sg_cpu)
+ sg = videobuf_sg_splice(dma->sglist, dma->sglen, offset, size, &sglen);
+ if (!sg)
return -ENOMEM;

- pxa_dma->sglen = sglen;
- offset = *sg_first_ofs;
-
- dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
- *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
-
+ memset(&config, 0, sizeof(config));
+ config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; /* FIXME? */
+ config.src_maxburst = 8;
+ config.src_addr = pcdev->res->start + cibr;
+ config.direction = DMA_DEV_TO_MEM;

- for_each_sg(*sg_first, sg, sglen, i) {
- dma_len = sg_dma_len(sg);
-
- /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
- xfer_len = roundup(min(dma_len - offset, size), 8);
-
- size = max(0, size - xfer_len);
-
- pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr;
- pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset;
- pxa_dma->sg_cpu[i].dcmd =
- DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len;
-#ifdef DEBUG
- if (!i)
- pxa_dma->sg_cpu[i].dcmd |= DCMD_STARTIRQEN;
-#endif
- pxa_dma->sg_cpu[i].ddadr =
- pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
-
- dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
- pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
- sg_dma_address(sg) + offset, xfer_len);
- offset = 0;
-
- if (size == 0)
- break;
+ ret = dmaengine_slave_config(dma_chan, &config);
+ if (ret < 0) {
+ printk("%s(): dma slave config failed: %d\n", __func__, ret);
+ return ret;
}

- pxa_dma->sg_cpu[sglen].ddadr = DDADR_STOP;
- pxa_dma->sg_cpu[sglen].dcmd = DCMD_FLOWSRC | DCMD_BURST8 | DCMD_ENDIRQEN;
+ tx = dmaengine_prep_slave_sg(dma_chan, sg, sglen,
+ config.direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tx) {
+ printk("%s(): prep_slave_sg() failed\n", __func__);
+ goto fail;
+ }

- /*
- * Handle 1 special case :
- * - in 3 planes (YUV422P format), we might finish with xfer_len equal
- * to dma_len (end on PAGE boundary). In this case, the sg element
- * for next plane should be the next after the last used to store the
- * last scatter gather RAM page
- */
- if (xfer_len >= dma_len) {
- *sg_first_ofs = xfer_len - dma_len;
- *sg_first = sg_next(sg);
- } else {
- *sg_first_ofs = xfer_len;
- *sg_first = sg;
+ tx->callback_param = pcdev;
+ switch (channel) {
+ case 0:
+ tx->callback = pxa_camera_dma_irq_y;
+ break;
+ case 1:
+ tx->callback = pxa_camera_dma_irq_u;
+ break;
+ case 2:
+ tx->callback = pxa_camera_dma_irq_v;
+ break;
}
+fail:
+ kfree(sg);
+ buf->descs[channel] = tx;
+
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s (vb=0x%p) dma_tx=%p\n",
+ __func__, &buf->vb, tx);

return 0;
}
@@ -470,11 +470,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
goto out;
}

- if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ //if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ if (vb->state != VIDEOBUF_PREPARED) {
int size = vb->size;
- int next_ofs = 0;
struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
- struct scatterlist *sg;

ret = videobuf_iolock(vq, vb, NULL);
if (ret)
@@ -487,11 +486,8 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
size_y = size;
}

- sg = dma->sglist;
-
/* init DMA for Y channel */
- ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
- &sg, &next_ofs);
+ ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y, 0);
if (ret) {
dev_err(dev, "DMA initialization for Y/RGB failed\n");
goto fail;
@@ -500,7 +496,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
/* init DMA for U channel */
if (size_u)
ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
- size_u, &sg, &next_ofs);
+ size_u, size_y);
if (ret) {
dev_err(dev, "DMA initialization for U failed\n");
goto fail_u;
@@ -509,7 +505,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
/* init DMA for V channel */
if (size_v)
ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
- size_v, &sg, &next_ofs);
+ size_v, size_y + size_u);
if (ret) {
dev_err(dev, "DMA initialization for V failed\n");
goto fail_v;
@@ -524,11 +520,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
return 0;

fail_v:
- dma_free_coherent(dev, buf->dmas[1].sg_size,
- buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
fail_u:
- dma_free_coherent(dev, buf->dmas[0].sg_size,
- buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
fail:
free_buffer(vq, buf);
out:
@@ -552,10 +544,8 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)

for (i = 0; i < pcdev->channels; i++) {
dev_dbg(pcdev->soc_host.v4l2_dev.dev,
- "%s (channel=%d) ddadr=%08x\n", __func__,
- i, active->dmas[i].sg_dma);
- DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
- DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+ "%s (channel=%d)\n", __func__, i);
+ dma_async_issue_pending(pcdev->dma_chans[i]);
}
}

@@ -566,7 +556,7 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
for (i = 0; i < pcdev->channels; i++) {
dev_dbg(pcdev->soc_host.v4l2_dev.dev,
"%s (channel=%d)\n", __func__, i);
- DCSR(pcdev->dma_chans[i]) = 0;
+ dmaengine_terminate_all(pcdev->dma_chans[i]);
}
}

@@ -574,18 +564,12 @@ static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev,
struct pxa_buffer *buf)
{
int i;
- struct pxa_dma_desc *buf_last_desc;

for (i = 0; i < pcdev->channels; i++) {
- buf_last_desc = buf->dmas[i].sg_cpu + buf->dmas[i].sglen;
- buf_last_desc->ddadr = DDADR_STOP;
-
- if (pcdev->sg_tail[i])
- /* Link the new buffer to the old tail */
- pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma;
-
- /* Update the channel tail */
- pcdev->sg_tail[i] = buf_last_desc;
+ dmaengine_submit(buf->descs[i]);
+ dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+ "%s (channel=%d) : submit vb=%p cookie=%d\n",
+ __func__, i, buf, buf->descs[i]->cookie);
}
}

@@ -676,8 +660,6 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
struct videobuf_buffer *vb,
struct pxa_buffer *buf)
{
- int i;
-
/* _init is used to debug races, see comment in pxa_camera_reqbufs() */
list_del_init(&vb->queue);
vb->state = VIDEOBUF_DONE;
@@ -689,8 +671,6 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,

if (list_empty(&pcdev->capture)) {
pxa_camera_stop_capture(pcdev);
- for (i = 0; i < pcdev->channels; i++)
- pcdev->sg_tail[i] = NULL;
return;
}

@@ -716,48 +696,33 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
*/
static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
{
- int i, is_dma_stopped = 1;
+ /* FIXME: ask dmaengine if channel is still running */
+ int is_dma_stopped = 1;

- for (i = 0; i < pcdev->channels; i++)
- if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP)
- is_dma_stopped = 0;
dev_dbg(pcdev->soc_host.v4l2_dev.dev,
- "%s : top queued buffer=%p, dma_stopped=%d\n",
- __func__, pcdev->active, is_dma_stopped);
+ "%s : top queued buffer=%p\n", __func__, pcdev->active);
+ if (pcdev->active)
+ pxa_dma_start_channels(pcdev);
if (pcdev->active && is_dma_stopped)
pxa_camera_start_capture(pcdev);
}

-static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
+static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev,
enum pxa_camera_active_dma act_dma)
{
struct device *dev = pcdev->soc_host.v4l2_dev.dev;
struct pxa_buffer *buf;
unsigned long flags;
- u32 status, camera_status, overrun;
+ u32 camera_status, overrun;
struct videobuf_buffer *vb;

spin_lock_irqsave(&pcdev->lock, flags);

- status = DCSR(channel);
- DCSR(channel) = status;
-
camera_status = __raw_readl(pcdev->base + CISR);
overrun = CISR_IFO_0;
if (pcdev->channels == 3)
overrun |= CISR_IFO_1 | CISR_IFO_2;

- if (status & DCSR_BUSERR) {
- dev_err(dev, "DMA Bus Error IRQ!\n");
- goto out;
- }
-
- if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
- dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n",
- status);
- goto out;
- }
-
/*
* pcdev->active should not be NULL in DMA irq handler.
*
@@ -777,52 +742,28 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
buf = container_of(vb, struct pxa_buffer, vb);
WARN_ON(buf->inwork || list_empty(&vb->queue));

- dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
- __func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
- status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
-
- if (status & DCSR_ENDINTR) {
- /*
- * It's normal if the last frame creates an overrun, as there
- * are no more DMA descriptors to fetch from QCI fifos
- */
- if (camera_status & overrun &&
- !list_is_last(pcdev->capture.next, &pcdev->capture)) {
- dev_dbg(dev, "FIFO overrun! CISR: %x\n",
- camera_status);
- pxa_camera_stop_capture(pcdev);
- pxa_camera_start_capture(pcdev);
- goto out;
- }
- buf->active_dma &= ~act_dma;
- if (!buf->active_dma) {
- pxa_camera_wakeup(pcdev, vb, buf);
- pxa_camera_check_link_miss(pcdev);
- }
+ /*
+ * It's normal if the last frame creates an overrun, as there
+ * are no more DMA descriptors to fetch from QCI fifos
+ */
+ if (camera_status & overrun &&
+ !list_is_last(pcdev->capture.next, &pcdev->capture)) {
+ dev_dbg(dev, "FIFO overrun! CISR: %x\n",
+ camera_status);
+ pxa_camera_stop_capture(pcdev);
+ pxa_camera_start_capture(pcdev);
+ goto out;
+ }
+ buf->active_dma &= ~act_dma;
+ if (!buf->active_dma) {
+ pxa_camera_wakeup(pcdev, vb, buf);
+ pxa_camera_check_link_miss(pcdev);
}

out:
spin_unlock_irqrestore(&pcdev->lock, flags);
}

-static void pxa_camera_dma_irq_y(int channel, void *data)
-{
- struct pxa_camera_dev *pcdev = data;
- pxa_camera_dma_irq(channel, pcdev, DMA_Y);
-}
-
-static void pxa_camera_dma_irq_u(int channel, void *data)
-{
- struct pxa_camera_dev *pcdev = data;
- pxa_camera_dma_irq(channel, pcdev, DMA_U);
-}
-
-static void pxa_camera_dma_irq_v(int channel, void *data)
-{
- struct pxa_camera_dev *pcdev = data;
- pxa_camera_dma_irq(channel, pcdev, DMA_V);
-}
-
static struct videobuf_queue_ops pxa_videobuf_ops = {
.buf_setup = pxa_videobuf_setup,
.buf_prepare = pxa_videobuf_prepare,
@@ -992,10 +933,7 @@ static void pxa_camera_clock_stop(struct soc_camera_host *ici)
__raw_writel(0x3ff, pcdev->base + CICR0);

/* Stop DMA engine */
- DCSR(pcdev->dma_chans[0]) = 0;
- DCSR(pcdev->dma_chans[1]) = 0;
- DCSR(pcdev->dma_chans[2]) = 0;
-
+ pxa_dma_stop_channels(pcdev);
pxa_camera_deactivate(pcdev);
}

@@ -1608,10 +1546,6 @@ static int pxa_camera_resume(struct device *dev)
struct pxa_camera_dev *pcdev = ici->priv;
int i = 0, ret = 0;

- DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
- DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
- DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
-
__raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0);
__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1);
__raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2);
@@ -1655,6 +1589,8 @@ static int pxa_camera_probe(struct platform_device *pdev)
struct pxa_camera_dev *pcdev;
struct resource *res;
void __iomem *base;
+ dma_cap_mask_t mask;
+ unsigned int drcmr;
int irq;
int err = 0;

@@ -1717,36 +1653,35 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->base = base;

/* request dma */
- err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
- pxa_camera_dma_irq_y, pcdev);
- if (err < 0) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ drcmr = 68;
+ pcdev->dma_chans[0] =
+ dma_request_slave_channel_compat(mask, mmp_pdma_filter_fn,
+ &drcmr, &pdev->dev, "CI_Y");
+ if (!pcdev->dma_chans[0]) {
dev_err(&pdev->dev, "Can't request DMA for Y\n");
- return err;
+ return -ENODEV;
}
- pcdev->dma_chans[0] = err;
- dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);

- err = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
- pxa_camera_dma_irq_u, pcdev);
- if (err < 0) {
- dev_err(&pdev->dev, "Can't request DMA for U\n");
+ drcmr = 69;
+ pcdev->dma_chans[1] =
+ dma_request_slave_channel_compat(mask, mmp_pdma_filter_fn,
+ &drcmr, &pdev->dev, "CI_U");
+ if (!pcdev->dma_chans[1]) {
+ dev_err(&pdev->dev, "Can't request DMA for Y\n");
goto exit_free_dma_y;
}
- pcdev->dma_chans[1] = err;
- dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);

- err = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
- pxa_camera_dma_irq_v, pcdev);
- if (err < 0) {
+ drcmr = 70;
+ pcdev->dma_chans[2] =
+ dma_request_slave_channel_compat(mask, mmp_pdma_filter_fn,
+ &drcmr, &pdev->dev, "CI_V");
+ if (!pcdev->dma_chans[2]) {
dev_err(&pdev->dev, "Can't request DMA for V\n");
goto exit_free_dma_u;
}
- pcdev->dma_chans[2] = err;
- dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
-
- DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
- DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
- DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;

/* request irq */
err = devm_request_irq(&pdev->dev, pcdev->irq, pxa_camera_irq, 0,
@@ -1769,11 +1704,11 @@ static int pxa_camera_probe(struct platform_device *pdev)
return 0;

exit_free_dma:
- pxa_free_dma(pcdev->dma_chans[2]);
+ dma_release_channel(pcdev->dma_chans[2]);
exit_free_dma_u:
- pxa_free_dma(pcdev->dma_chans[1]);
+ dma_release_channel(pcdev->dma_chans[1]);
exit_free_dma_y:
- pxa_free_dma(pcdev->dma_chans[0]);
+ dma_release_channel(pcdev->dma_chans[0]);
return err;
}

@@ -1783,9 +1718,9 @@ static int pxa_camera_remove(struct platform_device *pdev)
struct pxa_camera_dev *pcdev = container_of(soc_host,
struct pxa_camera_dev, soc_host);

- pxa_free_dma(pcdev->dma_chans[0]);
- pxa_free_dma(pcdev->dma_chans[1]);
- pxa_free_dma(pcdev->dma_chans[2]);
+ dma_release_channel(pcdev->dma_chans[0]);
+ dma_release_channel(pcdev->dma_chans[1]);
+ dma_release_channel(pcdev->dma_chans[2]);

soc_camera_host_unregister(soc_host);

----------

Arnd Bergmann

unread,
Dec 11, 2013, 10:00:02 AM12/11/13
to
On Wednesday 11 December 2013, Sergei Ianovich wrote:
> On Wed, 2013-12-11 at 06:11 +0100, Arnd Bergmann wrote:
> > It depends: if the driver is for the entire FPGA and does
> > the irqchip stuff in addition, it should probably live
> > in drivers/mfd. If it's a pure irqchip driver, drivers/irqchip
> > is better. You have to be careful in the second case though
> > because devices pointing to this irqchip in DT won't get
> > an IRQ resource assigned automatically but have to use
> > irq_of_parse_and_map instead. This may have been fixed since
> > I last looked though, I would consider that behavior a
> > bug in the of_platform handling.
>
> Thanks again for explaining.
>
> Although FPGA is a MFD, its irq are used mostly by 8250 serial ports. It
> will be enough to embed irqchip into serial driver for now.
>
> If there is a need to use the chip in another driver, it will be
> possible to introduce an artificial dependency there for the serial
> driver to ensure the serial driver is loaded before the other one.
>
> Is this plan acceptable?
>

If you already have an MFD driver, I think it's more logical to put
the irqchip in there, we have a number of other MFD drivers doing the
same but I have not seen a UART driver that comes with its own irqchip.

Arnd

Linus Walleij

unread,
Dec 12, 2013, 3:00:02 PM12/12/13
to
On Tue, Dec 10, 2013 at 1:47 PM, Sergei Ianovich <ynv...@gmail.com> wrote:
> On Tue, 2013-12-10 at 13:43 +0100, Linus Walleij wrote:
>> Argh! Now you're adding another user for a legacy custom pin control
>> implementation. But if noone is going to modernize PXA2xx what
>> can we do :-/
>
> I've rewritten the device to use device tree and posted patch series for
> that.

THANKS! For doing this.

Yours,
Linus Walleij

Linus Walleij

unread,
Dec 12, 2013, 3:10:02 PM12/12/13
to
On Tue, Dec 10, 2013 at 1:54 PM, Vasily Khoruzhick <anar...@gmail.com> wrote:
> On Tue, Dec 10, 2013 at 3:43 PM, Linus Walleij <linus....@linaro.org> wrote:

>> Argh! Now you're adding another user for a legacy custom pin control
>> implementation. But if noone is going to modernize PXA2xx what
>> can we do :-/
>
> I tried a ~year ago, but it's not so trivial. PXA2xx has no separate
> pin control module, it's
> highly integrated into GPIO controller. I've asked the maillist what
> should I do for that case, but AFAIR no one answered.

It is very common for pin controllers and GPIO blocks to
be integrated.

The usual solution is to make a combined driver that registers
both pinctrl and GPIO interfaces and put that into
drivers/pinctrl.

Here is a recent example that can be used as inspiration:
http://marc.info/?l=linux-doc&m=138629591206248&w=2

Yours,
Linus Walleij

Sergei Ianovich

unread,
Dec 12, 2013, 9:30:02 PM12/12/13
to
Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
v1..v2
* no changes

arch/arm/boot/dts/pxa27x.dtsi | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/pxa27x.dtsi b/arch/arm/boot/dts/pxa27x.dtsi
index d7c5d72..44df554 100644
--- a/arch/arm/boot/dts/pxa27x.dtsi
+++ b/arch/arm/boot/dts/pxa27x.dtsi
@@ -10,5 +10,11 @@
marvell,intc-priority;
marvell,intc-nr-irqs = <34>;
};
+
+ gpio: gpio@40e00000 {
+ compatible = "intel,pxa27x-gpio";
+ interrupts = <8>, <9>, <10>;
+ interrupt-names = "gpio0", "gpio1", "gpio_mux";
+ };
};
};
--
1.8.4.3

Sergei Ianovich

unread,
Dec 12, 2013, 9:30:02 PM12/12/13
to
Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
---
v0..v2
* use device tree
* use devm helpers where possible

.../devicetree/bindings/rtc/rtc-ds1302.txt | 14 +++
arch/arm/boot/dts/pxa27x-lp8x4x.dts | 6 ++
arch/arm/configs/lp8x4x_defconfig | 1 +
drivers/rtc/Kconfig | 2 +-
drivers/rtc/rtc-ds1302.c | 111 ++++++++++++++++++++-
5 files changed, 131 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/rtc/rtc-ds1302.txt

diff --git a/Documentation/devicetree/bindings/rtc/rtc-ds1302.txt b/Documentation/devicetree/bindings/rtc/rtc-ds1302.txt
new file mode 100644
index 0000000..876297c
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/rtc-ds1302.txt
@@ -0,0 +1,14 @@
+* Dallas Semiconductor DS-1302 RTC
+
+Simple device which could be used to store date/time between reboots.
+
+Required properties:
+- compatible : Should be "ds,rtc-ds1302"
+- reg : Should be address and size of IO memory region
+
+Examples:
+
+rtc@40900000 {
+ compatible = "ds,rtc-ds1302";
+ reg = <0x1700901c 0x1>;
+};
diff --git a/arch/arm/boot/dts/pxa27x-lp8x4x.dts b/arch/arm/boot/dts/pxa27x-lp8x4x.dts
index a2a9183..574e853 100644
--- a/arch/arm/boot/dts/pxa27x-lp8x4x.dts
+++ b/arch/arm/boot/dts/pxa27x-lp8x4x.dts
@@ -107,5 +107,11 @@
interrupts = <82 IRQ_TYPE_EDGE_RISING>;
status = "okay";
};
+
+ rtc@1700901c {
+ compatible = "ds,rtc-ds1302";
+ reg = <0x1700901c 0x1>;
+ status = "okay";
+ };
};
};
diff --git a/arch/arm/configs/lp8x4x_defconfig b/arch/arm/configs/lp8x4x_defconfig
index 4421c03..57f2830 100644
--- a/arch/arm/configs/lp8x4x_defconfig
+++ b/arch/arm/configs/lp8x4x_defconfig
@@ -133,6 +133,7 @@ CONFIG_USB_SERIAL=m
CONFIG_MMC=y
CONFIG_MMC_PXA=y
CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1302=y
CONFIG_RTC_DRV_PXA=m
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT2_FS=m
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 0077302..501055f 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -676,7 +676,7 @@ config RTC_DRV_DS1286

config RTC_DRV_DS1302
tristate "Dallas DS1302"
- depends on SH_SECUREEDGE5410
+ depends on SH_SECUREEDGE5410 || (ARCH_PXA && HIGH_RES_TIMERS)
help
If you say yes here you get support for the Dallas DS1302 RTC chips.

diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 07e8d79..d88749c 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -50,7 +50,7 @@
#define ds1302_set_tx()
#define ds1302_set_rx()

-static inline int ds1302_hw_init(void)
+static inline int ds1302_hw_init(struct platform_device *pdev)
{
return 0;
}
@@ -86,6 +86,112 @@ static inline int ds1302_rxbit(void)
return !!(get_dp() & RTC_IODATA);
}

+#elif defined(CONFIG_ARCH_PXA) && defined(CONFIG_HIGH_RES_TIMERS)
+
+#include <linux/hrtimer.h>
+#include <linux/of.h>
+#include <linux/sched.h>
+
+#define RTC_CE 0x01
+#define RTC_CLK 0x02
+#define RTC_nWE 0x04
+#define RTC_IODATA 0x08
+
+static unsigned long ds1302_state;
+
+static void *mem;
+
+void nsleep(unsigned long nanosec)
+{
+ ktime_t t = ns_to_ktime(nanosec);
+ long state = current->state;
+
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&t, HRTIMER_MODE_REL);
+ __set_current_state(state);
+}
+
+static inline int ds1302_hw_init(struct platform_device *pdev)
+{
+ struct resource *r;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ mem = devm_ioremap_resource(&pdev->dev, r);
+ if (!mem)
+ return -EFAULT;
+
+ return 0;
+}
+
+static inline void ds1302_reset(void)
+{
+ ds1302_state = 0;
+ iowrite8(ds1302_state, mem);
+ nsleep(4000);
+}
+
+static inline void ds1302_clock(void)
+{
+ nsleep(1000);
+ ds1302_state |= RTC_CLK;
+ iowrite8(ds1302_state, mem);
+ nsleep(1000);
+ ds1302_state &= ~RTC_CLK;
+ iowrite8(ds1302_state, mem);
+}
+
+static inline void ds1302_start(void)
+{
+ ds1302_state &= ~RTC_CLK;
+ ds1302_state |= RTC_CE;
+ iowrite8(ds1302_state, mem);
+ nsleep(3000);
+}
+
+static inline void ds1302_stop(void)
+{
+ ds1302_state &= ~RTC_CE;
+ iowrite8(ds1302_state, mem);
+}
+
+static inline void ds1302_set_tx(void)
+{
+ ds1302_state &= ~RTC_nWE;
+ iowrite8(ds1302_state, mem);
+}
+
+static inline void ds1302_set_rx(void)
+{
+ ds1302_state |= RTC_nWE;
+ iowrite8(ds1302_state, mem);
+}
+
+static inline void ds1302_txbit(int bit)
+{
+ if (bit)
+ ds1302_state |= RTC_IODATA;
+ else
+ ds1302_state &= ~RTC_IODATA;
+ iowrite8(ds1302_state, mem);
+}
+
+static inline int ds1302_rxbit(void)
+{
+ return ioread8(mem) & 0x1;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ds1302_dt_ids[] = {
+ { .compatible = "ds,rtc-ds1302" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, ds1302_dt_ids);
+#endif
+
#else
#error "Add support for your platform"
#endif
@@ -216,7 +322,7 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;

- if (ds1302_hw_init()) {
+ if (ds1302_hw_init(pdev)) {
dev_err(&pdev->dev, "Failed to init communication channel");
return -EINVAL;
}
@@ -245,6 +351,7 @@ static struct platform_driver ds1302_platform_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ds1302_dt_ids),
},

Sergei Ianovich

unread,
Dec 12, 2013, 9:30:02 PM12/12/13
to
This way it will be more difficult to change the declaration in one
place, but not the other.

In addition, the change allows to use the binding for pxa-gpio on
other PXA CPUs.

Signed-off-by: Sergei Ianovich <ynv...@gmail.com>
CC: Daniel Mack <zon...@gmail.com>
CC: Arnd Bergmann <ar...@arndb.de>
---
v1..v2
* drop #ifdef in header file
* number changed from 6 to 4 (dropped patches)

arch/arm/mach-pxa/include/mach/irqs.h | 2 ++
arch/arm/mach-pxa/pxa3xx.c | 2 --
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-pxa/include/mach/irqs.h b/arch/arm/mach-pxa/include/mach/irqs.h
index 48c2fd8..732315d 100644
--- a/arch/arm/mach-pxa/include/mach/irqs.h
+++ b/arch/arm/mach-pxa/include/mach/irqs.h
@@ -113,4 +113,6 @@ void ichp_handle_irq(struct pt_regs *);
void pxa_init_irq(int irq_nr, int (*set_wake)(struct irq_data *, unsigned int));
#endif

+extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int));
+
#endif /* __ASM_MACH_IRQS_H */
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 87011f3..2397dec 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -42,8 +42,6 @@
#define PECR_IE(n) ((1 << ((n) * 2)) << 28)
#define PECR_IS(n) ((1 << ((n) * 2)) << 29)

-extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int));
-
static DEFINE_PXA3_CKEN(pxa3xx_ffuart, FFUART, 14857000, 1);
static DEFINE_PXA3_CKEN(pxa3xx_btuart, BTUART, 14857000, 1);
static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1);
It is loading more messages.
0 new messages