Re: [PATCH 3/6] fbdev: Add n64rdp driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



在 2020/12/26 上午1:00, Lauri Kasanen 写道:
I'm aware of the drm-fbdev resolution, but CONFIG_DRM adds 100kb, which
is a complete blocker on a system with 8mb RAM.

Hi Lauri,

AFAIK it's impossible to have a new fbdev driver.
However you can workaround it by setup fb memory in platform code or even
bootloader and register a simplefb platform driver.

Thanks.

- Jiaxun


Signed-off-by: Lauri Kasanen <cand@xxxxxxx>
---
  arch/mips/n64/init.c         |  10 +++
  drivers/video/fbdev/Kconfig  |   9 ++
  drivers/video/fbdev/Makefile |   1 +
  drivers/video/fbdev/n64rdp.c | 190 +++++++++++++++++++++++++++++++++++++++++++
  4 files changed, 210 insertions(+)
  create mode 100644 drivers/video/fbdev/n64rdp.c

diff --git a/arch/mips/n64/init.c b/arch/mips/n64/init.c
index 6fb622d..635e9ef 100644
--- a/arch/mips/n64/init.c
+++ b/arch/mips/n64/init.c
@@ -8,6 +8,7 @@
  #include <linux/ioport.h>
  #include <linux/irq.h>
  #include <linux/memblock.h>
+#include <linux/platform_device.h>
  #include <linux/string.h>

  #include <asm/bootinfo.h>
@@ -46,6 +47,15 @@ void __init prom_free_prom_memory(void)
  {
  }

+static int __init n64_platform_init(void)
+{
+	platform_device_register_simple("n64rdp", -1, NULL, 0);
+
+	return 0;
+}
+
+arch_initcall(n64_platform_init);
+
  void __init plat_mem_setup(void)
  {
  	iomem_resource_init();
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index cfb7f56..4dde2c7 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2206,6 +2206,15 @@ config FB_SIMPLE
  	  Configuration re: surface address, size, and format must be provided
  	  through device tree, or plain old platform data.

+config FB_N64RDP
+	bool "Nintendo 64 RDP support"
+	depends on (FB = y) && MIPS_N64
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  Driver for the N64's display.
+
  config FB_SSD1307
  	tristate "Solomon SSD1307 framebuffer support"
  	depends on FB && I2C
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 477b962..86f1e22 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_FB_MX3)		  += mx3fb.o
  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
  obj-$(CONFIG_FB_SSD1307)	  += ssd1307fb.o
  obj-$(CONFIG_FB_SIMPLE)           += simplefb.o
+obj-$(CONFIG_FB_N64RDP)           += n64rdp.o

  # the test framebuffer is last
  obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff --git a/drivers/video/fbdev/n64rdp.c b/drivers/video/fbdev/n64rdp.c
