xburst: add support for 3.8

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>

SVN-Revision: 35932
This commit is contained in:
Gabor Juhos 2013-03-10 13:24:50 +00:00
parent 15718f5387
commit 8942d4dc04
20 changed files with 4655 additions and 0 deletions

View file

@ -0,0 +1,300 @@
CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
# CONFIG_ARPD is not set
CONFIG_BATTERY_JZ4740=y
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_BRIDGE is not set
CONFIG_CHARGER_GPIO=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
CONFIG_CPU_MIPS32_R1=y
CONFIG_CPU_MIPSR1=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_CPUFREQ=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CRC16=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_XZ=y
CONFIG_DEVMEM=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_EARLY_PRINTK=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_EXT4_FS=y
CONFIG_FAT_FS=y
CONFIG_FB=y
CONFIG_FB_JZ4740=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_IMAGEBLIT=y
# CONFIG_FB_WMT_GE_ROPS is not set
CONFIG_FONTS=y
# CONFIG_FONT_10x18 is not set
CONFIG_FONT_6x11=y
# CONFIG_FONT_7x14 is not set
# CONFIG_FONT_8x16 is not set
# CONFIG_FONT_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_SUN8x16 is not set
CONFIG_FORCE_MAX_ZONEORDER=12
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FREEZER=y
CONFIG_FS_MBCACHE=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GPIOLIB=y
# CONFIG_HAMRADIO is not set
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_KERNEL_BZIP2=y
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_HW_CONSOLE=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_KEYBOARD=y
CONFIG_INPUT_MOUSE=y
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_INPUT_UINPUT=y
CONFIG_IRQ_CPU=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_JBD2=y
CONFIG_JZ4740_QI_LB60=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_UNCOMPRESSED is not set
CONFIG_KERNEL_GZIP=y
CONFIG_KEXEC=y
# CONFIG_KEYBOARD_GPIO is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=2
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MACH_JZ4740=y
CONFIG_MFD_CORE=y
CONFIG_MFD_JZ4740_ADC=y
CONFIG_MIPS=y
CONFIG_MIPS_CPUFREQ=y
CONFIG_MIPS_FPU_EMU=y
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_SEAD3 is not set
CONFIG_MMC=y
CONFIG_MMC_BLOCK=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_JZ4740=y
CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MOUSE_BCM5974 is not set
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_PS2_ALPS is not set
# CONFIG_MOUSE_PS2_ELANTECH is not set
# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
# CONFIG_MOUSE_PS2_SYNAPTICS is not set
# CONFIG_MOUSE_PS2_TOUCHKIT is not set
# CONFIG_MOUSE_PS2_TRACKPOINT is not set
# CONFIG_MOUSE_SERIAL is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_MTD_CFI is not set
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_JZ4740=y
# CONFIG_MTD_SM_COMMON is not set
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
# CONFIG_MTD_UBI_FASTMAP is not set
# CONFIG_MTD_UBI_GLUEBI is not set
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
# CONFIG_NETWORK_FILESYSTEMS is not set
# CONFIG_NET_SCHED is not set
# CONFIG_NEW_LEDS is not set
CONFIG_NLS=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_CODEPAGE_1250=y
CONFIG_NLS_CODEPAGE_1251=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=y
CONFIG_NLS_CODEPAGE_775=y
CONFIG_NLS_CODEPAGE_850=y
CONFIG_NLS_CODEPAGE_852=y
CONFIG_NLS_CODEPAGE_855=y
CONFIG_NLS_CODEPAGE_857=y
CONFIG_NLS_CODEPAGE_860=y
CONFIG_NLS_CODEPAGE_861=y
CONFIG_NLS_CODEPAGE_862=y
CONFIG_NLS_CODEPAGE_863=y
CONFIG_NLS_CODEPAGE_864=y
CONFIG_NLS_CODEPAGE_865=y
CONFIG_NLS_CODEPAGE_866=y
CONFIG_NLS_CODEPAGE_869=y
CONFIG_NLS_CODEPAGE_874=y
CONFIG_NLS_CODEPAGE_932=y
CONFIG_NLS_CODEPAGE_936=y
CONFIG_NLS_CODEPAGE_949=y
CONFIG_NLS_CODEPAGE_950=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_13=y
CONFIG_NLS_ISO8859_14=y
CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_ISO8859_2=y
CONFIG_NLS_ISO8859_3=y
CONFIG_NLS_ISO8859_4=y
CONFIG_NLS_ISO8859_5=y
CONFIG_NLS_ISO8859_6=y
CONFIG_NLS_ISO8859_7=y
CONFIG_NLS_ISO8859_8=y
CONFIG_NLS_ISO8859_9=y
CONFIG_NLS_KOI8_R=y
CONFIG_NLS_KOI8_U=y
CONFIG_NLS_UTF8=y
CONFIG_PAGEFLAGS_EXTENDED=y
# CONFIG_PDA_POWER is not set
CONFIG_PERCPU_RWSEM=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PM=y
CONFIG_PM_CLK=y
# CONFIG_PM_DEBUG is not set
CONFIG_PM_SLEEP=y
CONFIG_POWER_SUPPLY=y
CONFIG_PREEMPT=y
CONFIG_PREEMPT_COUNT=y
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_RCU=y
CONFIG_PRINTK_TIME=y
CONFIG_PROC_PAGE_MONITOR=y
# CONFIG_RCU_BOOST is not set
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_CMOS is not set
CONFIG_RTC_DRV_JZ4740=y
# CONFIG_SCSI_DMA is not set
CONFIG_SERIO=y
CONFIG_SERIO_LIBPS2=y
CONFIG_SND=y
CONFIG_SND_COMPRESS_OFFLOAD=y
# CONFIG_SND_EMU10K1_SEQ is not set
CONFIG_SND_JACK=y
CONFIG_SND_JZ4740_SOC=y
CONFIG_SND_JZ4740_SOC_I2S=y
CONFIG_SND_JZ4740_SOC_QI_LB60=y
# CONFIG_SND_OPL3_LIB_SEQ is not set
# CONFIG_SND_OPL4_LIB_SEQ is not set
CONFIG_SND_PCM=y
# CONFIG_SND_RAWMIDI_SEQ is not set
# CONFIG_SND_SBAWE_SEQ is not set
CONFIG_SND_SOC=y
# CONFIG_SND_SOC_ALL_CODECS is not set
CONFIG_SND_SOC_I2C_AND_SPI=y
CONFIG_SND_SOC_JZ4740_CODEC=y
CONFIG_SND_TIMER=y
CONFIG_SOUND=y
# CONFIG_SOUND_OSS_CORE is not set
# CONFIG_SQUASHFS is not set
# CONFIG_STAGING is not set
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
# CONFIG_SYN_COOKIES is not set
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_ZBOOT=y
CONFIG_SYS_SUPPORTS_ZBOOT_UART16550=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TINY_PREEMPT_RCU=y
CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_UBIFS_FS_LZO=y
CONFIG_UBIFS_FS_XZ=y
CONFIG_UBIFS_FS_ZLIB=y
CONFIG_UIDGID_CONVERTED=y
CONFIG_UNINLINE_SPIN_UNLOCK=y
# CONFIG_USB_ARCH_HAS_EHCI is not set
# CONFIG_USB_ARCH_HAS_XHCI is not set
# CONFIG_USB_AUDIO is not set
CONFIG_USB_COMMON=y
CONFIG_USB_ETH=y
# CONFIG_USB_ETH_EEM is not set
# CONFIG_USB_ETH_RNDIS is not set
CONFIG_USB_FUSB300=y
CONFIG_USB_GADGET=y
# CONFIG_USB_JZ4740 is not set
CONFIG_USB_LIBCOMPOSITE=y
CONFIG_USB_SUPPORT=y
CONFIG_VFAT_FS=y
# CONFIG_VGA_CONSOLE is not set
# CONFIG_VLAN_8021Q is not set
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_VT_HW_CONSOLE_BINDING=y
# CONFIG_WATCHDOG is not set
CONFIG_ZONE_DMA_FLAG=0

View file

@ -0,0 +1,49 @@
# CONFIG_BACKLIGHT_ADP8860 is not set
# CONFIG_BACKLIGHT_ADP8870 is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GENERIC=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BLK_DEV_SD=y
CONFIG_GPIO_SYSFS=y
CONFIG_INPUT_MATRIXKMAP=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_MATRIX=y
# CONFIG_LCD_AMS369FG06 is not set
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_ILI8960=y
# CONFIG_LCD_L4F00242T03 is not set
# CONFIG_LCD_LD9040 is not set
# CONFIG_LCD_LMS283GF05 is not set
# CONFIG_LCD_LTV350QV is not set
# CONFIG_LCD_PLATFORM is not set
# CONFIG_LCD_S6E63M0 is not set
# CONFIG_LCD_TDO24M is not set
# CONFIG_LCD_VGG2432A4 is not set
CONFIG_LOGO=y
CONFIG_LOGO_LINUX_CLUT224=y
CONFIG_LOGO_LINUX_MONO=y
CONFIG_LOGO_LINUX_VGA16=y
CONFIG_REGMAP_SPI=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SPI=y
CONFIG_SPI_BITBANG=y
CONFIG_SPI_GPIO=y
CONFIG_SPI_MASTER=y
# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
# CONFIG_TOUCHSCREEN_BU21013 is not set
# CONFIG_TOUCHSCREEN_DYNAPRO is not set
# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
# CONFIG_TOUCHSCREEN_MAX11801 is not set
# CONFIG_TOUCHSCREEN_PIXCIR is not set
# CONFIG_TOUCHSCREEN_ST1232 is not set
# CONFIG_TOUCHSCREEN_TSC2005 is not set
# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
CONFIG_USB=y
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_HCD_PLATFORM is not set
CONFIG_USB_STORAGE=y

View file

@ -0,0 +1,10 @@
CONFIG_FB_DEFERRED_IO=y
CONFIG_FB_METRONOME=m
CONFIG_FB_SYS_FOPS=m
CONFIG_HWMON=y
CONFIG_I2C_ALGOBIT=y
CONFIG_LEDS_GPIO=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_NEW_LEDS=y
# CONFIG_SENSORS_JZ4740 is not set
CONFIG_SENSORS_LM75=y

View file

@ -0,0 +1 @@
CONFIG_I2C_ALGOBIT=y

View file

@ -0,0 +1,21 @@
From 73aab29ddc44a3e1a7156473ad5bc9cd80704274 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Tue, 15 Mar 2011 12:49:15 +0100
Subject: [PATCH 01/21] ubi: Read only the vid header instead of the whole
page
---
drivers/mtd/ubi/io.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -1019,7 +1019,7 @@ int ubi_io_read_vid_hdr(struct ubi_devic
p = (char *)vid_hdr - ubi->vid_hdr_shift;
read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
- ubi->vid_hdr_alsize);
+ UBI_VID_HDR_SIZE + ubi->vid_hdr_shift);
if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
return read_err;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
From b971c50dc50c07f981a1619f977e7509db9c4eac Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sat, 26 Feb 2011 15:30:07 +0100
Subject: [PATCH 03/21] NAND: Optimize NAND_ECC_HW_OOB_FIRST read
Avoid sending unnecessary READ commands to the chip.
---
drivers/mtd/nand/nand_base.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1299,9 +1299,15 @@ static int nand_read_page_hwecc_oob_firs
unsigned int max_bitflips = 0;
/* Read the OOB area first */
- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ if (mtd->writesize > 512) {
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+ } else {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ }
for (i = 0; i < chip->ecc.total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];

View file

@ -0,0 +1,131 @@
From 297d8a7bdfb755778d4189ca2861dd2a6125e972 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Tue, 15 Mar 2011 12:33:41 +0100
Subject: [PATCH 04/21] NAND: Add support for subpage reads for
NAND_ECC_HW_OOB_FIRST
---
drivers/mtd/nand/nand_base.c | 78 ++++++++++++++++++++++++++++++++++++++++--
include/linux/mtd/nand.h | 8 ++--
2 files changed, 79 insertions(+), 7 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1139,7 +1139,7 @@ static int nand_read_page_swecc(struct m
* @bufpoi: buffer to store read data
*/
static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)
{
int start_step, end_step, num_steps;
uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -1331,6 +1331,75 @@ static int nand_read_page_hwecc_oob_firs
}
/**
+ * nand_read_subpage_hwecc_oob_first - [REPLACABLE] hw ecc based sub-page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @data_offs: offset of requested data within the page
+ * @readlen: data length
+ * @bufpoi: buffer to store read data
+ * @page: page number to read
+ *
+ * Hardware ECC for large page chips, require OOB to be read first.
+ * For this ECC mode, the write_page method is re-used from ECC_HW.
+ * These methods read/write ECC from the OOB area, unlike the
+ * ECC_HW_SYNDROME support with multiple ECC steps, follows the
+ * "infix ECC" scheme and reads/writes ECC from the data area, by
+ * overwriting the NAND manufacturer bad block markings.
+ */
+static int nand_read_subpage_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip,
+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)
+{
+ int start_step, end_step, num_steps;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint8_t *p;
+ int data_col_addr;
+ int eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ int i;
+
+ /* Column address wihin the page aligned to ECC size */
+ start_step = data_offs / chip->ecc.size;
+ end_step = (data_offs + readlen - 1) / chip->ecc.size;
+ num_steps = end_step - start_step + 1;
+
+ data_col_addr = start_step * chip->ecc.size;
+
+ /* Read the OOB area first */
+ if (mtd->writesize > 512) {
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
+ } else {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page);
+ }
+
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+
+ p = bufpoi + data_col_addr;
+
+ for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) {
+ int stat;
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+
+ return 0;
+}
+
+/**
* nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
* @mtd: mtd info structure
* @chip: nand chip info structure
@@ -1495,7 +1564,7 @@ static int nand_do_read_ops(struct mtd_i
else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
!oob)
ret = chip->ecc.read_subpage(mtd, chip,
- col, bytes, bufpoi);
+ col, bytes, bufpoi, page);
else
ret = chip->ecc.read_page(mtd, chip, bufpoi,
oob_required, page);
@@ -3451,8 +3520,11 @@ int nand_scan_tail(struct mtd_info *mtd)
"hardware ECC not possible\n");
BUG();
}
- if (!chip->ecc.read_page)
+ if (!chip->ecc.read_page) {
chip->ecc.read_page = nand_read_page_hwecc_oob_first;
+ if (!chip->ecc.read_subpage)
+ chip->ecc.read_subpage = nand_read_subpage_hwecc_oob_first;
+ }
case NAND_ECC_HW:
/* Use standard hwecc read page function? */
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -384,7 +384,7 @@ struct nand_ecc_ctrl {
int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page);
int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t offs, uint32_t len, uint8_t *buf);
+ uint32_t offs, uint32_t len, uint8_t *buf, int page);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required);
int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,

View file

