summaryrefslogtreecommitdiffstats
path: root/drivers/staging/board
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:27:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:27:49 +0000
commitace9429bb58fd418f0c81d4c2835699bddf6bde6 (patch)
treeb2d64bc10158fdd5497876388cd68142ca374ed3 /drivers/staging/board
parentInitial commit. (diff)
downloadlinux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.tar.xz
linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.zip
Adding upstream version 6.6.15.upstream/6.6.15
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/staging/board')
-rw-r--r--drivers/staging/board/Kconfig12
-rw-r--r--drivers/staging/board/Makefile4
-rw-r--r--drivers/staging/board/TODO2
-rw-r--r--drivers/staging/board/armadillo800eva.c88
-rw-r--r--drivers/staging/board/board.c204
-rw-r--r--drivers/staging/board/board.h46
-rw-r--r--drivers/staging/board/kzm9d.c26
7 files changed, 382 insertions, 0 deletions
diff --git a/drivers/staging/board/Kconfig b/drivers/staging/board/Kconfig
new file mode 100644
index 0000000000..b49216768e
--- /dev/null
+++ b/drivers/staging/board/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+config STAGING_BOARD
+ bool "Staging Board Support"
+ depends on OF_ADDRESS && OF_IRQ && HAVE_CLK
+ help
+ Staging board base is to support continuous upstream
+ in-tree development and integration of platform devices.
+
+ Helps developers integrate devices as platform devices for
+ device drivers that only provide platform device bindings.
+ This in turn allows for incremental development of both
+ hardware feature support and DT binding work in parallel.
diff --git a/drivers/staging/board/Makefile b/drivers/staging/board/Makefile
new file mode 100644
index 0000000000..ed7839752e
--- /dev/null
+++ b/drivers/staging/board/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-y := board.o
+obj-$(CONFIG_ARCH_EMEV2) += kzm9d.o
+obj-$(CONFIG_ARCH_R8A7740) += armadillo800eva.o
diff --git a/drivers/staging/board/TODO b/drivers/staging/board/TODO
new file mode 100644
index 0000000000..8db70e10aa
--- /dev/null
+++ b/drivers/staging/board/TODO
@@ -0,0 +1,2 @@
+* replace platform device code with DT nodes once the driver supports DT
+* remove staging board code when no more platform devices are needed
diff --git a/drivers/staging/board/armadillo800eva.c b/drivers/staging/board/armadillo800eva.c
new file mode 100644
index 0000000000..0225234dd7
--- /dev/null
+++ b/drivers/staging/board/armadillo800eva.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Staging board support for Armadillo 800 eva.
+ * Enable not-yet-DT-capable devices here.
+ *
+ * Based on board-armadillo800eva.c
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+
+#include <video/sh_mobile_lcdc.h>
+
+#include "board.h"
+
+static struct fb_videomode lcdc0_mode = {
+ .name = "AMPIER/AM-800480",
+ .xres = 800,
+ .yres = 480,
+ .left_margin = 88,
+ .right_margin = 40,
+ .hsync_len = 128,
+ .upper_margin = 20,
+ .lower_margin = 5,
+ .vsync_len = 5,
+ .sync = 0,
+};
+
+static struct sh_mobile_lcdc_info lcdc0_info = {
+ .clock_source = LCDC_CLK_BUS,
+ .ch[0] = {
+ .chan = LCDC_CHAN_MAINLCD,
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .interface_type = RGB24,
+ .clock_divider = 5,
+ .flags = 0,
+ .lcd_modes = &lcdc0_mode,
+ .num_modes = 1,
+ .panel_cfg = {
+ .width = 111,
+ .height = 68,
+ },
+ },
+};
+
+static struct resource lcdc0_resources[] = {
+ DEFINE_RES_MEM_NAMED(0xfe940000, 0x4000, "LCD0"),
+ DEFINE_RES_IRQ(177 + 32),
+};
+
+static struct platform_device lcdc0_device = {
+ .name = "sh_mobile_lcdc_fb",
+ .num_resources = ARRAY_SIZE(lcdc0_resources),
+ .resource = lcdc0_resources,
+ .id = 0,
+ .dev = {
+ .platform_data = &lcdc0_info,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static const struct board_staging_clk lcdc0_clocks[] __initconst = {
+ { "lcdc0", NULL, "sh_mobile_lcdc_fb.0" },
+};
+
+static const struct board_staging_dev armadillo800eva_devices[] __initconst = {
+ {
+ .pdev = &lcdc0_device,
+ .clocks = lcdc0_clocks,
+ .nclocks = ARRAY_SIZE(lcdc0_clocks),
+ .domain = "/system-controller@e6180000/pm-domains/c5/a4lc@1"
+ },
+};
+
+static void __init armadillo800eva_init(void)
+{
+ board_staging_gic_setup_xlate("arm,pl390", 32);
+ board_staging_register_devices(armadillo800eva_devices,
+ ARRAY_SIZE(armadillo800eva_devices));
+}
+
+board_staging("renesas,armadillo800eva", armadillo800eva_init);
diff --git a/drivers/staging/board/board.c b/drivers/staging/board/board.c
new file mode 100644
index 0000000000..f980af0373
--- /dev/null
+++ b/drivers/staging/board/board.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2014 Magnus Damm
+ * Copyright (C) 2015 Glider bvba
+ */
+
+#define pr_fmt(fmt) "board_staging: " fmt
+
+#include <linux/clkdev.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+
+#include "board.h"
+
+static struct device_node *irqc_node __initdata;
+static unsigned int irqc_base __initdata;
+
+static bool find_by_address(u64 base_address)
+{
+ struct device_node *dn = of_find_all_nodes(NULL);
+ struct resource res;
+
+ while (dn) {
+ if (!of_address_to_resource(dn, 0, &res)) {
+ if (res.start == base_address) {
+ of_node_put(dn);
+ return true;
+ }
+ }
+ dn = of_find_all_nodes(dn);
+ }
+
+ return false;
+}
+
+bool __init board_staging_dt_node_available(const struct resource *resource,
+ unsigned int num_resources)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_resources; i++) {
+ const struct resource *r = resource + i;
+
+ if (resource_type(r) == IORESOURCE_MEM)
+ if (find_by_address(r->start))
+ return true; /* DT node available */
+ }
+
+ return false; /* Nothing found */
+}
+
+int __init board_staging_gic_setup_xlate(const char *gic_match,
+ unsigned int base)
+{
+ WARN_ON(irqc_node);
+
+ irqc_node = of_find_compatible_node(NULL, NULL, gic_match);
+
+ WARN_ON(!irqc_node);
+ if (!irqc_node)
+ return -ENOENT;
+
+ irqc_base = base;
+ return 0;
+}
+
+static void __init gic_fixup_resource(struct resource *res)
+{
+ struct of_phandle_args irq_data;
+ unsigned int hwirq = res->start;
+ unsigned int virq;
+
+ if (resource_type(res) != IORESOURCE_IRQ || !irqc_node)
+ return;
+
+ irq_data.np = irqc_node;
+ irq_data.args_count = 3;
+ irq_data.args[0] = 0;
+ irq_data.args[1] = hwirq - irqc_base;
+ switch (res->flags &
+ (IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE |
+ IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL)) {
+ case IORESOURCE_IRQ_LOWEDGE:
+ irq_data.args[2] = IRQ_TYPE_EDGE_FALLING;
+ break;
+ case IORESOURCE_IRQ_HIGHEDGE:
+ irq_data.args[2] = IRQ_TYPE_EDGE_RISING;
+ break;
+ case IORESOURCE_IRQ_LOWLEVEL:
+ irq_data.args[2] = IRQ_TYPE_LEVEL_LOW;
+ break;
+ case IORESOURCE_IRQ_HIGHLEVEL:
+ default:
+ irq_data.args[2] = IRQ_TYPE_LEVEL_HIGH;
+ break;
+ }
+
+ virq = irq_create_of_mapping(&irq_data);
+ if (WARN_ON(!virq))
+ return;
+
+ pr_debug("hwirq %u -> virq %u\n", hwirq, virq);
+ res->start = virq;
+}
+
+void __init board_staging_gic_fixup_resources(struct resource *res,
+ unsigned int nres)
+{
+ unsigned int i;
+
+ for (i = 0; i < nres; i++)
+ gic_fixup_resource(&res[i]);
+}
+
+int __init board_staging_register_clock(const struct board_staging_clk *bsc)
+{
+ int error;
+
+ pr_debug("Aliasing clock %s for con_id %s dev_id %s\n", bsc->clk,
+ bsc->con_id, bsc->dev_id);
+ error = clk_add_alias(bsc->con_id, bsc->dev_id, bsc->clk, NULL);
+ if (error)
+ pr_err("Failed to alias clock %s (%d)\n", bsc->clk, error);
+
+ return error;
+}
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
+static int board_staging_add_dev_domain(struct platform_device *pdev,
+ const char *domain)
+{
+ struct device *dev = &pdev->dev;
+ struct of_phandle_args pd_args;
+ struct device_node *np;
+
+ np = of_find_node_by_path(domain);
+ if (!np) {
+ pr_err("Cannot find domain node %s\n", domain);
+ return -ENOENT;
+ }
+
+ pd_args.np = np;
+ pd_args.args_count = 0;
+
+ /* Initialization similar to device_pm_init_common() */
+ spin_lock_init(&dev->power.lock);
+ dev->power.early_init = true;
+
+ return of_genpd_add_device(&pd_args, dev);
+}
+#else
+static inline int board_staging_add_dev_domain(struct platform_device *pdev,
+ const char *domain)
+{
+ return 0;
+}
+#endif
+
+int __init board_staging_register_device(const struct board_staging_dev *dev)
+{
+ struct platform_device *pdev = dev->pdev;
+ unsigned int i;
+ int error;
+
+ pr_debug("Trying to register device %s\n", pdev->name);
+ if (board_staging_dt_node_available(pdev->resource,
+ pdev->num_resources)) {
+ pr_warn("Skipping %s, already in DT\n", pdev->name);
+ return -EEXIST;
+ }
+
+ board_staging_gic_fixup_resources(pdev->resource, pdev->num_resources);
+
+ for (i = 0; i < dev->nclocks; i++)
+ board_staging_register_clock(&dev->clocks[i]);
+
+ if (dev->domain)
+ board_staging_add_dev_domain(pdev, dev->domain);
+
+ error = platform_device_register(pdev);
+ if (error) {
+ pr_err("Failed to register device %s (%d)\n", pdev->name,
+ error);
+ return error;
+ }
+
+ return error;
+}
+
+void __init board_staging_register_devices(const struct board_staging_dev *devs,
+ unsigned int ndevs)
+{
+ unsigned int i;
+
+ for (i = 0; i < ndevs; i++)
+ board_staging_register_device(&devs[i]);
+}
diff --git a/drivers/staging/board/board.h b/drivers/staging/board/board.h
new file mode 100644
index 0000000000..5609daf4d8
--- /dev/null
+++ b/drivers/staging/board/board.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __BOARD_H__
+#define __BOARD_H__
+
+#include <linux/init.h>
+#include <linux/of.h>
+
+struct board_staging_clk {
+ const char *clk;
+ const char *con_id;
+ const char *dev_id;
+};
+
+struct board_staging_dev {
+ /* Platform Device */
+ struct platform_device *pdev;
+ /* Clocks (optional) */
+ const struct board_staging_clk *clocks;
+ unsigned int nclocks;
+ /* Generic PM Domain (optional) */
+ const char *domain;
+};
+
+struct resource;
+
+bool board_staging_dt_node_available(const struct resource *resource,
+ unsigned int num_resources);
+int board_staging_gic_setup_xlate(const char *gic_match, unsigned int base);
+void board_staging_gic_fixup_resources(struct resource *res, unsigned int nres);
+int board_staging_register_clock(const struct board_staging_clk *bsc);
+int board_staging_register_device(const struct board_staging_dev *dev);
+void board_staging_register_devices(const struct board_staging_dev *devs,
+ unsigned int ndevs);
+
+#define board_staging(str, fn) \
+static int __init runtime_board_check(void) \
+{ \
+ if (of_machine_is_compatible(str)) \
+ fn(); \
+ \
+ return 0; \
+} \
+ \
+device_initcall(runtime_board_check)
+
+#endif /* __BOARD_H__ */
diff --git a/drivers/staging/board/kzm9d.c b/drivers/staging/board/kzm9d.c
new file mode 100644
index 0000000000..d449a83741
--- /dev/null
+++ b/drivers/staging/board/kzm9d.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Staging board support for KZM9D. Enable not-yet-DT-capable devices here. */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include "board.h"
+
+static struct resource usbs1_res[] __initdata = {
+ DEFINE_RES_MEM(0xe2800000, 0x2000),
+ DEFINE_RES_IRQ(159),
+};
+
+static void __init kzm9d_init(void)
+{
+ board_staging_gic_setup_xlate("arm,pl390", 32);
+
+ if (!board_staging_dt_node_available(usbs1_res,
+ ARRAY_SIZE(usbs1_res))) {
+ board_staging_gic_fixup_resources(usbs1_res,
+ ARRAY_SIZE(usbs1_res));
+ platform_device_register_simple("emxx_udc", -1, usbs1_res,
+ ARRAY_SIZE(usbs1_res));
+ }
+}
+
+board_staging("renesas,kzm9d", kzm9d_init);