![Alexey Charkov](/assets/img/avatar_default.png)
This adds support for the family of Systems-on-Chip produced initially by VIA and now its subsidiary WonderMedia that have recently become widespread in lower-end Chinese ARM-based tablets and netbooks. Support is included for both VT8500 and WM8505, selectable by a configuration switch at kernel build time. Included are basic machine initialization files, register and interrupt definitions, support for the on-chip interrupt controller, high-precision OS timer, GPIO lines, necessary macros for early debug, pulse-width-modulated outputs control, as well as platform device configurations for the specific drivers implemented elsewhere. Signed-off-by: Alexey Charkov <alchark@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
271 lines
5.9 KiB
C
271 lines
5.9 KiB
C
/* linux/arch/arm/mach-vt8500/devices.c
|
|
*
|
|
* Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/io.h>
|
|
#include <linux/device.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pwm_backlight.h>
|
|
#include <linux/memblock.h>
|
|
|
|
#include <asm/mach/arch.h>
|
|
|
|
#include <mach/vt8500fb.h>
|
|
#include <mach/i8042.h>
|
|
#include "devices.h"
|
|
|
|
/* These can't use resources currently */
|
|
unsigned long wmt_ic_base __initdata;
|
|
unsigned long wmt_sic_base __initdata;
|
|
unsigned long wmt_gpio_base __initdata;
|
|
unsigned long wmt_pmc_base __initdata;
|
|
unsigned long wmt_i8042_base __initdata;
|
|
|
|
int wmt_nr_irqs __initdata;
|
|
int wmt_timer_irq __initdata;
|
|
int wmt_gpio_ext_irq[8] __initdata;
|
|
|
|
/* Should remain accessible after init.
|
|
* i8042 driver desperately calls for attention...
|
|
*/
|
|
int wmt_i8042_kbd_irq;
|
|
int wmt_i8042_aux_irq;
|
|
|
|
static u64 fb_dma_mask = DMA_BIT_MASK(32);
|
|
|
|
struct platform_device vt8500_device_lcdc = {
|
|
.name = "vt8500-lcd",
|
|
.id = 0,
|
|
.dev = {
|
|
.dma_mask = &fb_dma_mask,
|
|
.coherent_dma_mask = DMA_BIT_MASK(32),
|
|
},
|
|
};
|
|
|
|
struct platform_device vt8500_device_wm8505_fb = {
|
|
.name = "wm8505-fb",
|
|
.id = 0,
|
|
};
|
|
|
|
/* Smallest to largest */
|
|
static struct vt8500fb_platform_data panels[] = {
|
|
#ifdef CONFIG_WMT_PANEL_800X480
|
|
{
|
|
.xres_virtual = 800,
|
|
.yres_virtual = 480 * 2,
|
|
.mode = {
|
|
.name = "800x480",
|
|
.xres = 800,
|
|
.yres = 480,
|
|
.left_margin = 88,
|
|
.right_margin = 40,
|
|
.upper_margin = 32,
|
|
.lower_margin = 11,
|
|
.hsync_len = 0,
|
|
.vsync_len = 1,
|
|
.vmode = FB_VMODE_NONINTERLACED,
|
|
},
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_WMT_PANEL_800X600
|
|
{
|
|
.xres_virtual = 800,
|
|
.yres_virtual = 600 * 2,
|
|
.mode = {
|
|
.name = "800x600",
|
|
.xres = 800,
|
|
.yres = 600,
|
|
.left_margin = 88,
|
|
.right_margin = 40,
|
|
.upper_margin = 32,
|
|
.lower_margin = 11,
|
|
.hsync_len = 0,
|
|
.vsync_len = 1,
|
|
.vmode = FB_VMODE_NONINTERLACED,
|
|
},
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_WMT_PANEL_1024X576
|
|
{
|
|
.xres_virtual = 1024,
|
|
.yres_virtual = 576 * 2,
|
|
.mode = {
|
|
.name = "1024x576",
|
|
.xres = 1024,
|
|
.yres = 576,
|
|
.left_margin = 40,
|
|
.right_margin = 24,
|
|
.upper_margin = 32,
|
|
.lower_margin = 11,
|
|
.hsync_len = 96,
|
|
.vsync_len = 2,
|
|
.vmode = FB_VMODE_NONINTERLACED,
|
|
},
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_WMT_PANEL_1024X600
|
|
{
|
|
.xres_virtual = 1024,
|
|
.yres_virtual = 600 * 2,
|
|
.mode = {
|
|
.name = "1024x600",
|
|
.xres = 1024,
|
|
.yres = 600,
|
|
.left_margin = 66,
|
|
.right_margin = 2,
|
|
.upper_margin = 19,
|
|
.lower_margin = 1,
|
|
.hsync_len = 23,
|
|
.vsync_len = 8,
|
|
.vmode = FB_VMODE_NONINTERLACED,
|
|
},
|
|
},
|
|
#endif
|
|
};
|
|
|
|
static int current_panel_idx __initdata = ARRAY_SIZE(panels) - 1;
|
|
|
|
static int __init panel_setup(char *str)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(panels); i++) {
|
|
if (strcmp(panels[i].mode.name, str) == 0) {
|
|
current_panel_idx = i;
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
early_param("panel", panel_setup);
|
|
|
|
static inline void preallocate_fb(struct vt8500fb_platform_data *p,
|
|
unsigned long align) {
|
|
p->video_mem_len = (p->xres_virtual * p->yres_virtual * 4) >>
|
|
(p->bpp > 16 ? 0 : (p->bpp > 8 ? 1 :
|
|
(8 / p->bpp) + 1));
|
|
p->video_mem_phys = (unsigned long)memblock_alloc(p->video_mem_len,
|
|
align);
|
|
p->video_mem_virt = phys_to_virt(p->video_mem_phys);
|
|
}
|
|
|
|
struct platform_device vt8500_device_uart0 = {
|
|
.name = "vt8500_serial",
|
|
.id = 0,
|
|
};
|
|
|
|
struct platform_device vt8500_device_uart1 = {
|
|
.name = "vt8500_serial",
|
|
.id = 1,
|
|
};
|
|
|
|
struct platform_device vt8500_device_uart2 = {
|
|
.name = "vt8500_serial",
|
|
.id = 2,
|
|
};
|
|
|
|
struct platform_device vt8500_device_uart3 = {
|
|
.name = "vt8500_serial",
|
|
.id = 3,
|
|
};
|
|
|
|
struct platform_device vt8500_device_uart4 = {
|
|
.name = "vt8500_serial",
|
|
.id = 4,
|
|
};
|
|
|
|
struct platform_device vt8500_device_uart5 = {
|
|
.name = "vt8500_serial",
|
|
.id = 5,
|
|
};
|
|
|
|
static u64 ehci_dma_mask = DMA_BIT_MASK(32);
|
|
|
|
struct platform_device vt8500_device_ehci = {
|
|
.name = "vt8500-ehci",
|
|
.id = 0,
|
|
.dev = {
|
|
.dma_mask = &ehci_dma_mask,
|
|
.coherent_dma_mask = DMA_BIT_MASK(32),
|
|
},
|
|
};
|
|
|
|
struct platform_device vt8500_device_ge_rops = {
|
|
.name = "wmt_ge_rops",
|
|
.id = -1,
|
|
};
|
|
|
|
struct platform_device vt8500_device_pwm = {
|
|
.name = "vt8500-pwm",
|
|
.id = 0,
|
|
};
|
|
|
|
static struct platform_pwm_backlight_data vt8500_pwmbl_data = {
|
|
.pwm_id = 0,
|
|
.max_brightness = 128,
|
|
.dft_brightness = 70,
|
|
.pwm_period_ns = 250000, /* revisit when clocks are implemented */
|
|
};
|
|
|
|
struct platform_device vt8500_device_pwmbl = {
|
|
.name = "pwm-backlight",
|
|
.id = 0,
|
|
.dev = {
|
|
.platform_data = &vt8500_pwmbl_data,
|
|
},
|
|
};
|
|
|
|
struct platform_device vt8500_device_rtc = {
|
|
.name = "vt8500-rtc",
|
|
.id = 0,
|
|
};
|
|
|
|
struct map_desc wmt_io_desc[] __initdata = {
|
|
/* SoC MMIO registers */
|
|
[0] = {
|
|
.virtual = 0xf8000000,
|
|
.pfn = __phys_to_pfn(0xd8000000),
|
|
.length = 0x00390000, /* max of all chip variants */
|
|
.type = MT_DEVICE
|
|
},
|
|
/* PCI I/O space, numbers tied to those in <mach/io.h> */
|
|
[1] = {
|
|
.virtual = 0xf0000000,
|
|
.pfn = __phys_to_pfn(0xc0000000),
|
|
.length = SZ_64K,
|
|
.type = MT_DEVICE
|
|
},
|
|
};
|
|
|
|
void __init vt8500_reserve_mem(void)
|
|
{
|
|
#ifdef CONFIG_FB_VT8500
|
|
panels[current_panel_idx].bpp = 16; /* Always use RGB565 */
|
|
preallocate_fb(&panels[current_panel_idx], SZ_4M);
|
|
vt8500_device_lcdc.dev.platform_data = &panels[current_panel_idx];
|
|
#endif
|
|
}
|
|
|
|
void __init wm8505_reserve_mem(void)
|
|
{
|
|
#if defined CONFIG_FB_WM8505
|
|
panels[current_panel_idx].bpp = 32; /* Always use RGB888 */
|
|
preallocate_fb(&panels[current_panel_idx], 32);
|
|
vt8500_device_wm8505_fb.dev.platform_data = &panels[current_panel_idx];
|
|
#endif
|
|
}
|