@ -0,0 +1,53 @@
From 4f28237a750afd1112b6f1266d36f8b718efe89c Mon Sep 17 00:00:00 2001
From: Xiangfu Liu <xiangfu@sharism.cc>
Date: Tue, 6 Mar 2012 11:19:26 +0800
Subject: [PATCH 05/21] NAND-Optimize-reading-the-eec-data-for-the-JZ4740
---
drivers/mtd/nand/nand_base.c | 14 ++++----------
1 files changed, 4 insertions(+), 10 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1300,8 +1300,8 @@ static int nand_read_page_hwecc_oob_firs
/* Read the OOB area first */
if (mtd->writesize > 512) {
- chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize + eccpos[0], page);
+ chip->read_buf(mtd, ecc_code, chip->ecc.total);
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
} else {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
@@ -1309,9 +1309,6 @@ static int nand_read_page_hwecc_oob_firs
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
}
- for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
@@ -1368,8 +1365,8 @@ static int nand_read_subpage_hwecc_oob_f
/* Read the OOB area first */
if (mtd->writesize > 512) {
- chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize + eccpos[0], page);
+ chip->read_buf(mtd, ecc_code, chip->ecc.total);
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
} else {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
@@ -1377,9 +1374,6 @@ static int nand_read_subpage_hwecc_oob_f
chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page);
}
- for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
p = bufpoi + data_col_addr;
for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) {

View file

@ -0,0 +1,304 @@
From 2248fb9c47fe7e72c735d6c16aba27bf92e1673a Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sun, 1 Aug 2010 21:19:40 +0200
Subject: [PATCH 07/21] Add ili8960 lcd driver
---
drivers/video/backlight/Kconfig | 7 +
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/ili8960.c | 263 +++++++++++++++++++++++++++++++++++++
3 files changed, 271 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/backlight/ili8960.c
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -59,6 +59,13 @@ config LCD_LTV350QV
The LTV350QV panel is present on all ATSTK1000 boards.
+config LCD_ILI8960
+ tristate "Ilitek ili8960 LCD driver"
+ depends on LCD_CLASS_DEVICE && SPI
+ default n
+ help
+ Driver for the Ilitek ili8960 LCD controller chip.
+
config LCD_ILI9320
tristate "ILI Technology ILI9320 controller support"
depends on SPI
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_LCD_HP700) += jornada72
obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o
obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o
obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
+obj-$(CONFIG_LCD_ILI8960) += ili8960.o
obj-$(CONFIG_LCD_ILI9320) += ili9320.o
obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
--- /dev/null
+++ b/drivers/video/backlight/ili8960.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * Driver for Ilitek ili8960 LCD
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/lcd.h>
+#include <linux/backlight.h>
+#include <linux/delay.h>
+
+struct ili8960 {
+ struct spi_device *spi;
+ struct lcd_device *lcd;
+ struct backlight_device *bl;
+ bool enabled;
+ unsigned int brightness;
+};
+
+#define ILI8960_REG_BRIGHTNESS 0x03
+#define ILI8960_REG_POWER 0x05
+#define ILI8960_REG_CONTRAST 0x0d
+
+static int ili8960_write_reg(struct spi_device *spi, uint8_t reg,
+ uint8_t data)
+{
+ uint8_t buf[2];
+ buf[0] = ((reg & 0x40) << 1) | (reg & 0x3f);
+ buf[1] = data;
+
+ return spi_write(spi, buf, sizeof(buf));
+}
+
+static int ili8960_programm_power(struct spi_device *spi, bool enabled)
+{
+ int ret;
+
+ if (enabled)
+ mdelay(20);
+
+ ret = ili8960_write_reg(spi, ILI8960_REG_POWER, enabled ? 0xc7 : 0xc6);
+
+ if (!enabled)
+ mdelay(20);
+
+ return ret;
+}
+
+static int ili8960_set_power(struct lcd_device *lcd, int power)
+{
+ struct ili8960 *ili8960 = lcd_get_data(lcd);
+
+ switch (power) {
+ case FB_BLANK_UNBLANK:
+ ili8960->enabled = true;
+ break;
+ default:
+ ili8960->enabled = false;
+ break;
+ }
+
+ return ili8960_programm_power(ili8960->spi, ili8960->enabled);
+}
+
+static int ili8960_get_power(struct lcd_device *lcd)
+{
+ struct ili8960 *ili8960 = lcd_get_data(lcd);
+ return ili8960->enabled ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+}
+
+static int ili8960_set_contrast(struct lcd_device *lcd, int contrast)
+{
+ struct ili8960 *ili8960 = lcd_get_data(lcd);
+
+ return ili8960_write_reg(ili8960->spi, ILI8960_REG_CONTRAST, contrast);
+}
+
+static int ili8960_set_mode(struct lcd_device *lcd, struct fb_videomode *mode)
+{
+ if (mode->xres != 320 && mode->yres != 240)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ili8960_set_brightness(struct ili8960 *ili8960, int brightness)
+{
+ int ret;
+
+ ret = ili8960_write_reg(ili8960->spi, ILI8960_REG_BRIGHTNESS, brightness);
+
+ if (ret == 0)
+ ili8960->brightness = brightness;
+
+ return ret;
+}
+
+static ssize_t ili8960_show_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lcd_device *ld = to_lcd_device(dev);
+ struct ili8960 *ili8960 = lcd_get_data(ld);
+
+ return sprintf(buf, "%u\n", ili8960->brightness);
+}
+
+static ssize_t ili8960_store_brightness(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lcd_device *ld = to_lcd_device(dev);
+ struct ili8960 *ili8960 = lcd_get_data(ld);
+ unsigned long brightness;
+ int ret;
+
+ ret = strict_strtoul(buf, 0, &brightness);
+ if (ret)
+ return ret;
+
+ if (brightness > 255)
+ return -EINVAL;
+
+ ili8960_set_brightness(ili8960, brightness);
+
+ return count;
+}
+
+
+static DEVICE_ATTR(brightness, 0644, ili8960_show_brightness,
+ ili8960_store_brightness);
+
+static struct lcd_ops ili8960_lcd_ops = {
+ .set_power = ili8960_set_power,
+ .get_power = ili8960_get_power,
+ .set_contrast = ili8960_set_contrast,
+ .set_mode = ili8960_set_mode,
+};
+
+static int __devinit ili8960_probe(struct spi_device *spi)
+{
+ int ret;
+ struct ili8960 *ili8960;
+
+ ili8960 = kmalloc(sizeof(*ili8960), GFP_KERNEL);
+ if (!ili8960)
+ return -ENOMEM;
+
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_3;
+
+ ret = spi_setup(spi);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to setup spi\n");
+ goto err_free_ili8960;
+ }
+
+ ili8960->spi = spi;
+
+ ili8960->lcd = lcd_device_register("ili8960-lcd", &spi->dev, ili8960,
+ &ili8960_lcd_ops);
+
+ if (IS_ERR(ili8960->lcd)) {
+ ret = PTR_ERR(ili8960->lcd);
+ dev_err(&spi->dev, "Failed to register lcd device: %d\n", ret);
+ goto err_free_ili8960;
+ }
+
+ ili8960->lcd->props.max_contrast = 255;
+
+ ret = device_create_file(&ili8960->lcd->dev, &dev_attr_brightness);
+ if (ret)
+ goto err_unregister_lcd;
+
+ ili8960_programm_power(ili8960->spi, true);
+ ili8960->enabled = true;
+
+ spi_set_drvdata(spi, ili8960);
+
+ ili8960_write_reg(spi, 0x13, 0x01);
+
+ return 0;
+err_unregister_lcd:
+ lcd_device_unregister(ili8960->lcd);
+err_free_ili8960:
+ kfree(ili8960);
+ return ret;
+}
+
+static int __devexit ili8960_remove(struct spi_device *spi)
+{
+ struct ili8960 *ili8960 = spi_get_drvdata(spi);
+
+ device_remove_file(&ili8960->lcd->dev, &dev_attr_brightness);
+ lcd_device_unregister(ili8960->lcd);
+
+ spi_set_drvdata(spi, NULL);
+ kfree(ili8960);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int ili8960_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct ili8960 *ili8960 = spi_get_drvdata(spi);
+
+ if (ili8960->enabled)
+ ili8960_programm_power(ili8960->spi, false);
+
+ return 0;
+}
+
+static int ili8960_resume(struct spi_device *spi)
+{
+ struct ili8960 *ili8960 = spi_get_drvdata(spi);
+
+ if (ili8960->enabled)
+ ili8960_programm_power(ili8960->spi, true);
+
+ return 0;
+}
+
+#else
+#define ili8960_suspend NULL
+#define ili8960_resume NULL
+#endif
+
+static struct spi_driver ili8960_driver = {
+ .driver = {
+ .name = "ili8960",
+ .owner = THIS_MODULE,
+ },
+ .probe = ili8960_probe,
+ .remove = __devexit_p(ili8960_remove),
+ .suspend = ili8960_suspend,
+ .resume = ili8960_resume,
+};
+
+static int __init ili8960_init(void)
+{
+ return spi_register_driver(&ili8960_driver);
+}
+module_init(ili8960_init);
+
+static void __exit ili8960_exit(void)
+{
+ spi_unregister_driver(&ili8960_driver);
+}
+module_exit(ili8960_exit)
+
+MODULE_AUTHOR("Lars-Peter Clausen");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LCD driver for Ilitek ili8960");
+MODULE_ALIAS("spi:ili8960");

View file

@ -0,0 +1,21 @@
From e5f25e25ed6c0478cbba7a32891b911e3183dad4 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Wed, 13 Oct 2010 01:17:24 +0200
Subject: [PATCH 08/21] qi_lb60: Don't use 3-wire spi mode for the display for
now
The spi_gpio driver does not support 3-wire mode.
---
arch/mips/jz4740/board-qi_lb60.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -311,7 +311,6 @@ static struct spi_board_info qi_lb60_spi
.chip_select = 0,
.bus_num = 1,
.max_speed_hz = 30 * 1000,
- .mode = SPI_3WIRE,
},
};

View file

@ -0,0 +1,124 @@
From 4003b9a2c05f4d0d37535c3dffbf4a7b47d5c36c Mon Sep 17 00:00:00 2001
From: Maarten ter Huurne <maarten@treewalker.org>
Date: Wed, 8 Sep 2010 02:31:19 +0200
Subject: [PATCH 09/21] /dev/mem: Add kernel config option to omit this
device.
Omitting this device prevents software from accessing the hardware directly, which can cause trouble if the kernel accesses the same hardware.
It also saves some space on embedded systems.
---
arch/x86/Kconfig.debug | 1 +
drivers/char/Kconfig | 10 ++++++++++
drivers/char/mem.c | 17 +++++++++++++++++
3 files changed, 28 insertions(+), 0 deletions(-)
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -7,6 +7,7 @@ source "lib/Kconfig.debug"
config STRICT_DEVMEM
bool "Filter access to /dev/mem"
+ depends on DEVMEM
---help---
If this option is disabled, you allow userspace (root) access to all
of memory, including kernel and userspace memory. Accidental
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -6,6 +6,16 @@ menu "Character devices"
source "drivers/tty/Kconfig"
+config DEVMEM
+ bool "/dev/mem virtual device support"
+ default y
+ help
+ Say Y here if you want to support the /dev/mem device.
+ Some X server drivers access the video hardware using this device.
+ Accessing hardware directly from user space can be useful in some
+ cases, but it is not without risks.
+ When in doubt, say "N".
+
config DEVKMEM
bool "/dev/kmem virtual device support"
default y
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -89,6 +89,8 @@ void __weak unxlate_dev_mem_ptr(unsigned
{
}
+#ifdef CONFIG_DEVMEM
+
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
* memory location.
@@ -212,6 +214,10 @@ static ssize_t write_mem(struct file *fi
return written;
}
+#endif
+
+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM)
+
int __weak phys_mem_access_prot_allowed(struct file *file,
unsigned long pfn, unsigned long size, pgprot_t *vma_prot)
{
@@ -333,6 +339,8 @@ static int mmap_mem(struct file *file, s
return 0;
}
+#endif
+
#ifdef CONFIG_DEVKMEM
static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
{
@@ -696,6 +704,7 @@ static loff_t null_lseek(struct file *fi
return file->f_pos = 0;
}
+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) || defined(CONFIG_DEVPORT)
/*
* The memory devices use the full 32/64 bits of the offset, and so we cannot
* check against negative addresses: they are ok. The return value is weird,
@@ -728,11 +737,15 @@ static loff_t memory_lseek(struct file *
mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return ret;
}
+#endif
+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) || \
+ defined(CONFIG_DEVPORT) || defined(CONFIG_CRASH_DUMP)
static int open_port(struct inode * inode, struct file * filp)
{
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
+#endif
#define zero_lseek null_lseek
#define full_lseek null_lseek
@@ -742,6 +755,7 @@ static int open_port(struct inode * inod
#define open_kmem open_mem
#define open_oldmem open_mem
+#ifdef CONFIG_DEVMEM
static const struct file_operations mem_fops = {
.llseek = memory_lseek,
.read = read_mem,
@@ -750,6 +764,7 @@ static const struct file_operations mem_
.open = open_mem,
.get_unmapped_area = get_unmapped_area_mem,
};
+#endif
#ifdef CONFIG_DEVKMEM
static const struct file_operations kmem_fops = {
@@ -815,7 +830,9 @@ static const struct memdev {
const struct file_operations *fops;
struct backing_dev_info *dev_info;
} devlist[] = {
+#ifdef CONFIG_DEVMEM
[1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi },
+#endif
#ifdef CONFIG_DEVKMEM
[2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi },
#endif

View file

@ -0,0 +1,304 @@
From ca40c7542f0cd0e0dfa074bd4ccefc04b8561427 Mon Sep 17 00:00:00 2001
From: Maarten ter Huurne <maarten@treewalker.org>
Date: Tue, 2 Aug 2011 10:26:09 +0200
Subject: [PATCH 10/21] cpufreq_stats: Support runtime changes to frequency
table.
---
drivers/cpufreq/cpufreq_stats.c | 161 ++++++++++++++++++++-------------------
1 files changed, 83 insertions(+), 78 deletions(-)
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -20,6 +20,7 @@
#include <linux/kobject.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
+#include <linux/string.h>
#include <asm/cputime.h>
static spinlock_t cpufreq_stats_lock;
@@ -36,7 +37,7 @@ struct cpufreq_stats {
unsigned long long last_time;
unsigned int max_state;
unsigned int state_num;
- unsigned int last_index;
+ int last_index;
u64 *time_in_state;
unsigned int *freq_table;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
@@ -59,7 +60,7 @@ static int cpufreq_stats_update(unsigned
cur_time = get_jiffies_64();
spin_lock(&cpufreq_stats_lock);
stat = per_cpu(cpufreq_stats_table, cpu);
- if (stat->time_in_state)
+ if (stat->time_in_state && stat->last_index != -1)
stat->time_in_state[stat->last_index] +=
cur_time - stat->last_time;
stat->last_time = cur_time;
@@ -81,7 +82,7 @@ static ssize_t show_time_in_state(struct
ssize_t len = 0;
int i;
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
- if (!stat)
+ if (!stat || !stat->time_in_state)
return 0;
cpufreq_stats_update(stat->cpu);
for (i = 0; i < stat->state_num; i++) {
@@ -99,7 +100,7 @@ static ssize_t show_trans_table(struct c
int i, j;
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
- if (!stat)
+ if (!stat || !stat->trans_table)
return 0;
cpufreq_stats_update(stat->cpu);
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
@@ -158,63 +159,35 @@ static struct attribute_group stats_attr
static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
{
int index;
- for (index = 0; index < stat->max_state; index++)
- if (stat->freq_table[index] == freq)
- return index;
+ if (stat->freq_table)
+ for (index = 0; index < stat->max_state; index++)
+ if (stat->freq_table[index] == freq)
+ return index;
return -1;
}
-/* should be called late in the CPU removal sequence so that the stats
- * memory is still available in case someone tries to use it.
- */
static void cpufreq_stats_free_table(unsigned int cpu)
{
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ if (policy && policy->cpu == cpu)
+ sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (stat) {
kfree(stat->time_in_state);
kfree(stat);
}
per_cpu(cpufreq_stats_table, cpu) = NULL;
-}
-
-/* must be called early in the CPU removal sequence (before
- * cpufreq_remove_dev) so that policy is still valid.
- */
-static void cpufreq_stats_free_sysfs(unsigned int cpu)
-{
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (policy && policy->cpu == cpu)
- sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (policy)
cpufreq_cpu_put(policy);
}
-static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
+static int cpufreq_stats_update_table(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
- unsigned int i, j, count = 0, ret = 0;
- struct cpufreq_stats *stat;
- struct cpufreq_policy *data;
+ unsigned int i, j, count = 0;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
- if (per_cpu(cpufreq_stats_table, cpu))
- return -EBUSY;
- stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
- if ((stat) == NULL)
- return -ENOMEM;
-
- data = cpufreq_cpu_get(cpu);
- if (data == NULL) {
- ret = -EINVAL;
- goto error_get_fail;
- }
-
- ret = sysfs_create_group(&data->kobj, &stats_attr_group);
- if (ret)
- goto error_out;
-
- stat->cpu = cpu;
- per_cpu(cpufreq_stats_table, cpu) = stat;
+ struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency;
@@ -223,40 +196,76 @@ static int cpufreq_stats_create_table(st
count++;
}
+ if (stat->max_state != count) {
+ stat->max_state = count;
+ kfree(stat->time_in_state);
+ stat->time_in_state = NULL;
+ }
+
alloc_size = count * sizeof(int) + count * sizeof(u64);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
alloc_size += count * count * sizeof(int);
#endif
- stat->max_state = count;
- stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
- if (!stat->time_in_state) {
- ret = -ENOMEM;
- goto error_out;
- }
- stat->freq_table = (unsigned int *)(stat->time_in_state + count);
-
+ if (stat->time_in_state) {
+ memset(stat->time_in_state, 0, alloc_size);
+ } else {
+ stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
+ if (!stat->time_in_state)
+ return -ENOMEM;
+ stat->freq_table = (unsigned int *)(
+ stat->time_in_state + count);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
- stat->trans_table = stat->freq_table + count;
+ stat->trans_table = stat->freq_table + count;
#endif
+ }
+
j = 0;
- for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
- if (freq_table_get_index(stat, freq) == -1)
- stat->freq_table[j++] = freq;
+ if (stat->freq_table) {
+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ unsigned int freq = table[i].frequency;
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+ if (freq_table_get_index(stat, freq) == -1)
+ stat->freq_table[j++] = freq;
+ }
}
+
stat->state_num = j;
spin_lock(&cpufreq_stats_lock);
stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur);
spin_unlock(&cpufreq_stats_lock);
+ return 0;
+}
+
+static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *table)
+{
+ unsigned int ret = 0;
+ struct cpufreq_stats *stat;
+ struct cpufreq_policy *data;
+ unsigned int cpu = policy->cpu;
+
+ stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
+ if ((stat) == NULL)
+ return -ENOMEM;
+
+ data = cpufreq_cpu_get(cpu);
+ if (data == NULL) {
+ ret = -EINVAL;
+ goto error_out;
+ }
+ ret = sysfs_create_group(&data->kobj, &stats_attr_group);
cpufreq_cpu_put(data);
+ if (ret)
+ goto error_out;
+
+ stat->cpu = cpu;
+ per_cpu(cpufreq_stats_table, cpu) = stat;
+
return 0;
error_out:
- cpufreq_cpu_put(data);
-error_get_fail:
kfree(stat);
per_cpu(cpufreq_stats_table, cpu) = NULL;
return ret;
@@ -274,10 +283,12 @@ static int cpufreq_stat_notifier_policy(
table = cpufreq_frequency_get_table(cpu);
if (!table)
return 0;
- ret = cpufreq_stats_create_table(policy, table);
- if (ret)
- return ret;
- return 0;
+ if (!per_cpu(cpufreq_stats_table, cpu)) {
+ ret = cpufreq_stats_create_table(policy, table);
+ if (ret)
+ return ret;
+ }
+ return cpufreq_stats_update_table(policy, table);
}
static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
@@ -297,21 +308,23 @@ static int cpufreq_stat_notifier_trans(s
old_index = stat->last_index;
new_index = freq_table_get_index(stat, freq->new);
- /* We can't do stat->time_in_state[-1]= .. */
- if (old_index == -1 || new_index == -1)
- return 0;
-
cpufreq_stats_update(freq->cpu);
-
if (old_index == new_index)
return 0;
+ if (new_index == -1)
+ return 0;
+
spin_lock(&cpufreq_stats_lock);
stat->last_index = new_index;
+ if (old_index != -1) {
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
- stat->trans_table[old_index * stat->max_state + new_index]++;
+ if (stat->trans_table)
+ stat->trans_table[old_index * stat->max_state +
+ new_index]++;
#endif
- stat->total_trans++;
+ stat->total_trans++;
+ }
spin_unlock(&cpufreq_stats_lock);
return 0;
}
@@ -327,10 +340,6 @@ static int __cpuinit cpufreq_stat_cpu_ca
case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu);
break;
- case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
- cpufreq_stats_free_sysfs(cpu);
- break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu);
@@ -339,10 +348,9 @@ static int __cpuinit cpufreq_stat_cpu_ca
return NOTIFY_OK;
}
-/* priority=1 so this will get called before cpufreq_remove_dev */
-static struct notifier_block cpufreq_stat_cpu_notifier __refdata = {
+static struct notifier_block cpufreq_stat_cpu_notifier __refdata =
+{
.notifier_call = cpufreq_stat_cpu_callback,
- .priority = 1,
};
static struct notifier_block notifier_policy_block = {
@@ -392,7 +400,6 @@ static void __exit cpufreq_stats_exit(vo
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
cpufreq_stats_free_table(cpu);
- cpufreq_stats_free_sysfs(cpu);
}
}

View file

@ -0,0 +1,351 @@
From 27ff621cd9a5347efda4be502abbef13a99146ce Mon Sep 17 00:00:00 2001
From: Maarten ter Huurne <maarten@treewalker.org>
Date: Sun, 29 Aug 2010 08:11:00 +0200
Subject: [PATCH 11/21] MIPS: JZ4740: Added setting of PLL rate and main
dividers.
This functionality makes a cpufreq driver possible.
Squashed version of the development done in the jz-2.6.39 branch.
---
arch/mips/jz4740/clock.c | 230 ++++++++++++++++++++++++++++++++++++++++++++--
arch/mips/jz4740/clock.h | 4 +
2 files changed, 224 insertions(+), 10 deletions(-)
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -1,5 +1,8 @@
/*
+ * Copyright (c) 2006-2007, Ingenic Semiconductor Inc.
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * Copyright (c) 2010, Ulrich Hecht <ulrich.hecht@gmail.com>
+ * Copyright (c) 2010, Maarten ter Huurne <maarten@treewalker.org>
* JZ4740 SoC clock support
*
* This program is free software; you can redistribute it and/or modify it
@@ -41,16 +44,20 @@
#define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31)
#define JZ_CLOCK_CTRL_KO_ENABLE BIT(30)
#define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29)
-#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000
#define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22)
#define JZ_CLOCK_CTRL_PLL_HALF BIT(21)
-#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000
#define JZ_CLOCK_CTRL_UDIV_OFFSET 23
#define JZ_CLOCK_CTRL_LDIV_OFFSET 16
#define JZ_CLOCK_CTRL_MDIV_OFFSET 12
#define JZ_CLOCK_CTRL_PDIV_OFFSET 8
#define JZ_CLOCK_CTRL_HDIV_OFFSET 4
#define JZ_CLOCK_CTRL_CDIV_OFFSET 0
+#define JZ_CLOCK_CTRL_UDIV_MASK (0x3f << JZ_CLOCK_CTRL_UDIV_OFFSET)
+#define JZ_CLOCK_CTRL_LDIV_MASK (0x1f << JZ_CLOCK_CTRL_LDIV_OFFSET)
+#define JZ_CLOCK_CTRL_MDIV_MASK (0x0f << JZ_CLOCK_CTRL_MDIV_OFFSET)
+#define JZ_CLOCK_CTRL_PDIV_MASK (0x0f << JZ_CLOCK_CTRL_PDIV_OFFSET)
+#define JZ_CLOCK_CTRL_HDIV_MASK (0x0f << JZ_CLOCK_CTRL_HDIV_OFFSET)
+#define JZ_CLOCK_CTRL_CDIV_MASK (0x0f << JZ_CLOCK_CTRL_CDIV_OFFSET)
#define JZ_CLOCK_GATE_UART0 BIT(0)
#define JZ_CLOCK_GATE_TCU BIT(1)
@@ -90,6 +97,7 @@
#define JZ_CLOCK_PLL_M_OFFSET 23
#define JZ_CLOCK_PLL_N_OFFSET 18
#define JZ_CLOCK_PLL_OD_OFFSET 16
+#define JZ_CLOCK_PLL_STABILIZE_OFFSET 0
#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
@@ -97,10 +105,15 @@
#define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7)
#define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6)
+#define JZ_REG_EMC_RTCNT 0x88
+#define JZ_REG_EMC_RTCOR 0x8C
+
static void __iomem *jz_clock_base;
static spinlock_t jz_clock_lock;
static LIST_HEAD(jz_clocks);
+static void __iomem *jz_emc_base;
+
struct main_clk {
struct clk clk;
uint32_t div_offset;
@@ -204,25 +217,88 @@ static int jz_clk_ko_is_enabled(struct c
return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE);
}
+static struct static_clk jz_clk_ext;
+
+static unsigned long jz_clk_pll_calc_rate(
+ unsigned int in_div, unsigned int feedback, unsigned int out_div)
+{
+ return ((jz_clk_ext.rate / in_div) * feedback) / out_div;
+}
+
+static void jz_clk_pll_calc_dividers(unsigned long rate,
+ unsigned int *in_div, unsigned int *feedback, unsigned int *out_div)
+{
+ unsigned int target;
+
+ /* The frequency after the input divider must be between 1 and 15 MHz.
+ The highest divider yields the best resolution. */
+ *in_div = jz_clk_ext.rate / 1000000;
+ if (*in_div >= 34)
+ *in_div = 33;
+
+ /* The frequency before the output divider must be between 100 and
+ 500 MHz. The lowest target rate is more energy efficient. */
+ if (rate < 25000000) {
+ *out_div = 4;
+ target = 25000000 * 4;
+ } else if (rate <= 50000000) {
+ *out_div = 4;
+ target = rate * 4;
+ } else if (rate <= 100000000) {
+ *out_div = 2;
+ target = rate * 2;
+ } else if (rate <= 500000000) {
+ *out_div = 1;
+ target = rate;
+ } else {
+ *out_div = 1;
+ target = 500000000;
+ }
+
+ /* Compute the feedback divider.
+ Since the divided input is at least 1 MHz and the target frequency
+ at most 500 MHz, the feedback will be at most 500 and will therefore
+ always fit in the 9-bit register.
+ Similarly, the divided input is at most 15 MHz and the target
+ frequency at least 100 MHz, so the feedback will be at least 6
+ where the minimum supported value is 2. */
+ *feedback = ((target / 1000) * *in_div) / (jz_clk_ext.rate / 1000);
+}
+
+static unsigned long jz_clk_pll_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned int in_div, feedback, out_div;
+ /* The PLL frequency must be a multiple of 24 MHz, since the LCD pixel
+ * clock must be exactly 12 MHz for the TV-out to work.
+ * TODO: A multiple of 12 MHz for the PLL would work if the PLL would
+ * not be divided by 2 before being passed to the set of derived
+ * clocks that includes the LCD pixel clock.
+ * TODO: Systemwide decisions like this should be made by the board
+ * support code, so add some kind of hook for that.
+ */
+ unsigned long rate24 = (rate / 24000000) * 24000000;
+
+ jz_clk_pll_calc_dividers(rate24, &in_div, &feedback, &out_div);
+ return jz_clk_pll_calc_rate(in_div, feedback, out_div);
+}
+
static const int pllno[] = {1, 2, 2, 4};
static unsigned long jz_clk_pll_get_rate(struct clk *clk)
{
uint32_t val;
- int m;
- int n;
- int od;
+ unsigned int in_div, feedback, out_div;
val = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
if (val & JZ_CLOCK_PLL_BYPASS)
return clk_get_rate(clk->parent);
- m = ((val >> 23) & 0x1ff) + 2;
- n = ((val >> 18) & 0x1f) + 2;
- od = (val >> 16) & 0x3;
+ feedback = ((val >> 23) & 0x1ff) + 2;
+ in_div = ((val >> 18) & 0x1f) + 2;
+ out_div = pllno[(val >> 16) & 0x3];
- return ((clk_get_rate(clk->parent) / n) * m) / pllno[od];
+ return jz_clk_pll_calc_rate(in_div, feedback, out_div);
}
static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
@@ -235,7 +311,77 @@ static unsigned long jz_clk_pll_half_get
return jz_clk_pll_get_rate(clk->parent) >> 1;
}
-static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+#define SDRAM_TREF 15625 /* Refresh period: 4096 refresh cycles/64ms */
+
+static void sdram_set_pll(unsigned int pllin)
+{
+ unsigned int ns, sdramclock;
+
+ ns = 1000000000 / pllin;
+ sdramclock = (SDRAM_TREF / ns) / 64 + 1;
+ if (sdramclock > 0xff) sdramclock = 0xff;
+ /* Set refresh registers */
+ writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCOR);
+ writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCNT);
+}
+
+static int jz_clk_pll_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned int ctrl, plcr1;
+ unsigned int feedback, in_div, out_div, pllout, pllout2;
+
+ jz_clk_pll_calc_dividers(rate, &in_div, &feedback, &out_div);
+
+ ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
+ pllout = jz_clk_pll_calc_rate(in_div, feedback, out_div);
+ pllout2 = (ctrl & JZ_CLOCK_CTRL_PLL_HALF) ? pllout : (pllout / 2);
+
+ /* Init UHC clock */
+ writel(pllout2 / 48000000 - 1, jz_clock_base + JZ_REG_CLOCK_UHC);
+
+ plcr1 = ((feedback - 2) << JZ_CLOCK_PLL_M_OFFSET) |
+ ((in_div - 2) << JZ_CLOCK_PLL_N_OFFSET) |
+ ((out_div - 1) << JZ_CLOCK_PLL_OD_OFFSET) |
+ (0x20 << JZ_CLOCK_PLL_STABILIZE_OFFSET) |
+ JZ_CLOCK_PLL_ENABLED;
+
+ sdram_set_pll(pllout);
+
+ /* LCD pixclock */
+ writel(pllout2 / 12000000 - 1, jz_clock_base + JZ_REG_CLOCK_LCD);
+
+ /* configure PLL */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (jz_clock_base + JZ_REG_CLOCK_PLL), "r" (plcr1));
+
+ /* MtH: For some reason the MSC will have problems if this flag is not
+ restored, even though the MSC is supposedly the only divider
+ that is not affected by this flag. */
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_CHANGE_ENABLE);
+
+ return 0;
+}
+
+static const unsigned int jz_clk_main_divs[] = {
+ 1, 2, 3, 4, 6, 8, 12, 16, 24, 32
+};
+static const unsigned int jz_clk_main_divs_inv[] = {
+ -1, 0, 1, 2, 3, -1, 4, -1, 5, -1, -1, -1, 6, -1, -1, -1,
+ 7, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1,
+ 9
+};
static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate)
{
@@ -290,6 +436,64 @@ static int jz_clk_main_set_rate(struct c
return 0;
}
+static struct main_clk jz_clk_cpu;
+
+int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv,
+ unsigned int mdiv, unsigned int pdiv)
+{
+ unsigned int cdiv_enc, hdiv_enc, mdiv_enc, pdiv_enc;
+ unsigned int ctrl;
+ unsigned int tmp, wait;
+
+ if (cdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) ||
+ hdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) ||
+ mdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) ||
+ pdiv >= ARRAY_SIZE(jz_clk_main_divs_inv))
+ return -EINVAL;
+ cdiv_enc = jz_clk_main_divs_inv[cdiv];
+ hdiv_enc = jz_clk_main_divs_inv[hdiv];
+ mdiv_enc = jz_clk_main_divs_inv[mdiv];
+ pdiv_enc = jz_clk_main_divs_inv[pdiv];
+ if (cdiv_enc == (unsigned int)-1 ||
+ hdiv_enc == (unsigned int)-1 ||
+ mdiv_enc == (unsigned int)-1 ||
+ pdiv_enc == (unsigned int)-1)
+ return -EINVAL;
+
+ ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
+ ctrl &= ~(JZ_CLOCK_CTRL_CHANGE_ENABLE |
+ JZ_CLOCK_CTRL_CDIV_MASK | JZ_CLOCK_CTRL_HDIV_MASK |
+ JZ_CLOCK_CTRL_MDIV_MASK | JZ_CLOCK_CTRL_PDIV_MASK);
+ if (immediate) ctrl |= JZ_CLOCK_CTRL_CHANGE_ENABLE;
+ ctrl |= (cdiv_enc << JZ_CLOCK_CTRL_CDIV_OFFSET) |
+ (hdiv_enc << JZ_CLOCK_CTRL_HDIV_OFFSET) |
+ (mdiv_enc << JZ_CLOCK_CTRL_MDIV_OFFSET) |
+ (pdiv_enc << JZ_CLOCK_CTRL_PDIV_OFFSET);
+
+ /* set dividers */
+ /* delay loops lifted from the old Ingenic cpufreq driver */
+ wait = ((clk_get_rate(&jz_clk_cpu.clk) / 1000000) * 500) / 1000;
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %2,0(%1)\n\t"
+ "li %0,0\n\t"
+ "1:\n\t"
+ "bne %0,%3,1b\n\t"
+ "addi %0, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ : "=r" (tmp)
+ : "r" (jz_clock_base + JZ_REG_CLOCK_CTRL), "r" (ctrl),
+ "r" (wait));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_main_set_dividers);
+
static struct clk_ops jz_clk_static_ops = {
.get_rate = jz_clk_static_get_rate,
.enable = jz_clk_enable_gating,
@@ -307,6 +511,8 @@ static struct static_clk jz_clk_ext = {
static struct clk_ops jz_clk_pll_ops = {
.get_rate = jz_clk_pll_get_rate,
+ .set_rate = jz_clk_pll_set_rate,
+ .round_rate = jz_clk_pll_round_rate,
};
static struct clk jz_clk_pll = {
@@ -897,6 +1103,10 @@ static int jz4740_clock_init(void)
if (!jz_clock_base)
return -EBUSY;
+ jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100);
+ if (!jz_emc_base)
+ return -EBUSY;
+
spin_lock_init(&jz_clock_lock);
jz_clk_ext.rate = jz4740_clock_bdata.ext_rate;
--- a/arch/mips/jz4740/clock.h
+++ b/arch/mips/jz4740/clock.h
@@ -17,6 +17,7 @@
#define __MIPS_JZ4740_CLOCK_H__
#include <linux/list.h>
+#include <linux/types.h>
struct jz4740_clock_board_data {
unsigned long ext_rate;
@@ -63,6 +64,9 @@ struct clk {
int clk_is_enabled(struct clk *clk);
+int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv,
+ unsigned int mdiv, unsigned int pdiv);
+
#ifdef CONFIG_DEBUG_FS
void jz4740_clock_debugfs_init(void);
void jz4740_clock_debugfs_add_clk(struct clk *clk);

View file

@ -0,0 +1,296 @@
From d0f0d5739a31c12d349980ed05a670fa1e84696d Mon Sep 17 00:00:00 2001
From: Maarten ter Huurne <maarten@treewalker.org>
Date: Wed, 16 Mar 2011 03:16:04 +0100
Subject: [PATCH 12/21] MIPS: JZ4740: Add cpufreq support.
This is a squashed version of Uli's driver that was further developed in the opendingux-kernel repository.
---
arch/mips/Kconfig | 1 +
arch/mips/jz4740/Makefile | 1 +
arch/mips/jz4740/cpufreq.c | 226 ++++++++++++++++++++++++++++++++++++++
arch/mips/kernel/cpufreq/Kconfig | 13 ++-
4 files changed, 240 insertions(+), 1 deletions(-)
create mode 100644 arch/mips/jz4740/cpufreq.c
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -228,6 +228,7 @@ config MACH_JZ4740
select HAVE_PWM
select HAVE_CLK
select GENERIC_IRQ_CHIP
+ select CPU_SUPPORTS_CPUFREQ
config LANTIQ
bool "Lantiq based platforms"
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_JZ4740_QI_LB60) += board-qi
# PM support
obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_CPU_FREQ_JZ) += cpufreq.o
--- /dev/null
+++ b/arch/mips/jz4740/cpufreq.c
@@ -0,0 +1,226 @@
+/*
+ * linux/arch/mips/jz4740/cpufreq.c
+ *
+ * cpufreq driver for JZ4740
+ *
+ * Copyright (c) 2010 Ulrich Hecht <ulrich.hecht@gmail.com>
+ * Copyright (c) 2010 Maarten ter Huurne <maarten@treewalker.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#include <linux/cpufreq.h>
+
+#include <linux/clk.h>
+#include <asm/mach-jz4740/base.h>
+
+#include "clock.h"
+
+#define DEBUG_CPUFREQ
+
+#ifdef DEBUG_CPUFREQ
+#define dprintk(X...) printk(KERN_INFO X)
+#else
+#define dprintk(X...) do { } while(0)
+#endif
+
+#define HCLK_MIN 30000
+/* TODO: The maximum MCLK most likely depends on the SDRAM chips used,
+ so it is board-specific. */
+#define MCLK_MAX 140000
+
+/* Same as jz_clk_main_divs, but with 24 and 32 removed because the hardware
+ spec states those dividers must not be used for CCLK or HCLK. */
+static const unsigned int jz4740_freq_cpu_divs[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+struct jz4740_freq_percpu_info {
+ unsigned int pll_rate;
+ struct cpufreq_frequency_table table[
+ ARRAY_SIZE(jz4740_freq_cpu_divs) + 1];
+};
+
+static struct clk *pll;
+static struct clk *cclk;
+
+static struct jz4740_freq_percpu_info jz4740_freq_info;
+
+static struct cpufreq_driver cpufreq_jz4740_driver;
+
+static void jz4740_freq_fill_table(struct cpufreq_policy *policy,
+ unsigned int pll_rate)
+{
+ struct cpufreq_frequency_table *table = &jz4740_freq_info.table[0];
+ int i;
+
+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
+ /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
+ static bool init = false;
+ if (init)
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ else
+ init = true;
+#endif
+
+ jz4740_freq_info.pll_rate = pll_rate;
+
+ for (i = 0; i < ARRAY_SIZE(jz4740_freq_cpu_divs); i++) {
+ unsigned int freq = pll_rate / jz4740_freq_cpu_divs[i];
+ if (freq < HCLK_MIN) break;
+ table[i].index = i;
+ table[i].frequency = freq;
+ }
+ table[i].index = i;
+ table[i].frequency = CPUFREQ_TABLE_END;
+
+ policy->min = table[i - 1].frequency;
+ policy->max = table[0].frequency;
+
+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
+ cpufreq_frequency_table_get_attr(table, policy->cpu);
+#endif
+}
+
+static unsigned int jz4740_freq_get(unsigned int cpu)
+{
+ return clk_get_rate(cclk) / 1000;
+}
+
+static int jz4740_freq_verify(struct cpufreq_policy *policy)
+{
+ unsigned int new_pll;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
+ new_pll = clk_round_rate(pll, policy->max * 1000) / 1000;
+ if (jz4740_freq_info.pll_rate != new_pll)
+ jz4740_freq_fill_table(policy, new_pll);
+
+ return 0;
+}
+
+static int jz4740_freq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_frequency_table *table = &jz4740_freq_info.table[0];
+ struct cpufreq_freqs freqs;
+ unsigned int new_index = 0;
+ unsigned int old_pll = clk_get_rate(pll) / 1000;
+ unsigned int new_pll = jz4740_freq_info.pll_rate;
+ int ret = 0;
+
+ if (cpufreq_frequency_table_target(policy, table,
+ target_freq, relation, &new_index))
+ return -EINVAL;
+ freqs = (struct cpufreq_freqs) {
+ .old = jz4740_freq_get(policy->cpu),
+ .new = table[new_index].frequency,
+ .cpu = policy->cpu,
+ .flags = cpufreq_jz4740_driver.flags,
+ };
+ if (freqs.new != freqs.old || new_pll != old_pll) {
+ unsigned int cdiv, hdiv, mdiv, pdiv;
+ cdiv = jz4740_freq_cpu_divs[new_index];
+ hdiv = (cdiv == 3 || cdiv == 6) ? cdiv * 2 : cdiv * 3;
+ while (new_pll < HCLK_MIN * hdiv)
+ hdiv -= cdiv;
+ mdiv = hdiv;
+ if (new_pll > MCLK_MAX * mdiv) {
+ /* 4,4 performs better than 3,6 */
+ if (new_pll > MCLK_MAX * 4)
+ mdiv *= 2;
+ else
+ hdiv = mdiv = cdiv * 4;
+ }
+ pdiv = mdiv;
+ dprintk(KERN_INFO "%s: cclk %p, setting from %d to %d, "
+ "dividers %d, %d, %d, %d\n",
+ __FUNCTION__, cclk, freqs.old, freqs.new,
+ cdiv, hdiv, mdiv, pdiv);
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ ret = clk_main_set_dividers(new_pll == old_pll,
+ cdiv, hdiv, mdiv, pdiv);
+ if (ret) {
+ dprintk(KERN_INFO "failed to set dividers\n");
+ } else if (new_pll != old_pll) {
+ dprintk(KERN_INFO "%s: pll %p, setting from %d to %d\n",
+ __FUNCTION__, pll, old_pll, new_pll);
+ ret = clk_set_rate(pll, new_pll * 1000);
+ }
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+
+ return ret;
+}
+
+static int jz4740_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+ int ret;
+
+ dprintk(KERN_INFO "Jz4740 cpufreq driver\n");
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ pll = clk_get(NULL, "pll");
+ if (IS_ERR(pll)) {
+ ret = PTR_ERR(pll);
+ goto err_exit;
+ }
+
+ cclk = clk_get(NULL, "cclk");
+ if (IS_ERR(cclk)) {
+ ret = PTR_ERR(cclk);
+ goto err_clk_put_pll;
+ }
+
+ policy->cpuinfo.min_freq = HCLK_MIN;
+ policy->cpuinfo.max_freq = 500000;
+ policy->cpuinfo.transition_latency = 100000; /* in nanoseconds */
+ policy->cur = jz4740_freq_get(policy->cpu);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ /* min and max are set by jz4740_freq_fill_table() */
+
+ jz4740_freq_fill_table(policy, clk_get_rate(pll) / 1000 /* in kHz */);
+
+ return 0;
+
+err_clk_put_pll:
+ clk_put(pll);
+err_exit:
+ return ret;
+}
+
+static struct cpufreq_driver cpufreq_jz4740_driver = {
+ .init = jz4740_cpufreq_driver_init,
+ .verify = jz4740_freq_verify,
+ .target = jz4740_freq_target,
+ .get = jz4740_freq_get,
+ .name = "jz4740",
+};
+
+static int __init jz4740_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&cpufreq_jz4740_driver);
+}
+
+static void __exit jz4740_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&cpufreq_jz4740_driver);
+}
+
+module_init(jz4740_cpufreq_init);
+module_exit(jz4740_cpufreq_exit);
+
+MODULE_AUTHOR("Ulrich Hecht <ulrich.hecht@gmail.com>, "
+ "Maarten ter Huurne <maarten@treewalker.org>");
+MODULE_DESCRIPTION("cpufreq driver for Jz4740");
+MODULE_LICENSE("GPL");
--- a/arch/mips/kernel/cpufreq/Kconfig
+++ b/arch/mips/kernel/cpufreq/Kconfig
@@ -8,7 +8,7 @@ config MIPS_EXTERNAL_TIMER
config MIPS_CPUFREQ
bool
default y
- depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
+ depends on CPU_SUPPORTS_CPUFREQ
if MIPS_CPUFREQ
@@ -24,6 +24,7 @@ config LOONGSON2_CPUFREQ
tristate "Loongson2 CPUFreq Driver"
select CPU_FREQ_TABLE
depends on MIPS_CPUFREQ
+ depends on MIPS_EXTERNAL_TIMER
help
This option adds a CPUFreq driver for loongson processors which
support software configurable cpu frequency.
@@ -34,6 +35,16 @@ config LOONGSON2_CPUFREQ
If in doubt, say N.
+config CPU_FREQ_JZ
+ tristate "CPUfreq driver for JZ CPUs"
+ select CPU_FREQ_TABLE
+ depends on MACH_JZ4740
+ default n
+ help
+ This enables the CPUfreq driver for JZ CPUs.
+
+ If in doubt, say N.
+
endif # CPU_FREQ
endmenu

