Commit 86619708 authored by Wang Qiang's avatar Wang Qiang Committed by Linus Torvalds

NUC900 LCD Controller Driver

An LCD controller driver for nuc900s.  The Linux LOGO is just fine and the
FB-Test application was ok, too.
Signed-off-by: default avatarWang Qiang <rurality.linux@gmail.com>
Cc: Wang Zongshun <mcuos.com@gmail.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 91d4e0a4
......@@ -590,8 +590,40 @@ CONFIG_SSB_POSSIBLE=y
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
# CONFIG_FB is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
# CONFIG_FB_BOOT_VESA_SUPPORT is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
# CONFIG_FB_SYS_IMAGEBLIT is not set
# CONFIG_FB_FOREIGN_ENDIAN is not set
# CONFIG_FB_SYS_FOPS is not set
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
#
# Frame buffer hardware drivers
#
# CONFIG_FB_S1D13XXX is not set
CONFIG_FB_NUC900=y
CONFIG_GPM1040A0_320X240=y
CONFIG_FB_NUC900_DEBUG=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
# CONFIG_FB_BROADSHEET is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Display device support
......@@ -603,6 +635,25 @@ CONFIG_SSB_POSSIBLE=y
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
# CONFIG_FONT_8x8 is not set
CONFIG_FONT_8x16=y
# CONFIG_FONT_6x11 is not set
# CONFIG_FONT_7x14 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_10x18 is not set
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_SOUND is not set
# CONFIG_HID_SUPPORT is not set
CONFIG_USB_SUPPORT=y
......
......@@ -57,3 +57,4 @@ extern struct platform_device nuc900_device_fmi;
extern struct platform_device nuc900_device_kpi;
extern struct platform_device nuc900_device_rtc;
extern struct platform_device nuc900_device_ts;
extern struct platform_device nuc900_device_lcd;
......@@ -34,6 +34,7 @@
#include <mach/regs-serial.h>
#include <mach/nuc900_spi.h>
#include <mach/map.h>
#include <mach/fb.h>
#include "cpu.h"
......@@ -380,6 +381,47 @@ struct platform_device nuc900_device_kpi = {
.resource = nuc900_kpi_resource,
};
#ifdef CONFIG_FB_NUC900
static struct resource nuc900_lcd_resource[] = {
[0] = {
.start = W90X900_PA_LCD,
.end = W90X900_PA_LCD + W90X900_SZ_LCD - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
static u64 nuc900_device_lcd_dmamask = -1;
struct platform_device nuc900_device_lcd = {
.name = "nuc900-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(nuc900_lcd_resource),
.resource = nuc900_lcd_resource,
.dev = {
.dma_mask = &nuc900_device_lcd_dmamask,
.coherent_dma_mask = -1,
}
};
void nuc900_fb_set_platdata(struct nuc900fb_mach_info *pd)
{
struct nuc900fb_mach_info *npd;
npd = kmalloc(sizeof(*npd), GFP_KERNEL);
if (npd) {
memcpy(npd, pd, sizeof(*npd));
nuc900_device_lcd.dev.platform_data = npd;
} else {
printk(KERN_ERR "no memory for LCD platform data\n");
}
}
#endif
/*Here should be your evb resourse,such as LCD*/
static struct platform_device *nuc900_public_dev[] __initdata = {
......
/* linux/include/asm/arch-nuc900/fb.h
*
* Copyright (c) 2008 Nuvoton technology corporation
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Changelog:
*
* 2008/08/26 vincen.zswan modify this file for LCD.
*/
#ifndef __ASM_ARM_FB_H
#define __ASM_ARM_FB_H
/* LCD Controller Hardware Desc */
struct nuc900fb_hw {
unsigned int lcd_dccs;
unsigned int lcd_device_ctrl;
unsigned int lcd_mpulcd_cmd;
unsigned int lcd_int_cs;
unsigned int lcd_crtc_size;
unsigned int lcd_crtc_dend;
unsigned int lcd_crtc_hr;
unsigned int lcd_crtc_hsync;
unsigned int lcd_crtc_vr;
unsigned int lcd_va_baddr0;
unsigned int lcd_va_baddr1;
unsigned int lcd_va_fbctrl;
unsigned int lcd_va_scale;
unsigned int lcd_va_test;
unsigned int lcd_va_win;
unsigned int lcd_va_stuff;
};
/* LCD Display Description */
struct nuc900fb_display {
/* LCD Image type */
unsigned type;
/* LCD Screen Size */
unsigned short width;
unsigned short height;
/* LCD Screen Info */
unsigned short xres;
unsigned short yres;
unsigned short bpp;
unsigned long pixclock;
unsigned short left_margin;
unsigned short right_margin;
unsigned short hsync_len;
unsigned short upper_margin;
unsigned short lower_margin;
unsigned short vsync_len;
/* hardware special register value */
unsigned int dccs;
unsigned int devctl;
unsigned int fbctrl;
unsigned int scale;
};
struct nuc900fb_mach_info {
struct nuc900fb_display *displays;
unsigned num_displays;
unsigned default_display;
/* GPIO Setting Info */
unsigned gpio_dir;
unsigned gpio_dir_mask;
unsigned gpio_data;
unsigned gpio_data_mask;
};
extern void __init nuc900_fb_set_platdata(struct nuc900fb_mach_info *);
#endif /* __ASM_ARM_FB_H */
/*
* arch/arm/mach-w90x900/include/mach/regs-serial.h
*
* Copyright (c) 2009 Nuvoton technology corporation
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Description:
* Nuvoton Display, LCM Register list
* Author: Wang Qiang (rurality.linux@gmail.com) 2009/12/11
*
*/
#ifndef __ASM_ARM_W90X900_REGS_LDM_H
#define __ASM_ARM_W90X900_REGS_LDM_H
#include <mach/map.h>
/* Display Controller Control/Status Register */
#define REG_LCM_DCCS (0x00)
#define LCM_DCCS_ENG_RST (1 << 0)
#define LCM_DCCS_VA_EN (1 << 1)
#define LCM_DCCS_OSD_EN (1 << 2)
#define LCM_DCCS_DISP_OUT_EN (1 << 3)
#define LCM_DCCS_DISP_INT_EN (1 << 4)
#define LCM_DCCS_CMD_ON (1 << 5)
#define LCM_DCCS_FIELD_INTR (1 << 6)
#define LCM_DCCS_SINGLE (1 << 7)
enum LCM_DCCS_VA_SRC {
LCM_DCCS_VA_SRC_YUV422 = (0 << 8),
LCM_DCCS_VA_SRC_YCBCR422 = (1 << 8),
LCM_DCCS_VA_SRC_RGB888 = (2 << 8),
LCM_DCCS_VA_SRC_RGB666 = (3 << 8),
LCM_DCCS_VA_SRC_RGB565 = (4 << 8),
LCM_DCCS_VA_SRC_RGB444LOW = (5 << 8),
LCM_DCCS_VA_SRC_RGB444HIGH = (7 << 8)
};
/* Display Device Control Register */
#define REG_LCM_DEV_CTRL (0x04)
enum LCM_DEV_CTRL_SWAP_YCbCr {
LCM_DEV_CTRL_SWAP_UYVY = (0 << 1),
LCM_DEV_CTRL_SWAP_YUYV = (1 << 1),
LCM_DEV_CTRL_SWAP_VYUY = (2 << 1),
LCM_DEV_CTRL_SWAP_YVYU = (3 << 1)
};
enum LCM_DEV_CTRL_RGB_SHIFT {
LCM_DEV_CTRL_RGB_SHIFT_NOT = (0 << 3),
LCM_DEV_CTRL_RGB_SHIFT_ONECYCLE = (1 << 3),
LCM_DEV_CTRL_RGB_SHIFT_TWOCYCLE = (2 << 3),
LCM_DEV_CTRL_RGB_SHIFT_NOT_DEF = (3 << 3)
};
enum LCM_DEV_CTRL_DEVICE {
LCM_DEV_CTRL_DEVICE_YUV422 = (0 << 5),
LCM_DEV_CTRL_DEVICE_YUV444 = (1 << 5),
LCM_DEV_CTRL_DEVICE_UNIPAC = (4 << 5),
LCM_DEV_CTRL_DEVICE_SEIKO_EPSON = (5 << 5),
LCM_DEV_CTRL_DEVICE_HIGH_COLOR = (6 << 5),
LCM_DEV_CTRL_DEVICE_MPU = (7 << 5)
};
#define LCM_DEV_CTRL_LCD_DDA (8)
#define LCM_DEV_CTRL_YUV2CCIR (16)
enum LCM_DEV_CTRL_LCD_SEL {
LCM_DEV_CTRL_LCD_SEL_RGB_GBR = (0 << 17),
LCM_DEV_CTRL_LCD_SEL_BGR_RBG = (1 << 17),
LCM_DEV_CTRL_LCD_SEL_GBR_RGB = (2 << 17),
LCM_DEV_CTRL_LCD_SEL_RBG_BGR = (3 << 17)
};
enum LCM_DEV_CTRL_FAL_D {
LCM_DEV_CTRL_FAL_D_FALLING = (0 << 19),
LCM_DEV_CTRL_FAL_D_RISING = (1 << 19),
};
enum LCM_DEV_CTRL_H_POL {
LCM_DEV_CTRL_H_POL_LOW = (0 << 20),
LCM_DEV_CTRL_H_POL_HIGH = (1 << 20),
};
enum LCM_DEV_CTRL_V_POL {
LCM_DEV_CTRL_V_POL_LOW = (0 << 21),
LCM_DEV_CTRL_V_POL_HIGH = (1 << 21),
};
enum LCM_DEV_CTRL_VR_LACE {
LCM_DEV_CTRL_VR_LACE_NINTERLACE = (0 << 22),
LCM_DEV_CTRL_VR_LACE_INTERLACE = (1 << 22),
};
enum LCM_DEV_CTRL_LACE {
LCM_DEV_CTRL_LACE_NINTERLACE = (0 << 23),
LCM_DEV_CTRL_LACE_INTERLACE = (1 << 23),
};
enum LCM_DEV_CTRL_RGB_SCALE {
LCM_DEV_CTRL_RGB_SCALE_4096 = (0 << 24),
LCM_DEV_CTRL_RGB_SCALE_65536 = (1 << 24),
LCM_DEV_CTRL_RGB_SCALE_262144 = (2 << 24),
LCM_DEV_CTRL_RGB_SCALE_16777216 = (3 << 24),
};
enum LCM_DEV_CTRL_DBWORD {
LCM_DEV_CTRL_DBWORD_HALFWORD = (0 << 26),
LCM_DEV_CTRL_DBWORD_FULLWORD = (1 << 26),
};
enum LCM_DEV_CTRL_MPU68 {
LCM_DEV_CTRL_MPU68_80_SERIES = (0 << 27),
LCM_DEV_CTRL_MPU68_68_SERIES = (1 << 27),
};
enum LCM_DEV_CTRL_DE_POL {
LCM_DEV_CTRL_DE_POL_HIGH = (0 << 28),
LCM_DEV_CTRL_DE_POL_LOW = (1 << 28),
};
#define LCM_DEV_CTRL_CMD16 (29)
#define LCM_DEV_CTRL_CM16t18 (30)
#define LCM_DEV_CTRL_CMD_LOW (31)
/* MPU-Interface LCD Write Command */
#define REG_LCM_MPU_CMD (0x08)
/* Interrupt Control/Status Register */
#define REG_LCM_INT_CS (0x0c)
#define LCM_INT_CS_DISP_F_EN (1 << 0)
#define LCM_INT_CS_UNDERRUN_EN (1 << 1)
#define LCM_INT_CS_BUS_ERROR_INT (1 << 28)
#define LCM_INT_CS_UNDERRUN_INT (1 << 29)
#define LCM_INT_CS_DISP_F_STATUS (1 << 30)
#define LCM_INT_CS_DISP_F_INT (1 << 31)
/* CRTC Display Size Control Register */
#define REG_LCM_CRTC_SIZE (0x10)
#define LCM_CRTC_SIZE_VTTVAL(x) ((x) << 16)
#define LCM_CRTC_SIZE_HTTVAL(x) ((x) << 0)
/* CRTC Display Enable End */
#define REG_LCM_CRTC_DEND (0x14)
#define LCM_CRTC_DEND_VDENDVAL(x) ((x) << 16)
#define LCM_CRTC_DEND_HDENDVAL(x) ((x) << 0)
/* CRTC Internal Horizontal Retrace Control Register */
#define REG_LCM_CRTC_HR (0x18)
#define LCM_CRTC_HR_EVAL(x) ((x) << 16)
#define LCM_CRTC_HR_SVAL(x) ((x) << 0)
/* CRTC Horizontal Sync Control Register */
#define REG_LCM_CRTC_HSYNC (0x1C)
#define LCM_CRTC_HSYNC_SHIFTVAL(x) ((x) << 30)
#define LCM_CRTC_HSYNC_EVAL(x) ((x) << 16)
#define LCM_CRTC_HSYNC_SVAL(x) ((x) << 0)
/* CRTC Internal Vertical Retrace Control Register */
#define REG_LCM_CRTC_VR (0x20)
#define LCM_CRTC_VR_EVAL(x) ((x) << 16)
#define LCM_CRTC_VR_SVAL(x) ((x) << 0)
/* Video Stream Frame Buffer-0 Starting Address */
#define REG_LCM_VA_BADDR0 (0x24)
/* Video Stream Frame Buffer-1 Starting Address */
#define REG_LCM_VA_BADDR1 (0x28)
/* Video Stream Frame Buffer Control Register */
#define REG_LCM_VA_FBCTRL (0x2C)
#define LCM_VA_FBCTRL_IO_REGION_HALF (1 << 28)
#define LCM_VA_FBCTRL_FIELD_DUAL (1 << 29)
#define LCM_VA_FBCTRL_START_BUF (1 << 30)
#define LCM_VA_FBCTRL_DB_EN (1 << 31)
/* Video Stream Scaling Control Register */
#define REG_LCM_VA_SCALE (0x30)
#define LCM_VA_SCALE_XCOPY_INTERPOLATION (0 << 15)
#define LCM_VA_SCALE_XCOPY_DUPLICATION (1 << 15)
/* Image Stream Active Window Coordinates */
#define REG_LCM_VA_WIN (0x38)
/* Image Stream Stuff Pixel */
#define REG_LCM_VA_STUFF (0x3C)
/* OSD Window Starting Coordinates */
#define REG_LCM_OSD_WINS (0x40)
/* OSD Window Ending Coordinates */
#define REG_LCM_OSD_WINE (0x44)
/* OSD Stream Frame Buffer Starting Address */
#define REG_LCM_OSD_BADDR (0x48)
/* OSD Stream Frame Buffer Control Register */
#define REG_LCM_OSD_FBCTRL (0x4c)
/* OSD Overlay Control Register */
#define REG_LCM_OSD_OVERLAY (0x50)
/* OSD Overlay Color-Key Pattern Register */
#define REG_LCM_OSD_CKEY (0x54)
/* OSD Overlay Color-Key Mask Register */
#define REG_LCM_OSD_CMASK (0x58)
/* OSD Window Skip1 Register */
#define REG_LCM_OSD_SKIP1 (0x5C)
/* OSD Window Skip2 Register */
#define REG_LCM_OSD_SKIP2 (0x60)
/* OSD horizontal up scaling control register */
#define REG_LCM_OSD_SCALE (0x64)
/* MPU Vsync control register */
#define REG_LCM_MPU_VSYNC (0x68)
/* Hardware cursor control Register */
#define REG_LCM_HC_CTRL (0x6C)
/* Hardware cursot tip point potison on va picture */
#define REG_LCM_HC_POS (0x70)
/* Hardware Cursor Window Buffer Control Register */
#define REG_LCM_HC_WBCTRL (0x74)
/* Hardware cursor memory base address register */
#define REG_LCM_HC_BADDR (0x78)
/* Hardware cursor color ram register mapped to bpp = 0 */
#define REG_LCM_HC_COLOR0 (0x7C)
/* Hardware cursor color ram register mapped to bpp = 1 */
#define REG_LCM_HC_COLOR1 (0x80)
/* Hardware cursor color ram register mapped to bpp = 2 */
#define REG_LCM_HC_COLOR2 (0x84)
/* Hardware cursor color ram register mapped to bpp = 3 */
#define REG_LCM_HC_COLOR3 (0x88)
#endif /* __ASM_ARM_W90X900_REGS_LDM_H */
......@@ -10,6 +10,8 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation;version 2 of the License.
* history:
* Wang Qiang (rurality.linux@gmail.com) add LCD support
*
*/
......@@ -18,9 +20,51 @@
#include <asm/mach/map.h>
#include <asm/mach-types.h>
#include <mach/map.h>
#include <mach/regs-ldm.h>
#include <mach/fb.h>
#include "nuc950.h"
#ifdef CONFIG_FB_NUC900
/* LCD Controller */
static struct nuc900fb_display __initdata nuc950_lcd_info[] = {
/* Giantplus Technology GPM1040A0 320x240 Color TFT LCD */
[0] = {
.type = LCM_DCCS_VA_SRC_RGB565,
.width = 320,
.height = 240,
.xres = 320,
.yres = 240,
.bpp = 16,
.pixclock = 200000,
.left_margin = 34,
.right_margin = 54,
.hsync_len = 10,
.upper_margin = 18,
.lower_margin = 4,
.vsync_len = 1,
.dccs = 0x8e00041a,
.devctl = 0x060800c0,
.fbctrl = 0x00a000a0,
.scale = 0x04000400,
},
};
static struct nuc900fb_mach_info nuc950_fb_info __initdata = {
#if defined(CONFIG_GPM1040A0_320X240)
.displays = &nuc950_lcd_info[0],
#else
.displays = nuc950_lcd_info,
#endif
.num_displays = ARRAY_SIZE(nuc950_lcd_info),
.default_display = 0,
.gpio_dir = 0x00000004,
.gpio_dir_mask = 0xFFFFFFFD,
.gpio_data = 0x00000004,
.gpio_data_mask = 0xFFFFFFFD,
};
#endif
static void __init nuc950evb_map_io(void)
{
nuc950_map_io();
......@@ -30,6 +74,9 @@ static void __init nuc950evb_map_io(void)
static void __init nuc950evb_init(void)
{
nuc950_board_init();
#ifdef CONFIG_FB_NUC900
nuc900_fb_set_platdata(&nuc950_fb_info);
#endif
}
MACHINE_START(W90P950EVB, "W90P950EVB")
......
......@@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include "cpu.h"
/* define specific CPU platform device */
......@@ -25,6 +26,9 @@
static struct platform_device *nuc950_dev[] __initdata = {
&nuc900_device_kpi,
&nuc900_device_fmi,
#ifdef CONFIG_FB_NUC900
&nuc900_device_lcd,
#endif
};
/* define specific CPU platform io map */
......
......@@ -1944,6 +1944,27 @@ config FB_S3C2410_DEBUG
Turn on debugging messages. Note that you can set/unset at run time
through sysfs
config FB_NUC900
bool "NUC900 LCD framebuffer support"
depends on FB && ARCH_W90X900
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
Frame buffer driver for the built-in LCD controller in the Nuvoton
NUC900 processor
config GPM1040A0_320X240
bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD"
depends on FB_NUC900
config FB_NUC900_DEBUG
bool "NUC900 lcd debug messages"
depends on FB_NUC900
help
Turn on debugging messages. Note that you can set/unset at run time
through sysfs
config FB_SM501
tristate "Silicon Motion SM501 framebuffer support"
depends on FB && MFD_SM501
......
......@@ -129,6 +129,7 @@ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
obj-$(CONFIG_FB_MSM) += msm/
obj-$(CONFIG_FB_NUC900) += nuc900fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
......
This diff is collapsed.
/*
*
* Copyright (c) 2009 Nuvoton technology corporation
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Auther:
* Wang Qiang(rurality.linux@gmail.com) 2009/12/16
*/
#ifndef __NUC900FB_H
#define __NUC900FB_H
#include <mach/map.h>
#include <mach/fb.h>
enum nuc900_lcddrv_type {
LCDDRV_NUC910,
LCDDRV_NUC930,
LCDDRV_NUC932,
LCDDRV_NUC950,
LCDDRV_NUC960,
};
#define PALETTE_BUFFER_SIZE 256
#define PALETTE_BUFF_CLEAR (0x80000000) /* entry is clear/invalid */
struct nuc900fb_info {
struct device *dev;
struct clk *clk;
struct resource *mem;
void __iomem *io;
void __iomem *irq_base;
int drv_type;
struct nuc900fb_hw regs;
unsigned long clk_rate;
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
/* keep these registers in case we need to re-write palette */
u32 palette_buffer[PALETTE_BUFFER_SIZE];
u32 pseudo_pal[16];
};
int nuc900fb_init(void);
#endif /* __NUC900FB_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment