diff for duplicates of <502DEDCD.9050303@gmail.com> diff --git a/a/1.txt b/N1/1.txt index dd6d0e4..4489532 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -12,7 +12,14 @@ I have written a driver for kernel 2.6.22 but SLCDC and DD12832 are in the same driver. Thank you for your help. -Gaëtan Carlier +Ga?tan Carlier ps : I attach my previous driver for a better overview (this is a working draft for test purpose) +-------------- next part -------------- +A non-text attachment was scrubbed... +Name: mx2fb-slcd_dd12832_oled.c +Type: text/x-csrc +Size: 35409 bytes +Desc: not available +URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120817/ea3df386/attachment-0001.bin> diff --git a/a/2.hdr b/a/2.hdr deleted file mode 100644 index b1ac541..0000000 --- a/a/2.hdr +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type: text/x-csrc; - name="mx2fb-slcd_dd12832_oled.c" -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; - filename="mx2fb-slcd_dd12832_oled.c" diff --git a/a/2.txt b/a/2.txt deleted file mode 100644 index d6f04d1..0000000 --- a/a/2.txt +++ /dev/null @@ -1,1319 +0,0 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - */ - -/* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -/*! - * @defgroup Framebuffer_MX27 Framebuffer Driver for MX27. - */ - -/*! - * @file mx2fb.c - * - * @brief Frame buffer driver for MX27 ADS. - * - * @ingroup Framebuffer_MX27 - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/dmapool.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <asm/uaccess.h> -#include <asm/arch/mxcfb.h> -#include <asm/arch/mx2fb_slcdc.h> - -#include <asm/arch/pmic_power.h> -#include "dd12832_oled.h" - -#ifdef CONFIG_PM -static int mx2fb_suspend(struct platform_device *pdev, pm_message_t state); -static int mx2fb_resume(struct platform_device *pdev); -#else -#define mx2fb_suspend 0 -#define mx2fb_resume 0 -#endif - -#define MX2FB_TYPE_BG 0 -#define MX2FB_TYPE_GW 1 - -#define floor8(a) (a&(~0x07)) -//#define iceil8(a) (((int)((a+7)/8))*8) -#define iceil8(a) ((int)((a & ~((int)0x03)) + 8)) - - - -extern void gpio_slcdc_active(void); -extern void gpio_slcdc_inactive(void); - -static char *fb_mode; -static int fb_enabled; -static unsigned long default_bpp = 1; -static unsigned char brightness = 255; -static ATOMIC_NOTIFIER_HEAD(mx2fb_notifier_list); -static struct clk *slcdc_clk; -/*! - * @brief Structure containing the MX2 specific framebuffer parameters. - */ -struct mx2fb_par { - int type; - char *id; - int registered; - int blank; - /* Tell if driver compiled with rotate option enabled */ - int rotate; - /* Contains displayed data in 1 byte / column (8 pixels) - * fb data are stored as 1 byte / pixel - * !! must be allocated with 128k alignment using dma_pool_create - */ - /* FrameBuffer memory map */ - unsigned char* fb_vmem; - size_t fb_len; - dma_addr_t fb_pmem; - /* Oled cgram memory map */ - unsigned long cgram_cmd_vaddr; - unsigned long cgram_cmd_paddr; - unsigned long cgram_cmd_len; - struct dma_pool *cgram_cmd_dma_pool; - unsigned long cgram_data_vaddr; - unsigned long cgram_data_paddr; - unsigned long cgram_data_len; - struct dma_pool *cgram_data_dma_pool; -}; - -/* Framebuffer APIs */ -/*static int mx2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); -static int mx2fb_set_par(struct fb_info *info); -static void _set_fix(struct fb_info *info);*/ - -/* Internal functions */ -static int __init _init_fbinfo(struct fb_info *info, - struct platform_device *pdev); -static int __init _install_fb(struct fb_info *info, - struct platform_device *pdev); -static void __exit _uninstall_fb(struct fb_info *info); -static int _map_video_memory(struct fb_info *info); -static void _unmap_video_memory(struct fb_info *info); -/*static void _enable_lcdc(struct fb_info *info); -static void _disable_lcdc(struct fb_info *info); -static void _update_slcdc(struct fb_info *info);*/ - -/* Oled display information */ -struct fb_videomode mxcfb_modedb[] = { - { - /* 128x32 */ - "Densitron DD12832", /* name */ - 0, /* refresh */ - 128, /* xres */ - 32, /* yres */ - 0, /* pixclock */ - 0, /* left_margin */ - 0, /* right_margin */ - 0, /* upper_margin */ - 0, /* lower_margin */ - 0, /* hsync_len */ - 0, /* vsync_len */ - 0, /* sync */ - 0, /* mode */ - 0}, /* flag */ -}; -int mxcfb_modedb_sz = ARRAY_SIZE(mxcfb_modedb); - -struct mx2fb_par mx2fbp_bg = { - .type = MX2FB_TYPE_BG, - .id = "DISP0 BG", - .registered = 0, -#ifdef CONFIG_FB_MXC_DENSITRON_DD12832_ROTATE - .rotate = 1, -#else - .rotate = 0, -#endif -}; - -/*! - * @brief Framebuffer information structures. - * There are up to 3 framebuffers: background, TVout, and graphic window. - * If graphic window is configured, it must be the last framebuffer. - */ -static struct fb_info mx2fb_info = { - .par = &mx2fbp_bg, -}; - -/*! - * Do a minimal setup of SLCDC to be able to send command to DD12832 - */ -static void slcdc_first_init(void) -{ - unsigned long val; - int i; - unsigned long *pdata; - - /* Screen start address register */ - __raw_writel(mx2fbp_bg.cgram_data_paddr, SLCDC_REG(SLCDC_DATABASEADDR)); - __raw_writel(mx2fbp_bg.cgram_data_len, SLCDC_REG(SLCDC_DATABUFSIZE)); - - /* Copy command array to DMA area */ - pdata = (unsigned long *)mx2fbp_bg.cgram_cmd_vaddr; - for (i = 0; i < mx2fbp_bg.cgram_cmd_len; i++) { - if ((i & 0x01) == 0) { - /* If even offset, command must be left-aligned in - * 32-bits memory space */ - *pdata = (unsigned long)_ssd1305_pagecmd_array[i] << 16; - } else { - /* If odd offset, command must be right-aligned in - * 32-bits memory space */ - *pdata |= (unsigned long)_ssd1305_pagecmd_array[i]; - /* When "right column" is filled, go to next address */ - pdata++; - } - } - /* Set Array of command for page addressing */ - __raw_writel(mx2fbp_bg.cgram_cmd_paddr, SLCDC_REG(SLCDC_COMBASEADDR)); - __raw_writel(mx2fbp_bg.cgram_cmd_len, SLCDC_REG(SLCDC_COMBUFSIZE)); - - /* Set number of command (words) that must be send to jump to a - * specific page. Size of "word" is define by WORDDEFCOM flag in - * LCDTRANSCONFIG register */ - __raw_writel(PAGE_COMMAND_PACK_SIZE, SLCDC_REG(SLCDC_COMSTRINGSIZ)); - - /* Define DMA burst */ - __raw_writel(0, SLCDC_REG(SLCDC_FIFOCONFIG)); - - /* Define number of column/segment in a page */ - __raw_writel(OLED_WIDTH, SLCDC_REG(SLCDC_LCDCONFIG)); - - /* Set transfer configuration */ - val = SLCDC_DATA_8BIT | SLCDC_COMMAND_8BIT | SLCDC_PARALLEL | - SLCDC_WRITEDATA_8BIT | SLCDC_TRANS_LITLENDIAN_8BIT | - SLCDC_CSPOL_LOW; - __raw_writel(val, SLCDC_REG(SLCDC_LCDTRANSCONFIG)); - - /* Set control register */ - val = SLCDC_MODE_COMMAND | SLCDC_IRQ_DISABLE | SLCDC_IRQ_FLAGS_MASK; - __raw_writel(val, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - - /* Set SLCDC clock divider = HCLK_SLCDC * val / 128 */ - val = 40; - __raw_writel(val, SLCDC_REG(SLCDC_LCDCLOCKCONFIG)); -} - - -/* - * Send one command to oled via SLCDC - */ -static int _slcdc_sendcmd_single(unsigned char cmd) -{ - while (__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)) & SLCDC_BUSY_MASK); - __raw_writel((u32)cmd | WRITE_LCDCMD, SLCDC_REG(SLCDC_LCDWRITEDATA)); - return 0; -} - -/* - * Send one data to oled via SLCDC - */ -static int _slcdc_senddata_single(unsigned char cmd) -{ - while (__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)) & SLCDC_BUSY_MASK); - __raw_writel((u32)cmd | WRITE_LCDDATA, SLCDC_REG(SLCDC_LCDWRITEDATA)); - return 0; -} - -/* - * Set Start line for Pan function - */ -static void dd12832_set_start_line(unsigned char y) -{ - _slcdc_sendcmd_single(SSD1305_CMD_ROWADDR | (y & 0x3F)); -} - -/* - * Set page address - */ -static void dd12832_set_yaddr(unsigned char y) -{ - _slcdc_sendcmd_single(SSD1305_CMD_PAGEADDR | (y & 0x07)); -} - -/* - * Set segment address - */ -static void dd12832_set_xaddr(unsigned char x) -{ -#ifndef CONFIG_FB_MXC_DENSITRON_DD12832_ROTATE - _slcdc_sendcmd_single(SSD1305_CMD_HIGHCOLADDR | (x >> 4)); - _slcdc_sendcmd_single(SSD1305_CMD_LOWCOLADDR | (x & 0x0F)); -#else - x += SSD1305_WIDTH - OLED_WIDTH; - _slcdc_sendcmd_single(SSD1305_CMD_HIGHCOLADDR | (x >> 4)); - _slcdc_sendcmd_single(SSD1305_CMD_LOWCOLADDR | (x & 0x0F)); -#endif -} - -/* - * Modify contrast value - */ -static void dd12832_set_brightness(unsigned char level) -{ - if (level == 0) { - /* If level 0 asked, display must be turned off - * because Display is still ON when Contrast - * is set to 0 */ - _slcdc_sendcmd_single(SSD1305_CMD_DISPLAY_POWER_OFF); - } else { - /* Apply new contrast */ - _slcdc_sendcmd_single(SSD1305_CMD_BRIGHTNESS_MODE); - _slcdc_sendcmd_single(level); - /* Be sure that DISPLAY is ON */ - _slcdc_sendcmd_single(SSD1305_CMD_DISPLAY_POWER_ON); - } -} - -/* - * Clear internal RAM of controller - */ -static void dd12832_clear_lcd(void) -{ - unsigned long status; - /* Clear OLED RAM mirror buffer */ - char *pdata = (char *)mx2fbp_bg.cgram_data_vaddr; - memset(pdata, 0, mx2fbp_bg.cgram_data_len); - - /* Clear FrameBuffer mirror buffer */ - pdata = (char __force *) mx2fbp_bg.fb_vmem; - memset(pdata, 0, mx2fbp_bg.fb_len); - - dd12832_set_yaddr(0); - dd12832_set_xaddr(0); - while (__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)) & SLCDC_BUSY_MASK); - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status &= ~(SLCDC_SLCDCCTRLSTAT_AUTOMODE_MASK); - status |= SLCDC_MODE_DATA | SLCDC_START_TRANSFERT; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); -} - -/* - * Send init sequence to display controller - */ -static int dd12832_init_controller(void) -{ - /* Use SLCDC to send command block */ - unsigned long i; - - for (i = 0; i < sizeof(_ssd1305_init_array); i++) { - _slcdc_sendcmd_single(_ssd1305_init_array[i]); - } - dd12832_clear_lcd(); - return 0; -} - -/*! - * @brief Enable LCD controller. - * @param info framebuffer information pointer - */ -static void _enable_slcdc(struct fb_info *info) -{ - if (!fb_enabled) { - fb_enabled++; - - if (fb_mode) { - unsigned long mode = 0; - if (mode == 0) { - dd12832_set_brightness(brightness); - } - } - } -} - -/*! - * @brief Disable LCD controller. - * @param info framebuffer information pointer - */ -static void _disable_slcdc(struct fb_info *info) -{ - if (fb_enabled) { - dd12832_set_brightness(0); - fb_enabled = 0; - } -} - -/*! - * @brief Update SLCDC registers - * @param info framebuffer information pointer - */ -static void _update_slcdc(struct fb_info *info) -{ - unsigned long base; - unsigned long val; - struct fb_var_screeninfo *var = &info->var; - - base = (var->yoffset * var->xres_virtual + var->xoffset); - base += (unsigned long)info->screen_base; - - /* Set number of command (words) that must be send to jump to a - * specific page. Size of "word" is define by WORDDEFCOM flag in - * LCDTRANSCONFIG register */ - __raw_writel(PAGE_COMMAND_PACK_SIZE, SLCDC_REG(SLCDC_COMSTRINGSIZ)); - - /* Define DMA burst */ - __raw_writel(0, SLCDC_REG(SLCDC_FIFOCONFIG)); - - /* Define number of column/segment in a page */ - __raw_writel(OLED_WIDTH, SLCDC_REG(SLCDC_LCDCONFIG)); - - /* Set transfer configuration */ - val = SLCDC_DATA_8BIT | SLCDC_COMMAND_8BIT | SLCDC_PARALLEL | - SLCDC_WRITEDATA_8BIT | SLCDC_TRANS_LITLENDIAN_8BIT | - SLCDC_CSPOL_LOW; - __raw_writel(val, SLCDC_REG(SLCDC_LCDTRANSCONFIG)); - - /* Set SLCDC clock divider = HCLK_SLCDC * val / 128 */ - val = 60; - __raw_writel(val, SLCDC_REG(SLCDC_LCDCLOCKCONFIG)); - - return; -} - - -/*! - * @brief Blanks the display. - * - * @param blank_mode The blank mode we want. - * @param info Frame buffer structure that represents a single frame buffer - * - * @return Negative errno on error, or zero on success. - * - * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking - * succeeded, != 0 if un-/blanking failed. - * blank_mode == 2: suspend vsync - * blank_mode == 3: suspend hsync - * blank_mode == 4: powerdown - */ -static int mx2fb_blank(int blank_mode, struct fb_info *info) -{ - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - - dev_dbg(info->device, "blank mode = %d\n", blank_mode); - - mx2fbp->blank = blank_mode; - - switch (blank_mode) { - case FB_BLANK_POWERDOWN: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_NORMAL: - _disable_slcdc(info); - break; - case FB_BLANK_UNBLANK: - _enable_slcdc(info); - break; - } - - return 0; -} - -/* - * here we start the process of spliting out the fb update into - * individual blocks of pixels. we end up spliting into 64x64 blocks - * and finally down to 64x8 pages. - */ -static void dd12832_cgram_update(struct fb_info *info, unsigned int dx, - unsigned int dy, unsigned int w, unsigned int h) -{ - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - unsigned int startpage, endpage, startseg, endseg; - unsigned int curpage, curseg; - unsigned long status; - int i; - unsigned char myseg; - char *cgram; - unsigned char *ppixel; - - /* align the request first */ - /* Get first line of the page where starting pixel is located */ - startpage = floor8(dy) / 8; - /* Get first line of the next page where last pixel to update - * is located */ - endpage = h + dy - 1; - endpage = iceil8(endpage) / 8; - - /* First segment to update */ - startseg = dx; - /* Last segment to update */ - endseg = dx + (w - 1); - - for (curpage = startpage; curpage < endpage; curpage++) { - cgram = (char*)mx2fbp->cgram_data_vaddr; - cgram += curpage * info->fix.line_length; - cgram += startseg; - for (curseg = startseg; curseg <= endseg; curseg++) { - /* Get segment to update in video memory */ - myseg = 0; - ppixel = (unsigned char __force *) mx2fbp->fb_vmem; - /* There is 8 lines per page */ - ppixel += curpage * info->fix.line_length * 8; - /* Points to upper pixel of the current segment */ - ppixel += curseg; - for (i = 0; i < 8; i++) { - if (*ppixel != 0) { - myseg |= 1 << i; - } - /* Jump to next line to get pixel below */ - ppixel += info->fix.line_length; - } - *cgram = myseg; - cgram++; - } - } - dd12832_set_xaddr(0); - dd12832_set_yaddr(0); - while (__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)) & SLCDC_BUSY_MASK); - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status &= ~(SLCDC_SLCDCCTRLSTAT_AUTOMODE_MASK); - status |= SLCDC_MODE_DATA | SLCDC_START_TRANSFERT; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); -} - - - -static void mx2fb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - sys_fillrect(info, rect); - - /* update the physical lcd */ - dd12832_cgram_update(info, rect->dx, rect->dy, rect->width, rect->height); -} - -static void mx2fb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - sys_copyarea(info, area); - - /* update the physical lcd */ - dd12832_cgram_update(info, area->dx, area->dy, area->width, area->height); -} - -static void mx2fb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - char *ppixel; - const char *pdata; - int j; - - if (image->depth == 1) { - /* Draw image */ - pdata = image->data; - ppixel = mx2fbp->fb_vmem; - ppixel += image->dy * info->fix.line_length; - ppixel += image->dx; - for (j = 0; j < image->height; j++) { - memcpy(ppixel, pdata, image->width); - pdata += image->width; - ppixel += info->fix.line_length; - } - /* update the physical lcd */ - dd12832_cgram_update(info, image->dx, image->dy, image->width, image->height); - } -} - - -/*! - * @brief Pans the display. - * - * @param var Frame buffer variable screen structure - * @param info Frame buffer structure that represents a single frame buffer - * - * @return Negative errno on error, or zero on success. - * - * Pan (or wrap, depending on the `vmode' field) the display using the - * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values - * don't fit, return -EINVAL. - */ -static int mx2fb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - if (info->var.yoffset == var->yoffset) { - return 0; /* No change, do nothing */ - } - - if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < OLED_WIDTH) - && (info->var.yres <= OLED_WIDTH)) { - dd12832_set_start_line(var->yoffset); - info->var.yoffset = var->yoffset; - return 0; - } - - return -EINVAL; -} - -static int mx2fb_sync(struct fb_info *info) -{ - dd12832_cgram_update(info, 0, 0, info->fix.line_length, info->var.yres_virtual); - return 0; -} - -/*! - * @brief Ioctl function to support customized ioctl operations. - * - * @param info Framebuffer structure that represents a single frame buffer - * @param cmd The command number - * @param arg Argument which depends on cmd - * - * @return Negative errno on error, or zero on success. - */ -static int mx2fb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) -{ - unsigned char level; - - switch (cmd) { - case MX2FB_SET_BRIGHTNESS: - if (copy_from_user((void *)&level, (void *)arg, sizeof(level))) - return -EFAULT; - brightness = level; - dd12832_set_brightness(level); - break; - case MX2FB_FORCE_SYNC: - mx2fb_sync(info); - break; - default: - dev_dbg(info->device, "Unknown ioctl command (0x%08X)\n", cmd); - return -EINVAL; - } - - return 0; -} - -/*! - * @brief Set fixed framebuffer parameters based on variable settings. - * - * @param info framebuffer information pointer - * @return Negative errno on error, or zero on success. - */ -static void _set_fix(struct fb_info *info) -{ - struct fb_fix_screeninfo *fix = &info->fix; - struct fb_var_screeninfo *var = &info->var; - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - - strncpy(fix->id, mx2fbp->id, strlen(mx2fbp->id)); - if (var->bits_per_pixel < 8) - fix->line_length = var->xres_virtual; - else - fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->accel = FB_ACCEL_NONE; - fix->visual = FB_VISUAL_MONO10; - fix->xpanstep = 0; - fix->ypanstep = 1; - fix->ywrapstep = 0; -} - -/*! - * @brief Validates a var passed in. - * - * @param var Frame buffer variable screen structure - * @param info Frame buffer structure that represents a single frame buffer - * - * @return Negative errno on error, or zero on success. - * - * Checks to see if the hardware supports the state requested by var passed - * in. This function does not alter the hardware state! If the var passed in - * is slightly off by what the hardware can support then we alter the var - * PASSED in to what we can do. If the hardware doesn't support mode change - * a -EINVAL will be returned by the upper layers. - * - */ -static int mx2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; - - if (var->xoffset < 0) - var->xoffset = 0; - - if (var->yoffset < 0) - var->yoffset = 0; - - if (var->xoffset + info->var.xres > info->var.xres_virtual) - var->xoffset = info->var.xres_virtual - info->var.xres; - - if (var->yoffset + info->var.yres > info->var.yres_virtual) - var->yoffset = info->var.yres_virtual - info->var.yres; - - if (var->bits_per_pixel != default_bpp) - var->bits_per_pixel = default_bpp; - - if (var->pixclock != 0) - var->pixclock = 0; - var->red.length = var->green.length = var->blue.length = 1; - var->red.offset = var->green.offset = var->blue.offset = 0; - var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; - - var->transp.length = 0; - var->transp.offset = 0; - var->transp.msb_right = 0; - - var->height = -1; - var->width = -1; - var->grayscale = 0; - - /* Copy nonstd field to/from sync for fbset usage */ - var->sync |= var->nonstd; - var->nonstd |= var->sync; - - return 0; -} - -/*! - * @brief Alters the hardware state. - * - * @param info Frame buffer structure that represents a single frame buffer - * - * @return Zero on success others on failure - * - * Using the fb_var_screeninfo in fb_info we set the resolution of this - * particular framebuffer. This function alters the fb_fix_screeninfo stored - * in fb_info. It doesn't not alter var in fb_info since we are using that - * data. This means we depend on the data in var inside fb_info to be - * supported by the hardware. mx2fb_check_var is always called before - * mx2fb_set_par to ensure this. - */ -static int mx2fb_set_par(struct fb_info *info) -{ - unsigned long len; - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - - _set_fix(info); - - len = info->var.yres_virtual * info->fix.line_length; - if (len > info->fix.smem_len) { - if (info->fix.smem_start) - _unmap_video_memory(info); - - /* Memory allocation for framebuffer */ - if (_map_video_memory(info)) { - dev_err(info->device, "Unable to allocate fb memory\n"); - return -ENOMEM; - } - } - - _update_slcdc(info); - - mx2fb_blank(mx2fbp->blank, info); - - return 0; -} - -/* - * this is the access path from userspace. they can seek and write to - * the fb. it's inefficient for them to do anything less than 64*8 - * writes since we update the lcd in each write() anyway. - */ -static ssize_t mx2fb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - /* modded from epson 1355 */ - - unsigned long p; - int err=-EINVAL; - unsigned int fbmemlength, x, y, w, h, startpage, endpage; - struct arcfb_par *par; - unsigned int xres; - - p = *ppos; - par = info->par; - xres = info->var.xres; - fbmemlength = info->fix.smem_len; - - if (p > fbmemlength) - return -ENOSPC; - - err = 0; - if ((count + p) > fbmemlength) { - count = fbmemlength - p; - err = -ENOSPC; - } - - if (count) { - char *base_addr; - - base_addr = (char __force *)info->screen_base; - count -= copy_from_user(base_addr + p, buf, count); - *ppos += count; - err = -EFAULT; - } - - /* Check how many page are affected */ - startpage = floor8(p) / 8; - endpage = iceil8((p + count)) / 8; - x = p % info->fix.line_length; - y = p / info->fix.line_length; - w = count % info->fix.line_length; - h = count / info->fix.line_length; - if (startpage != (endpage - 1)) { - /* If several page affected, update complete line - * of all affected pages */ - dd12832_cgram_update(info, 0, y, info->fix.line_length, h); - } else { - /* One page has been affected, only updates modified segment - */ - dd12832_cgram_update(info, x, y, w, h); - } - if (p+count > info->fix.line_length) { - /* Several line must be updated */ - } - if (count) - return count; - return err; -} - -/* fb_mmap - * Map video memory in user space. We don't use the generic fb_mmap method - * mainly - * to allow the use of the TLB streaming flag (CCA=6) - */ -int mx2fb_mmap(struct fb_info *info /*fbi*/, struct vm_area_struct *vma) -{ - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - unsigned int len; - unsigned long start=0, off; - - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { - return -EINVAL; - } - - start = mx2fbp->fb_pmem & PAGE_MASK; - len = PAGE_ALIGN((start & ~PAGE_MASK) + mx2fbp->fb_len); - - off = vma->vm_pgoff << PAGE_SHIFT; - - if ((vma->vm_end - vma->vm_start + off) > len) { - return -EINVAL; - } - - off += start; - vma->vm_pgoff = off >> PAGE_SHIFT; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - pgprot_val(vma->vm_page_prot) |= (6 << 9); - - vma->vm_flags |= VM_IO; - - if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) { - return -EAGAIN; - } - return 0; -} - - -/*! - * @brief Framebuffer file operations - */ -static struct fb_ops mx2fb_ops = { - .owner = THIS_MODULE, - //.fb_read = fb_sys_read, - .fb_write = mx2fb_write, - .fb_check_var = mx2fb_check_var, - .fb_set_par = mx2fb_set_par, - .fb_blank = mx2fb_blank, - .fb_pan_display = mx2fb_pan_display, - .fb_fillrect = mx2fb_fillrect, - .fb_copyarea = mx2fb_copyarea, - .fb_imageblit = mx2fb_imageblit, - .fb_ioctl = mx2fb_ioctl, - .fb_sync = mx2fb_sync, - .fb_mmap = mx2fb_mmap, -}; - -/*! - * @brief Initialize framebuffer information structure. - * - * @param info framebuffer information pointer - * @param pdev pointer to struct device - * @return Negative errno on error, or zero on success. - */ -static int __init _init_fbinfo(struct fb_info *info, - struct platform_device *pdev) -{ - info->device = &pdev->dev; - info->var.activate = FB_ACTIVATE_NOW; - info->fbops = &mx2fb_ops; - info->flags = FBINFO_FLAG_DEFAULT; - info->pseudo_palette = NULL; - - return 0; -} - -/*! - * @brief Install framebuffer into the system. - * - * @param info framebuffer information pointer - * @param pdev pointer to struct device - * @return Negative errno on error, or zero on success. - */ -static int __init _install_fb(struct fb_info *info, - struct platform_device *pdev) -{ - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - - if (_init_fbinfo(info, pdev)) - return -EINVAL; - - if (fb_mode == 0) - fb_mode = pdev->dev.platform_data; - - if (!fb_find_mode(&info->var, info, fb_mode, mxcfb_modedb, - mxcfb_modedb_sz, NULL, default_bpp)) { - return -EBUSY; - } - - /* Default Y virtual size is 2x panel size */ - /* info->var.yres_virtual = info->var.yres << 1; */ - - if (mx2fbp->type == MX2FB_TYPE_GW) - mx2fbp->blank = FB_BLANK_NORMAL; - else - mx2fbp->blank = FB_BLANK_UNBLANK; - - if (mx2fb_set_par(info)) { - return -EINVAL; - } - - if (register_framebuffer(info) < 0) { - _unmap_video_memory(info); - return -EINVAL; - } - - mx2fbp->registered = 1; - - dev_info(info->device, "fb%d registered successfully on %s (rotate = %d).\n", - info->node, fb_mode, mx2fbp->rotate); - return 0; -} - -/*! - * @brief Uninstall framebuffer from the system. - * - * @param info framebuffer information pointer - */ -static void __exit _uninstall_fb(struct fb_info *info) -{ - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - - if (!mx2fbp->registered) - return; - - unregister_framebuffer(info); - _unmap_video_memory(info); - if (&info->cmap) - fb_dealloc_cmap(&info->cmap); - - mx2fbp->registered = 0; -} - -/*! - * @brief Allocate memory for framebuffer. - * - * @param info framebuffer information pointer - * @return Negative errno on error, or zero on success. - */ -static int _map_video_memory(struct fb_info *info) -{ - unsigned long page; - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - mx2fbp->fb_len = info->fix.line_length * info->var.yres_virtual; - - mx2fbp->fb_vmem = dma_alloc_coherent(info->device, PAGE_ALIGN(mx2fbp->fb_len), - &mx2fbp->fb_pmem, GFP_KERNEL); - if (mx2fbp->fb_vmem == 0) { - dev_err(info->device, "fail to allocate frambuffer (size: %dK))", - mx2fbp->fb_len / 1024); - return -ENOMEM; - } - - info->screen_base = mx2fbp->fb_vmem; - info->fix.smem_start = mx2fbp->fb_pmem; - info->fix.smem_len = mx2fbp->fb_len; - - dev_dbg(info->device, "Allocated fb @ paddr=0x%08lX, size=%d.\n", - info->fix.smem_start, info->fix.smem_len); - - info->screen_size = info->fix.smem_len; - - /* Clear the screen */ - memset((char *)mx2fbp->fb_vmem, 0x00, mx2fbp->fb_len); - - /* - * Set page reserved so that mmap will work. This is necessary - * since we'll be remapping normal memory. - */ - for (page = (unsigned long)mx2fbp->fb_vmem; - page < PAGE_ALIGN((unsigned long)mx2fbp->fb_vmem + mx2fbp->fb_len); - page += PAGE_SIZE) { -#ifdef CONFIG_DMA_NONCOHERENT - SetPageReserved(virt_to_page(CAC_ADDR(page))); -#else - SetPageReserved(virt_to_page(page)); -#endif - } - - return 0; -} - -/*! - * @brief Release memory for framebuffer. - * @param info framebuffer information pointer - */ -static void _unmap_video_memory(struct fb_info *info) -{ - struct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par; - if (mx2fbp->fb_vmem) { - dma_free_noncoherent(info->device, mx2fbp->fb_len, mx2fbp->fb_vmem, mx2fbp->fb_pmem); - } - mx2fbp->fb_len = 0; - mx2fbp->fb_pmem = 0; - mx2fbp->fb_vmem = 0; - info->screen_base = 0; - info->fix.smem_start = 0; - info->fix.smem_len = 0; - /* Free DMA of SLCDC transfert */ - dma_pool_free(mx2fbp->cgram_data_dma_pool, (void *)mx2fbp->cgram_data_vaddr, (dma_addr_t) mx2fbp->cgram_data_paddr); - dma_pool_destroy(mx2fbp->cgram_data_dma_pool); - mx2fbp->cgram_data_dma_pool = 0; - mx2fbp->cgram_data_vaddr = 0; - mx2fbp->cgram_data_paddr = 0; - mx2fbp->cgram_data_len = 0; - /* Free DMA of SLCDC transfert */ - dma_pool_free(mx2fbp->cgram_cmd_dma_pool, (void *)mx2fbp->cgram_cmd_vaddr, (dma_addr_t) mx2fbp->cgram_cmd_paddr); - dma_pool_destroy(mx2fbp->cgram_cmd_dma_pool); - mx2fbp->cgram_cmd_dma_pool = 0; - mx2fbp->cgram_cmd_vaddr = 0; - mx2fbp->cgram_cmd_paddr = 0; - mx2fbp->cgram_cmd_len = 0; -} - -/* - * @brief LCDC interrupt handler - */ -static irqreturn_t mx2fb_isr(int irq, void *dev_id) -{ - struct fb_event event; - unsigned long status; - - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status &= SLCDC_IRQ_FLAGS_MASK; - - if (status & SLCDC_IRQ_FLAG) { - printk("Oled xfer done : "); - if (status == SLCDC_IRQ_FLAG) { - printk("Successful\n"); - } - if (status & SLCDC_IRQ_TEA_FLAG) { - printk("DMA error\n"); - event.info = &mx2fb_info; - atomic_notifier_call_chain(&mx2fb_notifier_list, - FB_EVENT_MXC_DMA_ERROR, &event); - } - if (status & SLCDC_IRQ_UNDRFLOW_FLAG) { - printk("Underflow occurs\n"); - event.info = &mx2fb_info; - atomic_notifier_call_chain(&mx2fb_notifier_list, - FB_EVENT_MXC_UNDERFLOW, &event); - } - } - - /* Write 1 to clear the status */ - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status |= SLCDC_IRQ_FLAGS_MASK; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - - return IRQ_HANDLED; -} - -/*! - * @brief Config and request LCDC interrupt - */ -static void _request_irq(void) -{ - unsigned long status; - unsigned long flags; - - /* Write 1 to clear the status */ - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status |= SLCDC_IRQ_FLAGS_MASK; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - - if (request_irq(INT_SLCDC, mx2fb_isr, 0, "SLCDC", 0)) - pr_info("Request LCDC IRQ failed.\n"); - else { - spin_lock_irqsave(&mx2fb_notifier_list.lock, flags); - - /* Enable interrupt in case client has registered */ - //if (mx2fb_notifier_list.head != NULL) { - //unsigned long status; - //unsigned long ints = MX2FB_INT_EOF; - - //ints |= MX2FB_INT_GW_EOF; - - /* Enable interrupt in case client has registered */ - //if (mx2fb_notifier_list.head != NULL) { - /* Write 1 to clear the status */ - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status |= SLCDC_IRQ_FLAGS_MASK; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - - /* Enable SLCDC interrupt */ - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status |= SLCDC_IRQ_ENABLE; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - //} - //} - - spin_unlock_irqrestore(&mx2fb_notifier_list.lock, flags); - } -} - -/*! - * @brief Free LCDC interrupt handler - */ -static void _free_irq(void) -{ - unsigned long status; - status =__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - /* Write 1 to clear the status */ - status |= SLCDC_IRQ_FLAGS_MASK; - /* Disable all LCDC interrupt */ - status &= ~SLCDC_IRQ_ENABLE; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - - free_irq(INT_SLCDC, 0); -} - -/*! - * @brief Register a client notifier - * @param nb notifier block to callback on events - */ -int mx2fb_register_client(struct notifier_block *nb) -{ - unsigned long flags, status; - int ret; - - ret = atomic_notifier_chain_register(&mx2fb_notifier_list, nb); - - spin_lock_irqsave(&mx2fb_notifier_list.lock, flags); - - /* Enable interrupt in case client has registered */ - if (mx2fb_notifier_list.head != NULL) { - /* Write 1 to clear the status */ - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status |= SLCDC_IRQ_FLAGS_MASK; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - - /* Enable SLCDC interrupt */ - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status |= SLCDC_IRQ_ENABLE; - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - } - spin_unlock_irqrestore(&mx2fb_notifier_list.lock, flags); - - return ret; -} - -/*! - * @brief Unregister a client notifier - * @param nb notifier block to callback on events - */ -int mx2fb_unregister_client(struct notifier_block *nb) -{ - unsigned long flags, status; - int ret; - - ret = atomic_notifier_chain_unregister(&mx2fb_notifier_list, nb); - - spin_lock_irqsave(&mx2fb_notifier_list.lock, flags); - - /* Mask interrupt in case no client registered */ - if (mx2fb_notifier_list.head == NULL) { - /* Enable SLCDC interrupt */ - status = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - status &= ~(SLCDC_IRQ_ENABLE); - __raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT)); - } - - spin_unlock_irqrestore(&mx2fb_notifier_list.lock, flags); - - return ret; -} - -#ifdef CONFIG_PM -/* - * Power management hooks. Note that we won't be called from IRQ context, - * unlike the blank functions above, so we may sleep. - */ - -/*! - * @brief Suspends the framebuffer and blanks the screen. - * Power management support - */ -#ifdef CONFIG_FB_MXC_EPSON_L4F0024 -static int mx2fb_spi_suspend(struct spi_device *spi, pm_message_t state) -{ -#else -static int mx2fb_suspend(struct platform_device *pdev, pm_message_t state) -{ -#endif - _disable_slcdc(&mx2fb_info); - - return 0; -} - -/*! - * @brief Resumes the framebuffer and unblanks the screen. - * Power management support - */ -#ifdef CONFIG_FB_MXC_EPSON_L4F0024 -static int mx2fb_spi_resume(struct spi_device *spi) -#else -static int mx2fb_resume(struct platform_device *pdev) -#endif -{ - _enable_slcdc(&mx2fb_info); - return 0; -} -#endif /* CONFIG_PM */ - -/*! - * @brief Probe routine for the framebuffer driver. It is called during the - * driver binding process. - * - * @return Appropriate error code to the kernel common code - */ -static int mx2fb_probe(struct platform_device *pdev) -{ - int ret; - - slcdc_clk = clk_get(&pdev->dev, "slcdc_clk"); - clk_enable(slcdc_clk); - - gpio_slcdc_active(); - - /* Memory allocation of display data for DMA transfert */ - /* convert 1 byte / pixel length to 1 byte / column (8 pixels) */ - mx2fbp_bg.cgram_data_len = OLED_WIDTH*OLED_HEIGHT / 8; - /* Allocate memory for CGRAM mirror with 128k boundary - * (cf note SLCDC in Ch. 44.2 of i.MX27 RM) aligned on 1 byte */ - mx2fbp_bg.cgram_data_dma_pool = dma_pool_create("SLCDC_DMA_DATA", &pdev->dev, mx2fbp_bg.cgram_data_len, 1, 128*1024); - if (mx2fbp_bg.cgram_data_dma_pool == NULL) { - dev_err(&pdev->dev, "Unable to allocated DMA Pool.\n"); - return -ENOMEM; - } - mx2fbp_bg.cgram_data_vaddr = (unsigned long)dma_pool_alloc(mx2fbp_bg.cgram_data_dma_pool, GFP_DMA | GFP_KERNEL, (dma_addr_t *) &mx2fbp_bg.cgram_data_paddr); - if ((void *)mx2fbp_bg.cgram_data_vaddr == NULL) { - dev_err(&pdev->dev, "Unable to allocated DMA memory.\n"); - return -ENOMEM; - } - - /* Memory allocation of display commands for DMA transfert */ - /* a page address on LCD is defined by 3 three commands. - * Each command must be joined with a byte containing the state - * of RS pin to apply (cf Fig 44-5 from SLCDC chapter in i.MX27 RM). - * Array must be defined as unsigned short */ - mx2fbp_bg.cgram_cmd_len = sizeof(_ssd1305_pagecmd_array)/sizeof(_ssd1305_pagecmd_array[0]); - /* Allocate memory for CGRAM mirror with 128k boundary - * (cf note SLCDC in Ch. 44.2 of i.MX27 RM) aligned on 2 bytes (array of shorts) */ - mx2fbp_bg.cgram_cmd_dma_pool = dma_pool_create("SLCDC_DMA_CMD", &pdev->dev, mx2fbp_bg.cgram_cmd_len/(sizeof(int)/sizeof(_ssd1305_pagecmd_array[0])), 2, 128*1024); - if (mx2fbp_bg.cgram_cmd_dma_pool == NULL) { - dev_err(&pdev->dev, "Unable to allocated DMA Pool.\n"); - return -ENOMEM; - } - mx2fbp_bg.cgram_cmd_vaddr = (unsigned long)dma_pool_alloc(mx2fbp_bg.cgram_cmd_dma_pool, GFP_DMA | GFP_KERNEL, (dma_addr_t *) &mx2fbp_bg.cgram_cmd_paddr); - if ((void *)mx2fbp_bg.cgram_cmd_vaddr == NULL) { - dev_err(&pdev->dev, "Unable to allocated DMA memory.\n"); - return -ENOMEM; - } - - slcdc_first_init(); - dd12832_init_controller(); - - ret = _install_fb(&mx2fb_info, pdev); - if (ret) { - dev_err(&pdev->dev, - "Failed to register framebuffer\n"); - return ret; - } - - //_request_irq(); - - return 0; -} - -/*! - * @brief This structure contains pointers to the power management - * callback functions. - */ -static struct platform_driver mx2fb_driver = { - .driver = { - .name = "mxc_sdc_fb", - .owner = THIS_MODULE, - .bus = &platform_bus_type, - }, - .probe = mx2fb_probe, - .suspend = mx2fb_suspend, - .resume = mx2fb_resume, -}; - -/*! - * @brief Initialization - */ -int __init mx2fb_init(void) -{ - int ret = 0; - ret = platform_driver_register(&mx2fb_driver); - return ret; -} - -/*! - * @brief Cleanup - */ -void __exit mx2fb_exit(void) -{ - _free_irq(); - _uninstall_fb(&mx2fb_info); - - platform_driver_unregister(&mx2fb_driver); -} - -/* Modularization */ -module_init(mx2fb_init); -module_exit(mx2fb_exit); - -EXPORT_SYMBOL(mx2_gw_set); -EXPORT_SYMBOL(mx2fb_register_client); -EXPORT_SYMBOL(mx2fb_unregister_client); - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("MX2 framebuffer driver"); -MODULE_LICENSE("GPL"); diff --git a/a/content_digest b/N1/content_digest index 2fc7f04..7c0525b 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -1,8 +1,8 @@ - "From\0Ga\303\253tan Carlier <gcembed@gmail.com>\0" + "From\0gcembed@gmail.com (Ga\303\253tan Carlier)\0" "Subject\0i.MX27 SLCDC driver\0" - "Date\0Fri, 17 Aug 2012 07:07:57 +0000\0" + "Date\0Fri, 17 Aug 2012 09:07:57 +0200\0" "To\0linux-arm-kernel@lists.infradead.org\0" - "\01:1\0" + "\00:1\0" "b\0" "Hello,\n" "I would like to write the driver for SmartLCD controller of i.MX27. This \n" @@ -18,1331 +18,16 @@ "the same driver.\n" "\n" "Thank you for your help.\n" - "Ga\303\253tan Carlier\n" + "Ga?tan Carlier\n" "\n" "ps : I attach my previous driver for a better overview (this is a \n" - working draft for test purpose) - "\01:2\0" - "fn\0mx2fb-slcd_dd12832_oled.c\0" - "b\0" - "/*\n" - " * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.\n" - " */\n" - "\n" - "/*\n" - " * The code contained herein is licensed under the GNU General Public\n" - " * License. You may obtain a copy of the GNU General Public License\n" - " * Version 2 or later at the following locations:\n" - " *\n" - " * http://www.opensource.org/licenses/gpl-license.html\n" - " * http://www.gnu.org/copyleft/gpl.html\n" - " */\n" - "\n" - "/*!\n" - " * @defgroup Framebuffer_MX27 Framebuffer Driver for MX27.\n" - " */\n" - "\n" - "/*!\n" - " * @file mx2fb.c\n" - " *\n" - " * @brief Frame buffer driver for MX27 ADS.\n" - " *\n" - " * @ingroup Framebuffer_MX27\n" - " */\n" - "\n" - "#include <linux/module.h>\n" - "#include <linux/kernel.h>\n" - "#include <linux/errno.h>\n" - "#include <linux/string.h>\n" - "#include <linux/vmalloc.h>\n" - "#include <linux/slab.h>\n" - "#include <linux/fb.h>\n" - "#include <linux/init.h>\n" - "#include <linux/dmapool.h>\n" - "#include <linux/dma-mapping.h>\n" - "#include <linux/platform_device.h>\n" - "#include <linux/interrupt.h>\n" - "#include <linux/clk.h>\n" - "#include <linux/delay.h>\n" - "#include <asm/uaccess.h>\n" - "#include <asm/arch/mxcfb.h>\n" - "#include <asm/arch/mx2fb_slcdc.h>\n" - "\n" - "#include <asm/arch/pmic_power.h>\n" - "#include \"dd12832_oled.h\"\n" - "\n" - "#ifdef CONFIG_PM\n" - "static int mx2fb_suspend(struct platform_device *pdev, pm_message_t state);\n" - "static int mx2fb_resume(struct platform_device *pdev);\n" - "#else\n" - "#define mx2fb_suspend\t\t0\n" - "#define mx2fb_resume\t\t0\n" - "#endif\n" - "\n" - "#define MX2FB_TYPE_BG 0\n" - "#define MX2FB_TYPE_GW 1\n" - "\n" - "#define floor8(a) (a&(~0x07))\n" - "//#define iceil8(a) (((int)((a+7)/8))*8)\n" - "#define iceil8(a) ((int)((a & ~((int)0x03)) + 8))\n" - "\n" - "\n" - "\n" - "extern void gpio_slcdc_active(void);\n" - "extern void gpio_slcdc_inactive(void);\n" - "\n" - "static char *fb_mode;\n" - "static int fb_enabled;\n" - "static unsigned long default_bpp = 1;\n" - "static unsigned char brightness = 255;\n" - "static ATOMIC_NOTIFIER_HEAD(mx2fb_notifier_list);\n" - "static struct clk *slcdc_clk;\n" - "/*!\n" - " * @brief Structure containing the MX2 specific framebuffer parameters.\n" - " */\n" - "struct mx2fb_par {\n" - "\tint type;\n" - "\tchar *id;\n" - "\tint registered;\n" - "\tint blank;\n" - "\t/* Tell if driver compiled with rotate option enabled */\n" - "\tint rotate;\n" - "\t/* Contains displayed data in 1 byte / column (8 pixels)\n" - "\t * fb data are stored as 1 byte / pixel\n" - "\t * !! must be allocated with 128k alignment using dma_pool_create\n" - "\t */\n" - "\t/* FrameBuffer memory map */\n" - "\tunsigned char* fb_vmem;\n" - "\tsize_t fb_len;\n" - "\tdma_addr_t fb_pmem;\n" - "\t/* Oled cgram memory map */\n" - "\tunsigned long cgram_cmd_vaddr;\n" - "\tunsigned long cgram_cmd_paddr;\n" - "\tunsigned long cgram_cmd_len;\n" - "\tstruct dma_pool *cgram_cmd_dma_pool;\n" - "\tunsigned long cgram_data_vaddr;\n" - "\tunsigned long cgram_data_paddr;\n" - "\tunsigned long cgram_data_len;\n" - "\tstruct dma_pool *cgram_data_dma_pool;\n" - "};\n" - "\n" - "/* Framebuffer APIs */\n" - "/*static int mx2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);\n" - "static int mx2fb_set_par(struct fb_info *info);\n" - "static void _set_fix(struct fb_info *info);*/\n" - "\n" - "/* Internal functions */\n" - "static int __init _init_fbinfo(struct fb_info *info,\n" - "\t\t\t struct platform_device *pdev);\n" - "static int __init _install_fb(struct fb_info *info,\n" - "\t\t\t struct platform_device *pdev);\n" - "static void __exit _uninstall_fb(struct fb_info *info);\n" - "static int _map_video_memory(struct fb_info *info);\n" - "static void _unmap_video_memory(struct fb_info *info);\n" - "/*static void _enable_lcdc(struct fb_info *info);\n" - "static void _disable_lcdc(struct fb_info *info);\n" - "static void _update_slcdc(struct fb_info *info);*/\n" - "\n" - "/* Oled display information */\n" - "struct fb_videomode mxcfb_modedb[] = {\n" - "\t{\n" - "\t\t/* 128x32 */\n" - "\t\t\"Densitron DD12832\", /* name */\n" - "\t\t0, /* refresh */\n" - "\t\t128, /* xres */\n" - "\t\t32, /* yres */\n" - "\t\t0, /* pixclock */\n" - "\t\t0, /* left_margin */\n" - "\t\t0, /* right_margin */\n" - "\t\t0, /* upper_margin */\n" - "\t\t0, /* lower_margin */\n" - "\t\t0, /* hsync_len */\n" - "\t\t0, /* vsync_len */\n" - "\t\t0, /* sync */\n" - "\t\t0, /* mode */\n" - "\t\t0}, /* flag */\n" - "};\n" - "int mxcfb_modedb_sz = ARRAY_SIZE(mxcfb_modedb);\n" - "\n" - "struct mx2fb_par mx2fbp_bg = {\n" - "\t.type = MX2FB_TYPE_BG,\n" - "\t.id = \"DISP0 BG\",\n" - "\t.registered = 0,\n" - "#ifdef CONFIG_FB_MXC_DENSITRON_DD12832_ROTATE\n" - "\t.rotate = 1,\n" - "#else\n" - "\t.rotate = 0,\n" - "#endif\n" - "};\n" - "\n" - "/*!\n" - " * @brief Framebuffer information structures.\n" - " * There are up to 3 framebuffers: background, TVout, and graphic window.\n" - " * If graphic window is configured, it must be the last framebuffer.\n" - " */\n" - "static struct fb_info mx2fb_info = {\n" - "\t.par = &mx2fbp_bg,\n" - "};\n" - "\n" - "/*!\n" - " * Do a minimal setup of SLCDC to be able to send command to DD12832\n" - " */\n" - "static void slcdc_first_init(void)\n" - "{\n" - "\tunsigned long val;\n" - "\tint i;\n" - "\tunsigned long *pdata;\n" - "\n" - "\t/* Screen start address register */\n" - "\t__raw_writel(mx2fbp_bg.cgram_data_paddr, SLCDC_REG(SLCDC_DATABASEADDR));\n" - "\t__raw_writel(mx2fbp_bg.cgram_data_len, SLCDC_REG(SLCDC_DATABUFSIZE));\n" - "\n" - "\t/* Copy command array to DMA area */\n" - "\tpdata = (unsigned long *)mx2fbp_bg.cgram_cmd_vaddr;\n" - "\tfor (i = 0; i < mx2fbp_bg.cgram_cmd_len; i++) {\n" - "\t\tif ((i & 0x01) == 0) {\n" - "\t\t\t/* If even offset, command must be left-aligned in\n" - "\t\t\t * 32-bits memory space */\n" - "\t\t\t*pdata = (unsigned long)_ssd1305_pagecmd_array[i] << 16;\n" - "\t\t} else {\n" - "\t\t\t/* If odd offset, command must be right-aligned in\n" - "\t\t\t * 32-bits memory space */\n" - "\t\t\t*pdata |= (unsigned long)_ssd1305_pagecmd_array[i];\n" - "\t\t\t/* When \"right column\" is filled, go to next address */\n" - "\t\t\tpdata++;\n" - "\t\t}\n" - "\t}\n" - "\t/* Set Array of command for page addressing */\n" - "\t__raw_writel(mx2fbp_bg.cgram_cmd_paddr, SLCDC_REG(SLCDC_COMBASEADDR));\n" - "\t__raw_writel(mx2fbp_bg.cgram_cmd_len, SLCDC_REG(SLCDC_COMBUFSIZE));\n" - "\n" - "\t/* Set number of command (words) that must be send to jump to a\n" - "\t * specific page. Size of \"word\" is define by WORDDEFCOM flag in\n" - "\t * LCDTRANSCONFIG register */\n" - "\t__raw_writel(PAGE_COMMAND_PACK_SIZE, SLCDC_REG(SLCDC_COMSTRINGSIZ));\n" - "\n" - "\t/* Define DMA burst */\n" - "\t__raw_writel(0, SLCDC_REG(SLCDC_FIFOCONFIG));\n" - "\n" - "\t/* Define number of column/segment in a page */\n" - "\t__raw_writel(OLED_WIDTH, SLCDC_REG(SLCDC_LCDCONFIG));\n" - "\n" - "\t/* Set transfer configuration */\n" - "\tval = SLCDC_DATA_8BIT | SLCDC_COMMAND_8BIT | SLCDC_PARALLEL |\n" - "\t\tSLCDC_WRITEDATA_8BIT | SLCDC_TRANS_LITLENDIAN_8BIT |\n" - "\t\tSLCDC_CSPOL_LOW;\n" - "\t__raw_writel(val, SLCDC_REG(SLCDC_LCDTRANSCONFIG));\n" - "\n" - "\t/* Set control register */\n" - "\tval = SLCDC_MODE_COMMAND | SLCDC_IRQ_DISABLE | SLCDC_IRQ_FLAGS_MASK;\n" - "\t__raw_writel(val, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\n" - "\t/* Set SLCDC clock divider = HCLK_SLCDC * val / 128 */\n" - "\tval = 40;\n" - "\t__raw_writel(val, SLCDC_REG(SLCDC_LCDCLOCKCONFIG));\n" - "}\n" - "\n" - "\n" - "/*\n" - " * Send one command to oled via SLCDC\n" - " */\n" - "static int _slcdc_sendcmd_single(unsigned char cmd)\n" - "{\n" - "\twhile (__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)) & SLCDC_BUSY_MASK);\n" - "\t__raw_writel((u32)cmd | WRITE_LCDCMD, SLCDC_REG(SLCDC_LCDWRITEDATA));\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*\n" - " * Send one data to oled via SLCDC\n" - " */\n" - "static int _slcdc_senddata_single(unsigned char cmd)\n" - "{\n" - "\twhile (__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)) & SLCDC_BUSY_MASK);\n" - "\t__raw_writel((u32)cmd | WRITE_LCDDATA, SLCDC_REG(SLCDC_LCDWRITEDATA));\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*\n" - " * Set Start line for Pan function\n" - " */\n" - "static void dd12832_set_start_line(unsigned char y)\n" - "{\n" - "\t_slcdc_sendcmd_single(SSD1305_CMD_ROWADDR | (y & 0x3F));\n" - "}\n" - "\n" - "/*\n" - " * Set page address\n" - " */\n" - "static void dd12832_set_yaddr(unsigned char y)\n" - "{\n" - "\t_slcdc_sendcmd_single(SSD1305_CMD_PAGEADDR | (y & 0x07));\n" - "}\n" - "\n" - "/*\n" - " * Set segment address\n" - " */\n" - "static void dd12832_set_xaddr(unsigned char x)\n" - "{\n" - "#ifndef CONFIG_FB_MXC_DENSITRON_DD12832_ROTATE\n" - "\t_slcdc_sendcmd_single(SSD1305_CMD_HIGHCOLADDR | (x >> 4));\n" - "\t_slcdc_sendcmd_single(SSD1305_CMD_LOWCOLADDR | (x & 0x0F));\n" - "#else\n" - "\tx += SSD1305_WIDTH - OLED_WIDTH;\n" - "\t_slcdc_sendcmd_single(SSD1305_CMD_HIGHCOLADDR | (x >> 4));\n" - "\t_slcdc_sendcmd_single(SSD1305_CMD_LOWCOLADDR | (x & 0x0F));\n" - "#endif\n" - "}\n" - "\n" - "/*\n" - " * Modify contrast value\n" - " */\n" - "static void dd12832_set_brightness(unsigned char level)\n" - "{\n" - "\tif (level == 0) {\n" - "\t\t/* If level 0 asked, display must be turned off\n" - "\t\t* because Display is still ON when Contrast\n" - "\t\t* is set to 0 */\n" - "\t\t_slcdc_sendcmd_single(SSD1305_CMD_DISPLAY_POWER_OFF);\n" - "\t} else {\n" - "\t\t/* Apply new contrast */\n" - "\t\t_slcdc_sendcmd_single(SSD1305_CMD_BRIGHTNESS_MODE);\n" - "\t\t_slcdc_sendcmd_single(level);\n" - "\t\t/* Be sure that DISPLAY is ON */\n" - "\t\t_slcdc_sendcmd_single(SSD1305_CMD_DISPLAY_POWER_ON);\n" - "\t}\n" - "}\n" - "\n" - "/*\n" - " * Clear internal RAM of controller\n" - " */\n" - "static void dd12832_clear_lcd(void)\n" - "{\n" - "\tunsigned long status;\n" - "\t/* Clear OLED RAM mirror buffer */\n" - "\tchar *pdata = (char *)mx2fbp_bg.cgram_data_vaddr;\n" - "\tmemset(pdata, 0, mx2fbp_bg.cgram_data_len);\n" - "\n" - "\t/* Clear FrameBuffer mirror buffer */\n" - "\tpdata = (char __force *) mx2fbp_bg.fb_vmem;\n" - "\tmemset(pdata, 0, mx2fbp_bg.fb_len);\n" - "\n" - "\tdd12832_set_yaddr(0);\n" - "\tdd12832_set_xaddr(0);\n" - "\twhile (__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)) & SLCDC_BUSY_MASK);\n" - "\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\tstatus &= ~(SLCDC_SLCDCCTRLSTAT_AUTOMODE_MASK);\n" - "\tstatus |= SLCDC_MODE_DATA | SLCDC_START_TRANSFERT;\n" - "\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "}\n" - "\n" - "/*\n" - " * Send init sequence to display controller\n" - " */\n" - "static int dd12832_init_controller(void)\n" - "{\n" - "\t/* Use SLCDC to send command block */\n" - "\tunsigned long i;\n" - "\n" - "\tfor (i = 0; i < sizeof(_ssd1305_init_array); i++) {\n" - "\t\t_slcdc_sendcmd_single(_ssd1305_init_array[i]);\n" - "\t}\n" - "\tdd12832_clear_lcd();\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Enable LCD controller.\n" - " * @param info\tframebuffer information pointer\n" - " */\n" - "static void _enable_slcdc(struct fb_info *info)\n" - "{\n" - "\tif (!fb_enabled) {\n" - "\t\tfb_enabled++;\n" - "\n" - "\t\tif (fb_mode) {\n" - "\t\t\tunsigned long mode = 0;\n" - "\t\t\tif (mode == 0) {\n" - "\t\t\t\tdd12832_set_brightness(brightness);\n" - "\t\t\t}\n" - "\t\t}\n" - "\t}\n" - "}\n" - "\n" - "/*!\n" - " * @brief Disable LCD controller.\n" - " * @param info\tframebuffer information pointer\n" - " */\n" - "static void _disable_slcdc(struct fb_info *info)\n" - "{\n" - "\tif (fb_enabled) {\n" - "\t\tdd12832_set_brightness(0);\n" - "\t\tfb_enabled = 0;\n" - "\t}\n" - "}\n" - "\n" - "/*!\n" - " * @brief Update SLCDC registers\n" - " * @param info\tframebuffer information pointer\n" - " */\n" - "static void _update_slcdc(struct fb_info *info)\n" - "{\n" - "\tunsigned long base;\n" - "\tunsigned long val;\n" - "\tstruct fb_var_screeninfo *var = &info->var;\n" - "\n" - "\tbase = (var->yoffset * var->xres_virtual + var->xoffset);\n" - "\tbase += (unsigned long)info->screen_base;\n" - "\n" - "\t/* Set number of command (words) that must be send to jump to a\n" - "\t * specific page. Size of \"word\" is define by WORDDEFCOM flag in\n" - "\t * LCDTRANSCONFIG register */\n" - "\t__raw_writel(PAGE_COMMAND_PACK_SIZE, SLCDC_REG(SLCDC_COMSTRINGSIZ));\n" - "\n" - "\t/* Define DMA burst */\n" - "\t__raw_writel(0, SLCDC_REG(SLCDC_FIFOCONFIG));\n" - "\n" - "\t/* Define number of column/segment in a page */\n" - "\t__raw_writel(OLED_WIDTH, SLCDC_REG(SLCDC_LCDCONFIG));\n" - "\n" - "\t/* Set transfer configuration */\n" - "\tval = SLCDC_DATA_8BIT | SLCDC_COMMAND_8BIT | SLCDC_PARALLEL |\n" - "\t\tSLCDC_WRITEDATA_8BIT | SLCDC_TRANS_LITLENDIAN_8BIT |\n" - "\t\tSLCDC_CSPOL_LOW;\n" - "\t__raw_writel(val, SLCDC_REG(SLCDC_LCDTRANSCONFIG));\n" - "\n" - "\t/* Set SLCDC clock divider = HCLK_SLCDC * val / 128 */\n" - "\tval = 60;\n" - "\t__raw_writel(val, SLCDC_REG(SLCDC_LCDCLOCKCONFIG));\n" - "\n" - "\treturn;\n" - "}\n" - "\n" - "\n" - "/*!\n" - " * @brief Blanks the display.\n" - " *\n" - " * @param blank_mode\tThe blank mode we want.\n" - " * @param info\t\tFrame buffer structure that represents a single frame buffer\n" - " *\n" - " * @return\t\tNegative errno on error, or zero on success.\n" - " *\n" - " * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking\n" - " * succeeded, != 0 if un-/blanking failed.\n" - " * blank_mode == 2: suspend vsync\n" - " * blank_mode == 3: suspend hsync\n" - " * blank_mode == 4: powerdown\n" - " */\n" - "static int mx2fb_blank(int blank_mode, struct fb_info *info)\n" - "{\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\n" - "\tdev_dbg(info->device, \"blank mode = %d\\n\", blank_mode);\n" - "\n" - "\tmx2fbp->blank = blank_mode;\n" - "\n" - "\tswitch (blank_mode) {\n" - "\tcase FB_BLANK_POWERDOWN:\n" - "\tcase FB_BLANK_VSYNC_SUSPEND:\n" - "\tcase FB_BLANK_HSYNC_SUSPEND:\n" - "\tcase FB_BLANK_NORMAL:\n" - "\t\t_disable_slcdc(info);\n" - "\t\tbreak;\n" - "\tcase FB_BLANK_UNBLANK:\n" - "\t\t_enable_slcdc(info);\n" - "\t\tbreak;\n" - "\t}\n" - "\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*\n" - " * here we start the process of spliting out the fb update into\n" - " * individual blocks of pixels. we end up spliting into 64x64 blocks\n" - " * and finally down to 64x8 pages.\n" - " */\n" - "static void dd12832_cgram_update(struct fb_info *info, unsigned int dx,\n" - "\t\t\t\t\tunsigned int dy, unsigned int w, unsigned int h)\n" - "{\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\tunsigned int startpage, endpage, startseg, endseg;\n" - "\tunsigned int curpage, curseg;\n" - "\tunsigned long status;\n" - "\tint i;\n" - "\tunsigned char myseg;\n" - "\tchar *cgram;\n" - "\tunsigned char *ppixel;\n" - "\n" - "\t/* align the request first */\n" - "\t/* Get first line of the page where starting pixel is located */\n" - "\tstartpage = floor8(dy) / 8;\n" - "\t/* Get first line of the next page where last pixel to update\n" - "\t * is located */\n" - "\tendpage = h + dy - 1;\n" - "\tendpage = iceil8(endpage) / 8;\n" - "\n" - "\t/* First segment to update */\n" - "\tstartseg = dx;\n" - "\t/* Last segment to update */\n" - "\tendseg = dx + (w - 1);\n" - "\n" - "\tfor (curpage = startpage; curpage < endpage; curpage++) {\n" - "\t\tcgram = (char*)mx2fbp->cgram_data_vaddr;\n" - "\t\tcgram += curpage * info->fix.line_length;\n" - "\t\tcgram += startseg;\n" - "\t\tfor (curseg = startseg; curseg <= endseg; curseg++) {\n" - "\t\t\t/* Get segment to update in video memory */\n" - "\t\t\tmyseg = 0;\n" - "\t\t\tppixel = (unsigned char __force *) mx2fbp->fb_vmem;\n" - "\t\t\t/* There is 8 lines per page */\n" - "\t\t\tppixel += curpage * info->fix.line_length * 8;\n" - "\t\t\t/* Points to upper pixel of the current segment */\n" - "\t\t\tppixel += curseg;\n" - "\t\t\tfor (i = 0; i < 8; i++) {\n" - "\t\t\t\tif (*ppixel != 0) {\n" - "\t\t\t\t\tmyseg |= 1 << i;\n" - "\t\t\t\t}\n" - "\t\t\t\t/* Jump to next line to get pixel below */\n" - "\t\t\t\tppixel += info->fix.line_length;\n" - "\t\t\t}\n" - "\t\t\t*cgram = myseg;\n" - "\t\t\tcgram++;\n" - "\t\t}\n" - "\t}\n" - "\tdd12832_set_xaddr(0);\n" - "\tdd12832_set_yaddr(0);\n" - "\twhile (__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT)) & SLCDC_BUSY_MASK);\n" - "\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\tstatus &= ~(SLCDC_SLCDCCTRLSTAT_AUTOMODE_MASK);\n" - "\tstatus |= SLCDC_MODE_DATA | SLCDC_START_TRANSFERT;\n" - "\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "}\n" - "\n" - "\n" - "\n" - "static void mx2fb_fillrect(struct fb_info *info,\n" - "\t\t\t const struct fb_fillrect *rect)\n" - "{\n" - "\tsys_fillrect(info, rect);\n" - "\n" - "\t/* update the physical lcd */\n" - "\tdd12832_cgram_update(info, rect->dx, rect->dy, rect->width, rect->height);\n" - "}\n" - "\n" - "static void mx2fb_copyarea(struct fb_info *info,\n" - "\t\t\t const struct fb_copyarea *area)\n" - "{\n" - "\tsys_copyarea(info, area);\n" - "\n" - "\t/* update the physical lcd */\n" - "\tdd12832_cgram_update(info, area->dx, area->dy, area->width, area->height);\n" - "}\n" - "\n" - "static void mx2fb_imageblit(struct fb_info *info, const struct fb_image *image)\n" - "{\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\tchar *ppixel;\n" - "\tconst char *pdata;\n" - "\tint j;\n" - "\n" - "\tif (image->depth == 1) {\n" - "\t\t/* Draw image */\n" - "\t\tpdata = image->data;\n" - "\t\tppixel = mx2fbp->fb_vmem;\n" - "\t\tppixel += image->dy * info->fix.line_length;\n" - "\t\tppixel += image->dx;\n" - "\t\tfor (j = 0; j < image->height; j++) {\n" - "\t\t\tmemcpy(ppixel, pdata, image->width);\n" - "\t\t\tpdata += image->width;\n" - "\t\t\tppixel += info->fix.line_length;\n" - "\t\t}\n" - "\t\t/* update the physical lcd */\n" - "\t\tdd12832_cgram_update(info, image->dx, image->dy, image->width, image->height);\n" - "\t}\n" - "}\n" - "\n" - "\n" - "/*!\n" - " * @brief Pans the display.\n" - " *\n" - " * @param var\tFrame buffer variable screen structure\n" - " * @param info\tFrame buffer structure that represents a single frame buffer\n" - " *\n" - " * @return\tNegative errno on error, or zero on success.\n" - " *\n" - " * Pan (or wrap, depending on the `vmode' field) the display using the\n" - " * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values\n" - " * don't fit, return -EINVAL.\n" - " */\n" - "static int mx2fb_pan_display(struct fb_var_screeninfo *var,\n" - "\t\t\t struct fb_info *info)\n" - "{\n" - "\tif (info->var.yoffset == var->yoffset) {\n" - "\t\treturn 0;\t/* No change, do nothing */\n" - "\t}\n" - "\n" - " if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < OLED_WIDTH)\n" - " && (info->var.yres <= OLED_WIDTH)) {\n" - " dd12832_set_start_line(var->yoffset);\n" - " info->var.yoffset = var->yoffset;\n" - " return 0;\n" - " }\n" - "\n" - " return -EINVAL;\n" - "}\n" - "\n" - "static int mx2fb_sync(struct fb_info *info)\n" - "{\n" - "\tdd12832_cgram_update(info, 0, 0, info->fix.line_length, info->var.yres_virtual);\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Ioctl function to support customized ioctl operations.\n" - " *\n" - " * @param info\tFramebuffer structure that represents a single frame buffer\n" - " * @param cmd\tThe command number\n" - " * @param arg\tArgument which depends on cmd\n" - " *\n" - " * @return\tNegative errno on error, or zero on success.\n" - " */\n" - "static int mx2fb_ioctl(struct fb_info *info, unsigned int cmd,\n" - "\t\t unsigned long arg)\n" - "{\n" - "\tunsigned char level;\n" - "\n" - "\tswitch (cmd) {\n" - "\tcase MX2FB_SET_BRIGHTNESS:\n" - "\t\tif (copy_from_user((void *)&level, (void *)arg, sizeof(level)))\n" - "\t\t\treturn -EFAULT;\n" - "\t\tbrightness = level;\n" - "\t\tdd12832_set_brightness(level);\n" - "\t\tbreak;\n" - "\tcase MX2FB_FORCE_SYNC:\n" - "\t\tmx2fb_sync(info);\n" - "\t\tbreak;\n" - "\tdefault:\n" - "\t\tdev_dbg(info->device, \"Unknown ioctl command (0x%08X)\\n\", cmd);\n" - "\t\treturn -EINVAL;\n" - "\t}\n" - "\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Set fixed framebuffer parameters based on variable settings.\n" - " *\n" - " * @param info\tframebuffer information pointer\n" - " * @return\tNegative errno on error, or zero on success.\n" - " */\n" - "static void _set_fix(struct fb_info *info)\n" - "{\n" - "\tstruct fb_fix_screeninfo *fix = &info->fix;\n" - "\tstruct fb_var_screeninfo *var = &info->var;\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\n" - "\tstrncpy(fix->id, mx2fbp->id, strlen(mx2fbp->id));\n" - "\tif (var->bits_per_pixel < 8)\n" - "\t\tfix->line_length = var->xres_virtual;\n" - "\telse\n" - "\t\tfix->line_length = var->xres_virtual * var->bits_per_pixel / 8;\n" - "\tfix->type = FB_TYPE_PACKED_PIXELS;\n" - "\tfix->accel = FB_ACCEL_NONE;\n" - "\tfix->visual = FB_VISUAL_MONO10;\n" - "\tfix->xpanstep = 0;\n" - "\tfix->ypanstep = 1;\n" - "\tfix->ywrapstep = 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Validates a var passed in.\n" - " *\n" - " * @param var\tFrame buffer variable screen structure\n" - " * @param info\tFrame buffer structure that represents a single frame buffer\n" - " *\n" - " * @return\tNegative errno on error, or zero on success.\n" - " *\n" - " * Checks to see if the hardware supports the state requested by var passed\n" - " * in. This function does not alter the hardware state! If the var passed in\n" - " * is slightly off by what the hardware can support then we alter the var\n" - " * PASSED in to what we can do. If the hardware doesn't support mode change\n" - " * a -EINVAL will be returned by the upper layers.\n" - " *\n" - " */\n" - "static int mx2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)\n" - "{\n" - "\tif (var->xres_virtual < var->xres)\n" - "\t\tvar->xres_virtual = var->xres;\n" - "\tif (var->yres_virtual < var->yres)\n" - "\t\tvar->yres_virtual = var->yres;\n" - "\n" - "\tif (var->xoffset < 0)\n" - "\t\tvar->xoffset = 0;\n" - "\n" - "\tif (var->yoffset < 0)\n" - "\t\tvar->yoffset = 0;\n" - "\n" - "\tif (var->xoffset + info->var.xres > info->var.xres_virtual)\n" - "\t\tvar->xoffset = info->var.xres_virtual - info->var.xres;\n" - "\n" - "\tif (var->yoffset + info->var.yres > info->var.yres_virtual)\n" - "\t\tvar->yoffset = info->var.yres_virtual - info->var.yres;\n" - "\n" - "\tif (var->bits_per_pixel != default_bpp)\n" - "\t\tvar->bits_per_pixel = default_bpp;\n" - "\n" - "\tif (var->pixclock != 0)\n" - "\t\tvar->pixclock = 0;\n" - "\tvar->red.length = var->green.length = var->blue.length = 1;\n" - "\tvar->red.offset = var->green.offset = var->blue.offset = 0;\n" - "\tvar->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;\n" - "\n" - "\tvar->transp.length = 0;\n" - "\tvar->transp.offset = 0;\n" - "\tvar->transp.msb_right = 0;\n" - "\n" - "\tvar->height = -1;\n" - "\tvar->width = -1;\n" - "\tvar->grayscale = 0;\n" - "\n" - "\t/* Copy nonstd field to/from sync for fbset usage */\n" - "\tvar->sync |= var->nonstd;\n" - "\tvar->nonstd |= var->sync;\n" - "\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Alters the hardware state.\n" - " *\n" - " * @param info\tFrame buffer structure that represents a single frame buffer\n" - " *\n" - " * @return Zero on success others on failure\n" - " *\n" - " * Using the fb_var_screeninfo in fb_info we set the resolution of this\n" - " * particular framebuffer. This function alters the fb_fix_screeninfo stored\n" - " * in fb_info. It doesn't not alter var in fb_info since we are using that\n" - " * data. This means we depend on the data in var inside fb_info to be\n" - " * supported by the hardware. mx2fb_check_var is always called before\n" - " * mx2fb_set_par to ensure this.\n" - " */\n" - "static int mx2fb_set_par(struct fb_info *info)\n" - "{\n" - "\tunsigned long len;\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\n" - "\t_set_fix(info);\n" - "\n" - "\tlen = info->var.yres_virtual * info->fix.line_length;\n" - "\tif (len > info->fix.smem_len) {\n" - "\t\tif (info->fix.smem_start)\n" - "\t\t\t_unmap_video_memory(info);\n" - "\n" - "\t\t/* Memory allocation for framebuffer */\n" - "\t\tif (_map_video_memory(info)) {\n" - "\t\t\tdev_err(info->device, \"Unable to allocate fb memory\\n\");\n" - "\t\t\treturn -ENOMEM;\n" - "\t\t}\n" - "\t}\n" - "\n" - "\t_update_slcdc(info);\n" - "\n" - "\tmx2fb_blank(mx2fbp->blank, info);\n" - "\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*\n" - " * this is the access path from userspace. they can seek and write to\n" - " * the fb. it's inefficient for them to do anything less than 64*8\n" - " * writes since we update the lcd in each write() anyway.\n" - " */\n" - "static ssize_t mx2fb_write(struct fb_info *info, const char __user *buf,\n" - "\t\t\t size_t count, loff_t *ppos)\n" - "{\n" - "\t/* modded from epson 1355 */\n" - "\n" - "\tunsigned long p;\n" - "\tint err=-EINVAL;\n" - "\tunsigned int fbmemlength, x, y, w, h, startpage, endpage;\n" - "\tstruct arcfb_par *par;\n" - "\tunsigned int xres;\n" - "\n" - "\tp = *ppos;\n" - "\tpar = info->par;\n" - "\txres = info->var.xres;\n" - "\tfbmemlength = info->fix.smem_len;\n" - "\n" - "\tif (p > fbmemlength)\n" - "\t\treturn -ENOSPC;\n" - "\n" - "\terr = 0;\n" - "\tif ((count + p) > fbmemlength) {\n" - "\t\tcount = fbmemlength - p;\n" - "\t\terr = -ENOSPC;\n" - "\t}\n" - "\n" - "\tif (count) {\n" - "\t\tchar *base_addr;\n" - "\n" - "\t\tbase_addr = (char __force *)info->screen_base;\n" - "\t\tcount -= copy_from_user(base_addr + p, buf, count);\n" - "\t\t*ppos += count;\n" - "\t\terr = -EFAULT;\n" - "\t}\n" - "\n" - "\t/* Check how many page are affected */\n" - "\tstartpage = floor8(p) / 8;\n" - "\tendpage = iceil8((p + count)) / 8;\n" - "\tx = p % info->fix.line_length;\n" - "\ty = p / info->fix.line_length;\n" - "\tw = count % info->fix.line_length;\n" - "\th = count / info->fix.line_length;\n" - "\tif (startpage != (endpage - 1)) {\n" - "\t\t/* If several page affected, update complete line\n" - "\t\t * of all affected pages */\n" - "\t\tdd12832_cgram_update(info, 0, y, info->fix.line_length, h);\n" - "\t} else {\n" - "\t\t/* One page has been affected, only updates modified segment\n" - "\t\t */\n" - "\t\tdd12832_cgram_update(info, x, y, w, h);\n" - "\t}\n" - "\tif (p+count > info->fix.line_length) {\n" - "\t\t/* Several line must be updated */\n" - "\t}\n" - "\tif (count)\n" - "\t\treturn count;\n" - "\treturn err;\n" - "}\n" - "\n" - "/* fb_mmap\n" - " * Map video memory in user space. We don't use the generic fb_mmap method\n" - " * mainly\n" - " * to allow the use of the TLB streaming flag (CCA=6)\n" - " */\n" - "int mx2fb_mmap(struct fb_info *info /*fbi*/, struct vm_area_struct *vma)\n" - "{\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\tunsigned int len;\n" - "\tunsigned long start=0, off;\n" - "\n" - "\tif (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {\n" - "\t\treturn -EINVAL;\n" - "\t}\n" - "\n" - "\tstart = mx2fbp->fb_pmem & PAGE_MASK;\n" - "\tlen = PAGE_ALIGN((start & ~PAGE_MASK) + mx2fbp->fb_len);\n" - "\n" - "\toff = vma->vm_pgoff << PAGE_SHIFT;\n" - "\n" - "\tif ((vma->vm_end - vma->vm_start + off) > len) {\n" - "\t\treturn -EINVAL;\n" - "\t}\n" - "\n" - "\toff += start;\n" - "\tvma->vm_pgoff = off >> PAGE_SHIFT;\n" - "\n" - "\tvma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);\n" - "\tpgprot_val(vma->vm_page_prot) |= (6 << 9);\n" - "\n" - "\tvma->vm_flags |= VM_IO;\n" - "\n" - "\tif (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,\n" - "\t\t\t\tvma->vm_end - vma->vm_start,\n" - "\t\t\t\tvma->vm_page_prot)) {\n" - "\t\treturn -EAGAIN;\n" - "\t}\n" - "\treturn 0;\n" - "}\n" - "\n" - "\n" - "/*!\n" - " * @brief Framebuffer file operations\n" - " */\n" - "static struct fb_ops mx2fb_ops = {\n" - "\t.owner = THIS_MODULE,\n" - "\t//.fb_read = fb_sys_read,\n" - "\t.fb_write \t= mx2fb_write,\n" - "\t.fb_check_var \t= mx2fb_check_var,\n" - "\t.fb_set_par \t= mx2fb_set_par,\n" - "\t.fb_blank \t= mx2fb_blank,\n" - "\t.fb_pan_display\t= mx2fb_pan_display,\n" - "\t.fb_fillrect\t= mx2fb_fillrect,\n" - "\t.fb_copyarea\t= mx2fb_copyarea,\n" - "\t.fb_imageblit\t= mx2fb_imageblit,\n" - "\t.fb_ioctl\t= mx2fb_ioctl,\n" - "\t.fb_sync\t= mx2fb_sync,\n" - "\t.fb_mmap\t= mx2fb_mmap,\n" - "};\n" - "\n" - "/*!\n" - " * @brief Initialize framebuffer information structure.\n" - " *\n" - " * @param info\tframebuffer information pointer\n" - " * @param pdev\tpointer to struct device\n" - " * @return\tNegative errno on error, or zero on success.\n" - " */\n" - "static int __init _init_fbinfo(struct fb_info *info,\n" - "\t\t\t struct platform_device *pdev)\n" - "{\n" - "\tinfo->device = &pdev->dev;\n" - "\tinfo->var.activate = FB_ACTIVATE_NOW;\n" - "\tinfo->fbops = &mx2fb_ops;\n" - "\tinfo->flags = FBINFO_FLAG_DEFAULT;\n" - "\tinfo->pseudo_palette = NULL;\n" - "\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Install framebuffer into the system.\n" - " *\n" - " * @param info\tframebuffer information pointer\n" - " * @param pdev pointer to struct device\n" - " * @return\tNegative errno on error, or zero on success.\n" - " */\n" - "static int __init _install_fb(struct fb_info *info,\n" - "\t\t\t struct platform_device *pdev)\n" - "{\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\n" - "\tif (_init_fbinfo(info, pdev))\n" - "\t\treturn -EINVAL;\n" - "\n" - "\tif (fb_mode == 0)\n" - "\t\tfb_mode = pdev->dev.platform_data;\n" - "\n" - "\tif (!fb_find_mode(&info->var, info, fb_mode, mxcfb_modedb,\n" - "\t\t\t mxcfb_modedb_sz, NULL, default_bpp)) {\n" - "\t\treturn -EBUSY;\n" - "\t}\n" - "\n" - "\t/* Default Y virtual size is 2x panel size */\n" - "\t/* info->var.yres_virtual = info->var.yres << 1; */\n" - "\n" - "\tif (mx2fbp->type == MX2FB_TYPE_GW)\n" - "\t\tmx2fbp->blank = FB_BLANK_NORMAL;\n" - "\telse\n" - "\t\tmx2fbp->blank = FB_BLANK_UNBLANK;\n" - "\n" - "\tif (mx2fb_set_par(info)) {\n" - "\t\treturn -EINVAL;\n" - "\t}\n" - "\n" - "\tif (register_framebuffer(info) < 0) {\n" - "\t\t_unmap_video_memory(info);\n" - "\t\treturn -EINVAL;\n" - "\t}\n" - "\n" - "\tmx2fbp->registered = 1;\n" - "\n" - "\tdev_info(info->device, \"fb%d registered successfully on %s (rotate = %d).\\n\",\n" - "\t\t info->node, fb_mode, mx2fbp->rotate);\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Uninstall framebuffer from the system.\n" - " *\n" - " * @param info\tframebuffer information pointer\n" - " */\n" - "static void __exit _uninstall_fb(struct fb_info *info)\n" - "{\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\n" - "\tif (!mx2fbp->registered)\n" - "\t\treturn;\n" - "\n" - "\tunregister_framebuffer(info);\n" - "\t_unmap_video_memory(info);\n" - "\tif (&info->cmap)\n" - "\t\tfb_dealloc_cmap(&info->cmap);\n" - "\n" - "\tmx2fbp->registered = 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Allocate memory for framebuffer.\n" - " *\n" - " * @param info\tframebuffer information pointer\n" - " * @return\tNegative errno on error, or zero on success.\n" - " */\n" - "static int _map_video_memory(struct fb_info *info)\n" - "{\n" - "\tunsigned long page;\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\tmx2fbp->fb_len = info->fix.line_length * info->var.yres_virtual;\n" - "\n" - "\tmx2fbp->fb_vmem = dma_alloc_coherent(info->device, PAGE_ALIGN(mx2fbp->fb_len),\n" - "\t\t\t&mx2fbp->fb_pmem, GFP_KERNEL);\n" - "\tif (mx2fbp->fb_vmem == 0) {\n" - "\t\tdev_err(info->device, \"fail to allocate frambuffer (size: %dK))\",\n" - "\t\t\t\tmx2fbp->fb_len / 1024);\n" - "\t\treturn -ENOMEM;\n" - "\t}\n" - "\n" - "\tinfo->screen_base = mx2fbp->fb_vmem;\n" - "\tinfo->fix.smem_start = mx2fbp->fb_pmem;\n" - "\tinfo->fix.smem_len = mx2fbp->fb_len;\n" - "\n" - "\tdev_dbg(info->device, \"Allocated fb @ paddr=0x%08lX, size=%d.\\n\",\n" - "\t\tinfo->fix.smem_start, info->fix.smem_len);\n" - "\n" - "\tinfo->screen_size = info->fix.smem_len;\n" - "\n" - "\t/* Clear the screen */\n" - "\tmemset((char *)mx2fbp->fb_vmem, 0x00, mx2fbp->fb_len);\n" - "\n" - "\t/*\n" - "\t * Set page reserved so that mmap will work. This is necessary\n" - "\t * since we'll be remapping normal memory.\n" - "\t */\n" - "\tfor (page = (unsigned long)mx2fbp->fb_vmem;\n" - "\t page < PAGE_ALIGN((unsigned long)mx2fbp->fb_vmem + mx2fbp->fb_len);\n" - "\t page += PAGE_SIZE) {\n" - "#ifdef CONFIG_DMA_NONCOHERENT\n" - "\t\tSetPageReserved(virt_to_page(CAC_ADDR(page)));\n" - "#else\n" - "\t\tSetPageReserved(virt_to_page(page));\n" - "#endif\n" - "\t}\n" - "\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Release memory for framebuffer.\n" - " * @param info\tframebuffer information pointer\n" - " */\n" - "static void _unmap_video_memory(struct fb_info *info)\n" - "{\n" - "\tstruct mx2fb_par *mx2fbp = (struct mx2fb_par *)info->par;\n" - "\tif (mx2fbp->fb_vmem) {\n" - "\t\tdma_free_noncoherent(info->device, mx2fbp->fb_len, mx2fbp->fb_vmem, mx2fbp->fb_pmem);\n" - "\t}\n" - "\tmx2fbp->fb_len = 0;\n" - "\tmx2fbp->fb_pmem = 0;\n" - "\tmx2fbp->fb_vmem = 0;\n" - "\tinfo->screen_base = 0;\n" - "\tinfo->fix.smem_start = 0;\n" - "\tinfo->fix.smem_len = 0;\n" - "\t/* Free DMA of SLCDC transfert */\n" - "\tdma_pool_free(mx2fbp->cgram_data_dma_pool, (void *)mx2fbp->cgram_data_vaddr, (dma_addr_t) mx2fbp->cgram_data_paddr);\n" - "\tdma_pool_destroy(mx2fbp->cgram_data_dma_pool);\n" - "\tmx2fbp->cgram_data_dma_pool = 0;\n" - "\tmx2fbp->cgram_data_vaddr = 0;\n" - "\tmx2fbp->cgram_data_paddr = 0;\n" - "\tmx2fbp->cgram_data_len = 0;\n" - "\t/* Free DMA of SLCDC transfert */\n" - "\tdma_pool_free(mx2fbp->cgram_cmd_dma_pool, (void *)mx2fbp->cgram_cmd_vaddr, (dma_addr_t) mx2fbp->cgram_cmd_paddr);\n" - "\tdma_pool_destroy(mx2fbp->cgram_cmd_dma_pool);\n" - "\tmx2fbp->cgram_cmd_dma_pool = 0;\n" - "\tmx2fbp->cgram_cmd_vaddr = 0;\n" - "\tmx2fbp->cgram_cmd_paddr = 0;\n" - "\tmx2fbp->cgram_cmd_len = 0;\n" - "}\n" - "\n" - "/*\n" - " * @brief LCDC interrupt handler\n" - " */\n" - "static irqreturn_t mx2fb_isr(int irq, void *dev_id)\n" - "{\n" - "\tstruct fb_event event;\n" - "\tunsigned long status;\n" - "\n" - "\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\tstatus &= SLCDC_IRQ_FLAGS_MASK;\n" - "\n" - "\tif (status & SLCDC_IRQ_FLAG) {\n" - "\t\tprintk(\"Oled xfer done : \");\n" - "\t\tif (status == SLCDC_IRQ_FLAG) {\n" - "\t\t\tprintk(\"Successful\\n\");\n" - "\t\t}\n" - "\t\tif (status & SLCDC_IRQ_TEA_FLAG) {\n" - "\t\t\tprintk(\"DMA error\\n\");\n" - "\t\t\tevent.info = &mx2fb_info;\n" - "\t\t\tatomic_notifier_call_chain(&mx2fb_notifier_list,\n" - "\t\t\t\t\tFB_EVENT_MXC_DMA_ERROR, &event);\n" - "\t\t}\n" - "\t\tif (status & SLCDC_IRQ_UNDRFLOW_FLAG) {\n" - "\t\t\tprintk(\"Underflow occurs\\n\");\n" - "\t\t\tevent.info = &mx2fb_info;\n" - "\t\t\tatomic_notifier_call_chain(&mx2fb_notifier_list,\n" - "\t\t\t\t\tFB_EVENT_MXC_UNDERFLOW, &event);\n" - "\t\t}\n" - "\t}\n" - "\n" - "\t/* Write 1 to clear the status */\n" - "\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\tstatus |= SLCDC_IRQ_FLAGS_MASK;\n" - "\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t\n" - "\treturn IRQ_HANDLED;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Config and request LCDC interrupt\n" - " */\n" - "static void _request_irq(void)\n" - "{\n" - "\tunsigned long status;\n" - "\tunsigned long flags;\n" - "\n" - "\t/* Write 1 to clear the status */\n" - "\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\tstatus |= SLCDC_IRQ_FLAGS_MASK;\n" - "\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\n" - "\tif (request_irq(INT_SLCDC, mx2fb_isr, 0, \"SLCDC\", 0))\n" - "\t\tpr_info(\"Request LCDC IRQ failed.\\n\");\n" - "\telse {\n" - "\t\tspin_lock_irqsave(&mx2fb_notifier_list.lock, flags);\n" - "\n" - "\t\t/* Enable interrupt in case client has registered */\n" - "\t\t//if (mx2fb_notifier_list.head != NULL) {\n" - "\t\t\t//unsigned long status;\n" - "\t\t\t//unsigned long ints = MX2FB_INT_EOF;\n" - "\n" - "\t\t\t//ints |= MX2FB_INT_GW_EOF;\n" - "\n" - "\t\t\t/* Enable interrupt in case client has registered */\n" - "\t\t\t//if (mx2fb_notifier_list.head != NULL) {\n" - "\t\t\t\t/* Write 1 to clear the status */\n" - "\t\t\t\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t\t\t\tstatus |= SLCDC_IRQ_FLAGS_MASK;\n" - "\t\t\t\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\n" - "\t\t\t\t/* Enable SLCDC interrupt */\n" - "\t\t\t\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t\t\t\tstatus |= SLCDC_IRQ_ENABLE;\n" - "\t\t\t\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t\t\t//}\n" - "\t\t//}\n" - "\n" - "\t\tspin_unlock_irqrestore(&mx2fb_notifier_list.lock, flags);\n" - "\t}\n" - "}\n" - "\n" - "/*!\n" - " * @brief Free LCDC interrupt handler\n" - " */\n" - "static void _free_irq(void)\n" - "{\n" - "\tunsigned long status;\n" - "\tstatus =__raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t/* Write 1 to clear the status */\n" - "\tstatus |= SLCDC_IRQ_FLAGS_MASK;\n" - "\t/* Disable all LCDC interrupt */\n" - "\tstatus &= ~SLCDC_IRQ_ENABLE;\n" - "\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\n" - "\tfree_irq(INT_SLCDC, 0);\n" - "}\n" - "\n" - "/*!\n" - " * @brief Register a client notifier\n" - " * @param nb\tnotifier block to callback on events\n" - " */\n" - "int mx2fb_register_client(struct notifier_block *nb)\n" - "{\n" - "\tunsigned long flags, status;\n" - "\tint ret;\n" - "\n" - "\tret = atomic_notifier_chain_register(&mx2fb_notifier_list, nb);\n" - "\n" - "\tspin_lock_irqsave(&mx2fb_notifier_list.lock, flags);\n" - "\n" - "\t/* Enable interrupt in case client has registered */\n" - "\tif (mx2fb_notifier_list.head != NULL) {\n" - "\t\t/* Write 1 to clear the status */\n" - "\t\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t\tstatus |= SLCDC_IRQ_FLAGS_MASK;\n" - "\t\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\n" - "\t\t/* Enable SLCDC interrupt */\n" - "\t\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t\tstatus |= SLCDC_IRQ_ENABLE;\n" - "\t\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t}\n" - "\tspin_unlock_irqrestore(&mx2fb_notifier_list.lock, flags);\n" - "\n" - "\treturn ret;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Unregister a client notifier\n" - " * @param nb\tnotifier block to callback on events\n" - " */\n" - "int mx2fb_unregister_client(struct notifier_block *nb)\n" - "{\n" - "\tunsigned long flags, status;\n" - "\tint ret;\n" - "\n" - "\tret = atomic_notifier_chain_unregister(&mx2fb_notifier_list, nb);\n" - "\n" - "\tspin_lock_irqsave(&mx2fb_notifier_list.lock, flags);\n" - "\n" - "\t/* Mask interrupt in case no client registered */\n" - "\tif (mx2fb_notifier_list.head == NULL) {\n" - "\t\t/* Enable SLCDC interrupt */\n" - "\t\tstatus = __raw_readl(SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t\tstatus &= ~(SLCDC_IRQ_ENABLE);\n" - "\t\t__raw_writel(status, SLCDC_REG(SLCDC_SLCDCCTRLSTAT));\n" - "\t}\n" - "\n" - "\tspin_unlock_irqrestore(&mx2fb_notifier_list.lock, flags);\n" - "\n" - "\treturn ret;\n" - "}\n" - "\n" - "#ifdef CONFIG_PM\n" - "/*\n" - " * Power management hooks. Note that we won't be called from IRQ context,\n" - " * unlike the blank functions above, so we may sleep.\n" - " */\n" - "\n" - "/*!\n" - " * @brief Suspends the framebuffer and blanks the screen.\n" - " * Power management support\n" - " */\n" - "#ifdef CONFIG_FB_MXC_EPSON_L4F0024\n" - "static int mx2fb_spi_suspend(struct spi_device *spi, pm_message_t state)\n" - "{\n" - "#else\n" - "static int mx2fb_suspend(struct platform_device *pdev, pm_message_t state)\n" - "{\n" - "#endif\n" - "\t_disable_slcdc(&mx2fb_info);\n" - "\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Resumes the framebuffer and unblanks the screen.\n" - " * Power management support\n" - " */\n" - "#ifdef CONFIG_FB_MXC_EPSON_L4F0024\n" - "static int mx2fb_spi_resume(struct spi_device *spi)\n" - "#else\n" - "static int mx2fb_resume(struct platform_device *pdev)\n" - "#endif\n" - "{\n" - "\t_enable_slcdc(&mx2fb_info);\n" - "\treturn 0;\n" - "}\n" - "#endif\t\t\t\t/* CONFIG_PM */\n" - "\n" - "/*!\n" - " * @brief Probe routine for the framebuffer driver. It is called during the\n" - " * driver binding process.\n" - " *\n" - " * @return Appropriate error code to the kernel common code\n" - " */\n" - "static int mx2fb_probe(struct platform_device *pdev)\n" - "{\n" - "\tint ret;\n" - "\n" - "\tslcdc_clk = clk_get(&pdev->dev, \"slcdc_clk\");\n" - "\tclk_enable(slcdc_clk);\n" - "\n" - "\tgpio_slcdc_active();\n" - "\n" - "\t/* Memory allocation of display data for DMA transfert */\n" - "\t/* convert 1 byte / pixel length to 1 byte / column (8 pixels) */\n" - "\tmx2fbp_bg.cgram_data_len = OLED_WIDTH*OLED_HEIGHT / 8;\n" - "\t/* Allocate memory for CGRAM mirror with 128k boundary\n" - "\t * (cf note SLCDC in Ch. 44.2 of i.MX27 RM) aligned on 1 byte */\n" - "\tmx2fbp_bg.cgram_data_dma_pool = dma_pool_create(\"SLCDC_DMA_DATA\", &pdev->dev, mx2fbp_bg.cgram_data_len, 1, 128*1024);\n" - "\tif (mx2fbp_bg.cgram_data_dma_pool == NULL) {\n" - "\t\tdev_err(&pdev->dev, \"Unable to allocated DMA Pool.\\n\");\n" - "\t\treturn -ENOMEM;\n" - "\t}\n" - "\tmx2fbp_bg.cgram_data_vaddr = (unsigned long)dma_pool_alloc(mx2fbp_bg.cgram_data_dma_pool, GFP_DMA | GFP_KERNEL, (dma_addr_t *) &mx2fbp_bg.cgram_data_paddr);\n" - "\tif ((void *)mx2fbp_bg.cgram_data_vaddr == NULL) {\n" - "\t\tdev_err(&pdev->dev, \"Unable to allocated DMA memory.\\n\");\n" - "\t\treturn -ENOMEM;\n" - "\t}\n" - "\n" - "\t/* Memory allocation of display commands for DMA transfert */\n" - "\t/* a page address on LCD is defined by 3 three commands.\n" - "\t * Each command must be joined with a byte containing the state\n" - "\t * of RS pin to apply (cf Fig 44-5 from SLCDC chapter in i.MX27 RM).\n" - "\t * Array must be defined as unsigned short */\n" - "\tmx2fbp_bg.cgram_cmd_len = sizeof(_ssd1305_pagecmd_array)/sizeof(_ssd1305_pagecmd_array[0]);\n" - "\t/* Allocate memory for CGRAM mirror with 128k boundary\n" - "\t * (cf note SLCDC in Ch. 44.2 of i.MX27 RM) aligned on 2 bytes (array of shorts) */\n" - "\tmx2fbp_bg.cgram_cmd_dma_pool = dma_pool_create(\"SLCDC_DMA_CMD\", &pdev->dev, mx2fbp_bg.cgram_cmd_len/(sizeof(int)/sizeof(_ssd1305_pagecmd_array[0])), 2, 128*1024);\n" - "\tif (mx2fbp_bg.cgram_cmd_dma_pool == NULL) {\n" - "\t\tdev_err(&pdev->dev, \"Unable to allocated DMA Pool.\\n\");\n" - "\t\treturn -ENOMEM;\n" - "\t}\n" - "\tmx2fbp_bg.cgram_cmd_vaddr = (unsigned long)dma_pool_alloc(mx2fbp_bg.cgram_cmd_dma_pool, GFP_DMA | GFP_KERNEL, (dma_addr_t *) &mx2fbp_bg.cgram_cmd_paddr);\n" - "\tif ((void *)mx2fbp_bg.cgram_cmd_vaddr == NULL) {\n" - "\t\tdev_err(&pdev->dev, \"Unable to allocated DMA memory.\\n\");\n" - "\t\treturn -ENOMEM;\n" - "\t}\n" - "\n" - "\tslcdc_first_init();\n" - "\tdd12832_init_controller();\n" - "\n" - "\tret = _install_fb(&mx2fb_info, pdev);\n" - "\tif (ret) {\n" - "\t\tdev_err(&pdev->dev,\n" - "\t\t\t\"Failed to register framebuffer\\n\");\n" - "\t\treturn ret;\n" - "\t}\n" - "\n" - "\t//_request_irq();\n" - "\n" - "\treturn 0;\n" - "}\n" - "\n" - "/*!\n" - " * @brief This structure contains pointers to the power management\n" - " * callback functions.\n" - " */\n" - "static struct platform_driver mx2fb_driver = {\n" - "\t.driver = {\n" - "\t\t .name = \"mxc_sdc_fb\",\n" - "\t\t .owner = THIS_MODULE,\n" - "\t\t .bus = &platform_bus_type,\n" - "\t\t },\n" - "\t.probe = mx2fb_probe,\n" - "\t.suspend = mx2fb_suspend,\n" - "\t.resume = mx2fb_resume,\n" - "};\n" - "\n" - "/*!\n" - " * @brief Initialization\n" - " */\n" - "int __init mx2fb_init(void)\n" - "{\n" - "\tint ret = 0;\n" - "\tret = platform_driver_register(&mx2fb_driver);\n" - "\treturn ret;\n" - "}\n" - "\n" - "/*!\n" - " * @brief Cleanup\n" - " */\n" - "void __exit mx2fb_exit(void)\n" - "{\n" - "\t_free_irq();\n" - "\t_uninstall_fb(&mx2fb_info);\n" - "\n" - "\tplatform_driver_unregister(&mx2fb_driver);\n" - "}\n" - "\n" - "/* Modularization */\n" - "module_init(mx2fb_init);\n" - "module_exit(mx2fb_exit);\n" - "\n" - "EXPORT_SYMBOL(mx2_gw_set);\n" - "EXPORT_SYMBOL(mx2fb_register_client);\n" - "EXPORT_SYMBOL(mx2fb_unregister_client);\n" - "\n" - "MODULE_AUTHOR(\"Freescale Semiconductor, Inc.\");\n" - "MODULE_DESCRIPTION(\"MX2 framebuffer driver\");\n" - "MODULE_LICENSE(\"GPL\");" + "working draft for test purpose)\n" + "-------------- next part --------------\n" + "A non-text attachment was scrubbed...\n" + "Name: mx2fb-slcd_dd12832_oled.c\n" + "Type: text/x-csrc\n" + "Size: 35409 bytes\n" + "Desc: not available\n" + URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120817/ea3df386/attachment-0001.bin> -5c56b6cfaa6792bdbeea2695e99ca95676506187a4bd9c94b79d216892a7093e +2d05b305da118cb99804ec354d487b68df5db18c98039a680628b51300b06e49
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.