View file

@ -0,0 +1,129 @@
From b95144c1b702f98c7902c75beb83f323701eb7c5 Mon Sep 17 00:00:00 2001
From: Maarten ter Huurne <maarten@treewalker.org>
Date: Sun, 19 Jun 2011 10:57:18 +0200
Subject: [PATCH 13/21] MMC: JZ4740: Added support for CPU frequency changing.
The MSC device clock is stopped before the frequency change.
After the change a new divider is computed and the clock is restarted.
Also the frequency change is postponed if an I/O operation is in progress.
---
drivers/mmc/host/jz4740_mmc.c | 69 +++++++++++++++++++++++++++++++++++++++-
1 files changed, 67 insertions(+), 2 deletions(-)
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/scatterlist.h>
#include <linux/clk.h>
+#include <linux/cpufreq.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
@@ -685,6 +686,60 @@ static void jz4740_mmc_enable_sdio_irq(s
jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable);
}
+#ifdef CONFIG_CPU_FREQ
+
+static struct jz4740_mmc_host *cpufreq_host;
+
+static int jz4740_mmc_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ /* TODO: We only have to take action when the PLL freq changes:
+ the main dividers have no influence on the MSC device clock. */
+
+ if (val == CPUFREQ_PRECHANGE) {
+ mmc_claim_host(cpufreq_host->mmc);
+ clk_disable(cpufreq_host->clk);
+ } else if (val == CPUFREQ_POSTCHANGE) {
+ struct mmc_ios *ios = &cpufreq_host->mmc->ios;
+ if (ios->clock)
+ jz4740_mmc_set_clock_rate(cpufreq_host, ios->clock);
+ if (ios->power_mode != MMC_POWER_OFF)
+ clk_enable(cpufreq_host->clk);
+ mmc_release_host(cpufreq_host->mmc);
+ }
+ return 0;
+}
+
+static struct notifier_block jz4740_mmc_cpufreq_nb = {
+ .notifier_call = jz4740_mmc_cpufreq_transition,
+};
+
+static inline int jz4740_mmc_cpufreq_register(struct jz4740_mmc_host *host)
+{
+ cpufreq_host = host;
+ return cpufreq_register_notifier(&jz4740_mmc_cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void jz4740_mmc_cpufreq_unregister(void)
+{
+ cpufreq_unregister_notifier(&jz4740_mmc_cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+
+static inline int jz4740_mmc_cpufreq_register(struct jz4740_mmc_host *host)
+{
+ return 0;
+}
+
+static inline void jz4740_mmc_cpufreq_unregister(void)
+{
+}
+
+#endif
+
static const struct mmc_host_ops jz4740_mmc_ops = {
.request = jz4740_mmc_request,
.set_ios = jz4740_mmc_set_ios,
@@ -834,11 +889,18 @@ static int jz4740_mmc_probe(struct platf
goto err_free_host;
}
+ ret = jz4740_mmc_cpufreq_register(host);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to register cpufreq transition notifier\n");
+ goto err_clk_put;
+ }
+
host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!host->mem) {
ret = -ENOENT;
dev_err(&pdev->dev, "Failed to get base platform memory\n");
- goto err_clk_put;
+ goto err_cpufreq_unreg;
}
host->mem = request_mem_region(host->mem->start,
@@ -846,7 +908,7 @@ static int jz4740_mmc_probe(struct platf
if (!host->mem) {
ret = -EBUSY;
dev_err(&pdev->dev, "Failed to request base memory region\n");
- goto err_clk_put;
+ goto err_cpufreq_unreg;
}
host->base = ioremap_nocache(host->mem->start, resource_size(host->mem));
@@ -929,6 +991,8 @@ err_iounmap:
iounmap(host->base);
err_release_mem_region:
release_mem_region(host->mem->start, resource_size(host->mem));
+err_cpufreq_unreg:
+ jz4740_mmc_cpufreq_unregister();
err_clk_put:
clk_put(host->clk);
err_free_host:
@@ -958,6 +1022,7 @@ static int jz4740_mmc_remove(struct plat
iounmap(host->base);
release_mem_region(host->mem->start, resource_size(host->mem));
+ jz4740_mmc_cpufreq_unregister();
clk_put(host->clk);
platform_set_drvdata(pdev, NULL);

View file

@ -0,0 +1,89 @@
From 8a5087fe59e31efb8641e704058328997c3c8ff1 Mon Sep 17 00:00:00 2001
From: Maarten ter Huurne <maarten@treewalker.org>
Date: Wed, 10 Aug 2011 00:25:11 +0200
Subject: [PATCH 16/21] ASoC: JZ4740: Support buffer size that is not a
multiple of period size.
This fixes glitches triggered by libao, which sets time-based intervals
instead of byte-based intervals like SDL does.
Thanks to Paul Cercueil for figuring out that the buffer size was causing
the glitches and to Lars Clausen for helping me write the fix.
---
sound/soc/jz4740/jz4740-pcm.c | 21 ++++++++++++++++++---
1 files changed, 18 insertions(+), 3 deletions(-)
--- a/sound/soc/jz4740/jz4740-pcm.c
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -31,6 +31,7 @@
struct jz4740_runtime_data {
unsigned long dma_period;
+ unsigned long dma_period_left;
dma_addr_t dma_start;
dma_addr_t dma_pos;
dma_addr_t dma_end;
@@ -67,10 +68,13 @@ static void jz4740_pcm_start_transfer(st
if (prtd->dma_pos == prtd->dma_end)
prtd->dma_pos = prtd->dma_start;
- if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
+ if (prtd->dma_period_left == 0)
+ prtd->dma_period_left = prtd->dma_period;
+
+ if (prtd->dma_pos + prtd->dma_period_left > prtd->dma_end)
count = prtd->dma_end - prtd->dma_pos;
else
- count = prtd->dma_period;
+ count = prtd->dma_period_left;
jz4740_dma_disable(prtd->dma);
@@ -85,6 +89,7 @@ static void jz4740_pcm_start_transfer(st
jz4740_dma_set_transfer_count(prtd->dma, count);
prtd->dma_pos += count;
+ prtd->dma_period_left -= count;
jz4740_dma_enable(prtd->dma);
}
@@ -96,7 +101,8 @@ static void jz4740_pcm_dma_transfer_done
struct snd_pcm_runtime *runtime = substream->runtime;
struct jz4740_runtime_data *prtd = runtime->private_data;
- snd_pcm_period_elapsed(substream);
+ if (prtd->dma_period_left == 0)
+ snd_pcm_period_elapsed(substream);
jz4740_pcm_start_transfer(prtd, substream);
}
@@ -133,6 +139,7 @@ static int jz4740_pcm_hw_params(struct s
runtime->dma_bytes = params_buffer_bytes(params);
prtd->dma_period = params_period_bytes(params);
+ prtd->dma_period_left = 0;
prtd->dma_start = runtime->dma_addr;
prtd->dma_pos = prtd->dma_start;
prtd->dma_end = prtd->dma_start + runtime->dma_bytes;
@@ -160,6 +167,7 @@ static int jz4740_pcm_prepare(struct snd
if (!prtd->dma)
return -EBUSY;
+ prtd->dma_period_left = 0;
prtd->dma_pos = prtd->dma_start;
return 0;
@@ -219,6 +227,13 @@ static int jz4740_pcm_open(struct snd_pc
if (prtd == NULL)
return -ENOMEM;
+ /* Force period and buffer size to be a multiple of the DMA transfer
+ * size, which is 16 bytes. */
+ snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16);
+ snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+
snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
runtime->private_data = prtd;

View file

@ -0,0 +1,26 @@
From 1d7ef3445db5aebf48c90b20e18630633623c750 Mon Sep 17 00:00:00 2001
From: Xiangfu Liu <xiangfu@macbook.(none)>
Date: Fri, 19 Aug 2011 15:46:52 +0800
Subject: [PATCH 20/21] qi_lb60: NAND: add data partition
---
arch/mips/jz4740/board-qi_lb60.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -118,8 +118,13 @@ static struct mtd_partition qi_lb60_part
{
.name = "NAND ROOTFS partition",
.offset = 8 * 0x100000,
- .size = (504 + 512 + 1024) * 0x100000,
+ .size = 512 * 0x100000,
},
+ {
+ .name = "NAND DATA partition",
+ .offset = 520 * 0x100000,
+ .size = 1528 * 0x100000,
+ },
};
static void qi_lb60_nand_ident(struct platform_device *pdev,

View file

@ -0,0 +1,20 @@
From a37ca6eb8cb52d620feff3323a3be4da24f5bee8 Mon Sep 17 00:00:00 2001
From: Xiangfu <xiangfu@openmobilefree.net>
Date: Fri, 16 Mar 2012 17:48:45 +0800
Subject: [PATCH 21/21] rtc: jz4740 fix hwclock give time out
---
drivers/rtc/rtc-jz4740.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
--- a/drivers/rtc/rtc-jz4740.c
+++ b/drivers/rtc/rtc-jz4740.c
@@ -280,6 +280,8 @@ static int jz4740_rtc_probe(struct platf
}
}
+ jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ_IRQ, 1);
+
return 0;
err_free_irq:

View file

@ -0,0 +1,33 @@
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_INPUT_MATRIXKMAP=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_MATRIX=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_ILI8960=y
# CONFIG_LCD_L4F00242T03 is not set
# CONFIG_LCD_LMS283GF05 is not set
# CONFIG_LCD_LTV350QV is not set
# CONFIG_LCD_PLATFORM is not set
# CONFIG_LCD_TDO24M is not set
# CONFIG_LCD_VGG2432A4 is not set
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_CLUT224 is not set
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_REGMAP_SPI=y
CONFIG_SND_HWDEP=y
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
CONFIG_SND_SEQUENCER=y
# CONFIG_SND_SEQUENCER_OSS is not set
CONFIG_SND_SEQ_DUMMY=y
# CONFIG_SND_VIRMIDI is not set
CONFIG_SOUND_OSS_CORE=y
CONFIG_SOUND_OSS_CORE_PRECLAIM=y
CONFIG_SPI=y
CONFIG_SPI_BITBANG=y
CONFIG_SPI_GPIO=y
CONFIG_SPI_MASTER=y
# CONFIG_USB_FUSB300 is not set
CONFIG_USB_JZ4740=y