new file mode 100644
index 0000000..e5456b6
--- /dev/null
+++ b/drivers/video/fbdev/n64rdp.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * DRM driver for the N64's RDP
+ *
+ * Copyright (c) 2020 Lauri Kasanen
+ *
+ * Based on simplefb.c, which was:
+ * Copyright (c) 2013, Stephen Warren
+ *
+ * Based on q40fb.c, which was:
+ * Copyright (C) 2001 Richard Zidlicky <rz@xxxxxxxxxxxxxx>
+ *
+ * Also based on offb.c, which was:
+ * Copyright (C) 1997 Geert Uytterhoeven
+ * Copyright (C) 1996 Paul Mackerras
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/parser.h>
+
+#include <asm/addrspace.h>
+
+static const struct fb_fix_screeninfo n64rdp_fix = {
+	.id		= "default",
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_TRUECOLOR,
+	.accel		= FB_ACCEL_NONE,
+};
+
+static const struct fb_var_screeninfo n64rdp_var = {
+	.height		= -1,
+	.width		= -1,
+	.activate	= FB_ACTIVATE_NOW,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+#define PSEUDO_PALETTE_SIZE 16
+
+static int n64rdp_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			      u_int transp, struct fb_info *info)
+{
+	u32 *pal = info->pseudo_palette;
+	u32 cr = red >> (16 - info->var.red.length);
+	u32 cg = green >> (16 - info->var.green.length);
+	u32 cb = blue >> (16 - info->var.blue.length);
+	u32 value;
+
+	if (regno >= PSEUDO_PALETTE_SIZE)
+		return -EINVAL;
+
+	value = (cr << info->var.red.offset) |
+		(cg << info->var.green.offset) |
+		(cb << info->var.blue.offset);
+	if (info->var.transp.length > 0) {
+		u32 mask = (1 << info->var.transp.length) - 1;
+		mask <<= info->var.transp.offset;
+		value |= mask;
+	}
+	pal[regno] = value;
+
+	return 0;
+}
+
+static const struct fb_ops n64rdp_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= n64rdp_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+struct n64rdp_par {
+	u32 palette[PSEUDO_PALETTE_SIZE];
+	dma_addr_t physaddr;
+};
+
+#define REG_BASE ((u32 *) CKSEG1ADDR(0xA4400000))
+
+static void n64rdp_write_reg(const u8 reg, const u32 value)
+{
+	__raw_writel(value, REG_BASE + reg);
+}
+
+#define W 320
+#define H 240
+
+static const u32 ntsc_320[] __initconst = {
+	0x00013212, 0x00000000, 0x00000140, 0x00000200,
+	0x00000000, 0x03e52239, 0x0000020d, 0x00000c15,
+	0x0c150c15, 0x006c02ec, 0x002501ff, 0x000e0204,
+	0x00000200, 0x00000400
+};
+
+static int __init n64rdp_probe(struct platform_device *pdev)
+{
+	int ret;
+	u32 i;
+	struct fb_info *info;
+	struct n64rdp_par *par;
+	dma_addr_t addr;
+
+	info = framebuffer_alloc(sizeof(struct n64rdp_par), &pdev->dev);
+	if (!info)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, info);
+
+	par = info->par;
+
+	info->fix = n64rdp_fix;
+	info->screen_base = dma_alloc_coherent(&pdev->dev, W * H * 2, &addr,
+					       GFP_DMA | GFP_KERNEL);
+	if (!info->screen_base)
+		return -ENOMEM;
+
+	info->fix.smem_start = par->physaddr = addr;
+	info->fix.smem_len = W * H * 2;
+	info->fix.line_length = W * 2;
+
+	info->var = n64rdp_var;
+	info->var.xres = W;
+	info->var.yres = H;
+	info->var.xres_virtual = W;
+	info->var.yres_virtual = H;
+	info->var.bits_per_pixel = 16;
+	info->var.red = (struct fb_bitfield) {11, 5};
+	info->var.green = (struct fb_bitfield) {6, 5};
+	info->var.blue = (struct fb_bitfield) {1, 5};
+	info->var.transp = (struct fb_bitfield) {0, 1};
+
+	info->apertures = alloc_apertures(1);
+	if (!info->apertures) {
+		ret = -ENOMEM;
+		goto error_fb_release;
+	}
+	info->apertures->ranges[0].base = info->fix.smem_start;
+	info->apertures->ranges[0].size = info->fix.smem_len;
+
+	info->fbops = &n64rdp_ops;
+	info->flags = FBINFO_DEFAULT;
+	info->pseudo_palette = par->palette;
+
+	dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
+			     info->fix.smem_start, info->fix.smem_len,
+			     info->screen_base);
+
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to register n64rdp: %d\n", ret);
+		goto error_fb_release;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ntsc_320); i++) {
+		if (i == 1)
+			n64rdp_write_reg(i, par->physaddr);
+		else
+			n64rdp_write_reg(i, ntsc_320[i]);
+	}
+
+	return 0;
+
+error_fb_release:
+	framebuffer_release(info);
+	return ret;
+}
+
+static struct platform_driver n64rdp_driver = {
+	.driver = {
+		.name = "n64rdp",
+	},
+};
+
+static int __init n64rdp_init(void)
+{
+	int ret;
+
+	ret = platform_driver_probe(&n64rdp_driver, n64rdp_probe);
+
+	return ret;
+}
+
+fs_initcall(n64rdp_init);
+
+MODULE_AUTHOR("Lauri Kasanen <cand@xxxxxxx>");
+MODULE_DESCRIPTION("Driver for the N64's display");
+MODULE_LICENSE("GPL v2");
--
2.6.2





[Index of Archives]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux