^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * 2011 (c) Aeroflex Gaisler AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Full documentation of the core can be found here:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * https://www.gaisler.com/products/grlib/grip.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct grvga_regs {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u32 status; /* 0x00 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u32 video_length; /* 0x04 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u32 front_porch; /* 0x08 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) u32 sync_length; /* 0x0C */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) u32 line_length; /* 0x10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) u32 fb_pos; /* 0x14 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) u32 clk_vector[4]; /* 0x18 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u32 clut; /* 0x20 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct grvga_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct grvga_regs *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) u32 color_palette[16]; /* 16 entry pseudo palette used by fbcon in true color mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int clk_sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int fb_alloced; /* = 1 if framebuffer is allocated in main memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static const struct fb_videomode grvga_modedb[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* 640x480 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) 0, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* 800x600 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) 0, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* 800x600 @ 72 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) 0, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* 1024x768 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) 0, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static const struct fb_fix_screeninfo grvga_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) .id = "AG SVGACTRL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) .visual = FB_VISUAL_PSEUDOCOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .xpanstep = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) .ypanstep = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) .ywrapstep = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) .accel = FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int grvga_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct grvga_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (!var->xres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) var->xres = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (!var->yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) var->yres = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (var->bits_per_pixel <= 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) var->bits_per_pixel = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) else if (var->bits_per_pixel <= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) else if (var->bits_per_pixel <= 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) var->bits_per_pixel = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) else if (var->bits_per_pixel <= 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) var->bits_per_pixel = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) var->xres_virtual = var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) var->yres_virtual = 2*var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (info->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* Which clocks that are available can be read out in these registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) for (i = 0; i <= 3 ; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (var->pixclock == par->regs->clk_vector[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (i <= 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) par->clk_sel = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) var->red = (struct fb_bitfield) {0, 8, 0}; /* offset, length, msb-right */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) var->green = (struct fb_bitfield) {0, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) var->blue = (struct fb_bitfield) {0, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) var->transp = (struct fb_bitfield) {0, 0, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) var->red = (struct fb_bitfield) {11, 5, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) var->green = (struct fb_bitfield) {5, 6, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) var->blue = (struct fb_bitfield) {0, 5, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) var->transp = (struct fb_bitfield) {0, 0, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) var->red = (struct fb_bitfield) {16, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) var->green = (struct fb_bitfield) {8, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) var->blue = (struct fb_bitfield) {0, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) var->transp = (struct fb_bitfield) {24, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int grvga_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) u32 func = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct grvga_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) __raw_writel(((info->var.yres - 1) << 16) | (info->var.xres - 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) &par->regs->video_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) __raw_writel((info->var.lower_margin << 16) | (info->var.right_margin),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) &par->regs->front_porch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) __raw_writel((info->var.vsync_len << 16) | (info->var.hsync_len),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) &par->regs->sync_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) __raw_writel(((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) &par->regs->line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) func = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) func = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) func = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) __raw_writel((par->clk_sel << 6) | (func << 4) | 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) &par->regs->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct grvga_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (regno >= 256) /* Size of CLUT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (info->var.grayscale) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /* grayscale = 0.30*R + 0.59*G + 0.11*B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) red = CNVT_TOHW(red, info->var.red.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) green = CNVT_TOHW(green, info->var.green.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) blue = CNVT_TOHW(blue, info->var.blue.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) transp = CNVT_TOHW(transp, info->var.transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) #undef CNVT_TOHW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /* In PSEUDOCOLOR we use the hardware CLUT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) __raw_writel((regno << 24) | (red << 16) | (green << 8) | blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) &par->regs->clut);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* Truecolor uses the pseudo palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) else if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (regno >= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) v = (red << info->var.red.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) (green << info->var.green.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) (blue << info->var.blue.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) (transp << info->var.transp.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) ((u32 *) (info->pseudo_palette))[regno] = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static int grvga_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) struct grvga_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) struct fb_fix_screeninfo *fix = &info->fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) u32 base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (var->xoffset != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) base_addr = fix->smem_start + (var->yoffset * fix->line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) base_addr &= ~3UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* Set framebuffer base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) __raw_writel(base_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) &par->regs->fb_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static const struct fb_ops grvga_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) .fb_check_var = grvga_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) .fb_set_par = grvga_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) .fb_setcolreg = grvga_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) .fb_pan_display = grvga_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) .fb_imageblit = cfb_imageblit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static int grvga_parse_custom(char *options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct fb_var_screeninfo *screendata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) char *this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) while ((this_opt = strsep(&options, " ")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (!*this_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) switch (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) screendata->pixclock = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) screendata->right_margin = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) screendata->hsync_len = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) screendata->left_margin = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) screendata->lower_margin = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) case 7:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) screendata->vsync_len = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) screendata->upper_margin = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) case 9:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) screendata->activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) screendata->vmode = FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static int grvga_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) int retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) unsigned long virtual_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) unsigned long grvga_fix_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) unsigned long physical_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) unsigned long grvga_mem_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) struct grvga_par *par = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) char *options = NULL, *mode_opt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) * If address is left out, we allocate memory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * if size is left out we only allocate enough to support the given mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (fb_get_options("grvga", &options)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) options = "640x480-8@60";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) char *this_opt = strsep(&options, ",");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (!this_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (!strncmp(this_opt, "custom", 6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (grvga_parse_custom(this_opt, &info->var) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) } else if (!strncmp(this_opt, "addr", 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) else if (!strncmp(this_opt, "size", 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) mode_opt = this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) info->fbops = &grvga_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) info->fix = grvga_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) info->pseudo_palette = par->color_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) info->fix.smem_len = grvga_mem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (!devm_request_mem_region(&dev->dev, dev->resource[0].start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) resource_size(&dev->resource[0]), "grlib-svgactrl regs")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) dev_err(&dev->dev, "registers already mapped\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) retval = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) par->regs = of_ioremap(&dev->resource[0], 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) resource_size(&dev->resource[0]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) "grlib-svgactrl regs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (!par->regs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) dev_err(&dev->dev, "failed to map registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) retval = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) goto unmap_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (mode_opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) retval = fb_find_mode(&info->var, info, mode_opt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (!retval || retval == 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) goto dealloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (!grvga_mem_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (grvga_fix_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) /* Got framebuffer base address from argument list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) physical_start = grvga_fix_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (!devm_request_mem_region(&dev->dev, physical_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) grvga_mem_size, dev->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) dev_err(&dev->dev, "failed to request memory region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) goto dealloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (!virtual_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) dev_err(&dev->dev, "error mapping framebuffer memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) goto dealloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) } else { /* Allocate frambuffer memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) unsigned long page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) virtual_start = (unsigned long) __get_free_pages(GFP_DMA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) get_order(grvga_mem_size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (!virtual_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) dev_err(&dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) "unable to allocate framebuffer memory (%lu bytes)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) grvga_mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) goto dealloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) /* Set page reserved so that mmap will work. This is necessary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) * since we'll be remapping normal memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) for (page = virtual_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) page < PAGE_ALIGN(virtual_start + grvga_mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) page += PAGE_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) SetPageReserved(virt_to_page(page));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) par->fb_alloced = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) memset((unsigned long *) virtual_start, 0, grvga_mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) info->screen_base = (char __iomem *) virtual_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) info->fix.smem_start = physical_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) info->fix.smem_len = grvga_mem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) dev_set_drvdata(&dev->dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) dev_info(&dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) grvga_mem_size >> 10, info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) retval = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) dev_err(&dev->dev, "failed to register framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) goto free_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) __raw_writel(physical_start, &par->regs->fb_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) __raw_writel(__raw_readl(&par->regs->status) | 1, /* Enable framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) &par->regs->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) free_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (grvga_fix_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) iounmap((void *)virtual_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) kfree((void *)virtual_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) dealloc_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) unmap_regs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) of_iounmap(&dev->resource[0], par->regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) resource_size(&dev->resource[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) free_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static int grvga_remove(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) struct fb_info *info = dev_get_drvdata(&device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct grvga_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) of_iounmap(&device->resource[0], par->regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) resource_size(&device->resource[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) if (!par->fb_alloced)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) iounmap(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) kfree((void *)info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static struct of_device_id svgactrl_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) .name = "GAISLER_SVGACTRL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) .name = "01_063",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) MODULE_DEVICE_TABLE(of, svgactrl_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) static struct platform_driver grvga_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) .name = "grlib-svgactrl",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) .of_match_table = svgactrl_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) .probe = grvga_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) .remove = grvga_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) module_platform_driver(grvga_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) MODULE_AUTHOR("Aeroflex Gaisler");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");