diff -uNr a/arch/arm/configs/mainstone_defconfig b/arch/arm/configs/mainstone_defconfig --- a/arch/arm/configs/mainstone_defconfig 2004-10-19 05:54:37.000000000 +0800 +++ b/arch/arm/configs/mainstone_defconfig 2005-01-27 09:56:48.000000000 +0800 @@ -1,22 +1,25 @@ # # Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-intc1 +# Wed Jan 12 16:59:54 2005 # CONFIG_ARM=y CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_IOMAP=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y -CONFIG_STANDALONE=y CONFIG_BROKEN_ON_SMP=y # # General setup # +CONFIG_LOCALVERSION="" CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set @@ -29,6 +32,7 @@ # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -36,12 +40,15 @@ CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set # # Loadable module support # CONFIG_MODULES=y -# CONFIG_MODULE_UNLOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_KMOD is not set @@ -49,7 +56,6 @@ # # System Type # -# CONFIG_ARCH_ADIFCC is not set # CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set @@ -59,6 +65,7 @@ # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set # CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set # CONFIG_ARCH_L7200 is not set CONFIG_ARCH_PXA=y # CONFIG_ARCH_RPC is not set @@ -68,6 +75,8 @@ # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_OMAP is not set # CONFIG_ARCH_VERSATILE_PB is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set # # Intel PXA2xx Implementations @@ -75,10 +84,26 @@ # CONFIG_ARCH_LUBBOCK is not set CONFIG_MACH_MAINSTONE=y # CONFIG_ARCH_PXA_IDP is not set + +# +# Intel PXA27x Errata Fixes +# +CONFIG_PXA27x_E11=y +# CONFIG_PXA27x_E17 is not set +CONFIG_PXA27x_E20=y +CONFIG_PXA27x_E23=y +# CONFIG_PXA27x_E25 is not set +CONFIG_PXA27x_E28=y +CONFIG_PXA27x_E37=y +CONFIG_PXA27x_E38=y CONFIG_PXA27x=y CONFIG_IWMMXT=y # +# h720x Implementations +# + +# # Processor Type # CONFIG_CPU_32=y @@ -100,6 +125,16 @@ # CONFIG_ZBOOT_ROM is not set CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y +CONFIG_DVFM=y +CONFIG_FAST_DVFM=y +# CONFIG_CPU_FREQ_PROC_INTF is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set # # PCMCIA/CardBus support @@ -112,10 +147,8 @@ # # At least one math emulation must be selected # -CONFIG_FPE_NWFPE=y -# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_NWFPE is not set # CONFIG_FPE_FASTFPE is not set -# CONFIG_VFP is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_AOUT is not set # CONFIG_BINFMT_MISC is not set @@ -123,13 +156,17 @@ # # Generic Driver Options # +CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set -# CONFIG_PM is not set -# CONFIG_PREEMPT is not set +CONFIG_PM=y +CONFIG_SRAM_ALLOCATE=y +CONFIG_PREEMPT=y +CONFIG_APM=y # CONFIG_ARTHUR is not set -CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=64M" +CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=jffs2 ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on console=ttyS0,115200 mem=128M" +# CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.1.100:/nfs/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on console=ttyS0,115200n8 mem=128M" CONFIG_LEDS=y CONFIG_LEDS_TIMER=y CONFIG_LEDS_CPU=y @@ -148,6 +185,8 @@ CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_CONCAT is not set CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set # CONFIG_MTD_CMDLINE_PARTS is not set # CONFIG_MTD_AFS_PARTS is not set @@ -171,10 +210,12 @@ # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set CONFIG_MTD_CFI_GEOMETRY=y -# CONFIG_MTD_CFI_B1 is not set -# CONFIG_MTD_CFI_B2 is not set -CONFIG_MTD_CFI_B4=y -# CONFIG_MTD_CFI_B8 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set # CONFIG_MTD_CFI_I1 is not set CONFIG_MTD_CFI_I2=y # CONFIG_MTD_CFI_I4 is not set @@ -182,10 +223,10 @@ CONFIG_MTD_CFI_INTELEXT=y # CONFIG_MTD_CFI_AMDSTD is not set # CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access @@ -194,11 +235,13 @@ # CONFIG_MTD_PHYSMAP is not set # CONFIG_MTD_ARM_INTEGRATOR is not set # CONFIG_MTD_EDB7312 is not set +CONFIG_MTD_PXA27x=y # # Self-contained MTD device drivers # # CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set # CONFIG_MTD_BLKMTD is not set @@ -224,6 +267,7 @@ # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set # CONFIG_BLK_DEV_RAM is not set # @@ -257,6 +301,7 @@ # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -282,6 +327,7 @@ # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set # # Network testing @@ -290,7 +336,50 @@ # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set # CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set +CONFIG_IRDA=y + +# +# IrDA protocols +# +# CONFIG_IRLAN is not set +# CONFIG_IRCOMM is not set +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +# CONFIG_IRTTY_SIR is not set + +# +# Dongle support +# + +# +# Old SIR device drivers +# +# CONFIG_IRPORT_SIR is not set + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_SIGMATEL_FIR is not set +CONFIG_PXA_IRDA=y # CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set @@ -325,7 +414,15 @@ # # PCMCIA network device support # -# CONFIG_NET_PCMCIA is not set +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +CONFIG_PCMCIA_3C574=y +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +CONFIG_PCMCIA_XIRC2PS=y +# CONFIG_PCMCIA_AXNET is not set # # Wan interfaces @@ -345,12 +442,14 @@ # # Please see Documentation/ide.txt for help/info on IDE drives # +# CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set CONFIG_BLK_DEV_IDECS=y # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_IDE_TASK_IOCTL is not set # CONFIG_IDE_TASKFILE_IO is not set @@ -366,7 +465,45 @@ # # SCSI device support # -# CONFIG_SCSI is not set +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set # # Fusion MPT device support @@ -375,7 +512,6 @@ # # IEEE 1394 (FireWire) support # -# CONFIG_IEEE1394 is not set # # I2O device support @@ -409,9 +545,9 @@ # CONFIG_GAMEPORT is not set CONFIG_SOUND_GAMEPORT=y CONFIG_SERIO=y -# CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_RAW is not set # # Input Device Drivers @@ -421,6 +557,7 @@ # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set +CONFIG_KEYPAD_MAINSTONE=y # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set @@ -450,7 +587,6 @@ CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_QIC02_TAPE is not set # # IPMI @@ -460,19 +596,28 @@ # # Watchdog Cards # -# CONFIG_WATCHDOG is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_SA1100_WATCHDOG=y + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set +CONFIG_PXA_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set # CONFIG_DRM is not set # @@ -484,12 +629,89 @@ # # I2C support # -# CONFIG_I2C is not set +CONFIG_I2C=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set +CONFIG_I2C_ALGOPXA=y + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_ADAP_PXA=y + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=y +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +CONFIG_SENSORS_ADCM2650=y + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set # # Multimedia devices # -# CONFIG_VIDEO_DEV is not set +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_OVCAMCHIP is not set +CONFIG_PXA_CAMERA_MS=y + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set # # Digital Video Broadcasting Devices @@ -523,8 +745,9 @@ # CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -552,6 +775,13 @@ CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 # CONFIG_JFFS2_FS_NAND is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +CONFIG_JFFS2_RUBIN=y +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -563,15 +793,17 @@ # Network File Systems # CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set +CONFIG_NFS_V3=y # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y # CONFIG_EXPORTFS is not set CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set @@ -581,14 +813,29 @@ # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set # # Native Language Support # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -636,7 +883,11 @@ # Graphics support # CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y CONFIG_FB_PXA=y +CONFIG_FB_PXA_LCD_QVGA=y +# CONFIG_FB_PXA_LCD_VGA is not set +CONFIG_FB_PXA_OVERLAY=y # CONFIG_FB_PXA_PARAMETERS is not set # CONFIG_FB_VIRTUAL is not set @@ -644,10 +895,8 @@ # Console display driver support # # CONFIG_VGA_CONSOLE is not set -# CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -663,7 +912,31 @@ # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +# CONFIG_SND is not set + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set +# CONFIG_SOUND_AD1980 is not set +CONFIG_SOUND_PXA=y +CONFIG_SOUND_PXA_AC97=y +CONFIG_SOUND_UCB1X00=y +CONFIG_SOUND_UCB1X00_TS=y # # Misc devices @@ -672,24 +945,196 @@ # # USB support # +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_MIDI is not set +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DEBUG=y +# CONFIG_USB_STORAGE_RW_DETECT is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_STV680 is not set + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_GENESYS is not set +# CONFIG_USB_NET1080 is not set +# CONFIG_USB_PL2301 is not set + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_ZAURUS is not set +# CONFIG_USB_CDCETHER is not set + +# +# USB Network Adapters +# +# CONFIG_USB_AX8817X is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set # # USB Gadget Support # -# CONFIG_USB_GADGET is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +CONFIG_USB_GADGET_PXA27X=y +CONFIG_USB_PXA27X=y +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_SA1100 is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +# CONFIG_USB_ZERO is not set +CONFIG_USB_ETH=y +# CONFIG_USB_ETH_RNDIS is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set # # Kernel hacking # -CONFIG_FRAME_POINTER=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_INFO=y CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SLAB is not set CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_WAITQ is not set CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_WAITQ is not set CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y # CONFIG_DEBUG_ICEDCC is not set @@ -707,6 +1152,7 @@ # # Library routines # +CONFIG_CRC_CCITT=y CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y diff -uNr a/arch/arm/Kconfig b/arch/arm/Kconfig --- a/arch/arm/Kconfig 2004-10-19 05:54:31.000000000 +0800 +++ b/arch/arm/Kconfig 2005-01-27 09:56:48.000000000 +0800 @@ -357,7 +357,7 @@ config CPU_FREQ bool "Support CPU clock change (EXPERIMENTAL)" - depends on (ARCH_SA1100 || ARCH_INTEGRATOR) && EXPERIMENTAL + depends on (ARCH_SA1100 || ARCH_INTEGRATOR || MACH_MAINSTONE) && EXPERIMENTAL help CPU clock scaling allows you to change the clock speed of the running CPU on the fly. This is a nice method to save battery power, @@ -393,7 +393,17 @@ If in doubt, say Y. -if (CPU_FREQ_INTEGRATOR) || (CPU_FREQ_SA1110) || (CPU_FREQ_SA1100) +config DVFM + bool + depends on CPU_FREQ + default y + +config FAST_DVFM + bool + depends on DVFM + default y + +if (CPU_FREQ_INTEGRATOR) || (CPU_FREQ_SA1110) || (CPU_FREQ_SA1100) || (DVFM) source "drivers/cpufreq/Kconfig" @@ -478,6 +488,13 @@ will issue the hlt instruction if nothing is to be done, thereby sending the processor to sleep and saving power. +config SRAM_ALLOCATE + bool "PXA27x SRAM Allocation Support" if ARCH_PXA + depends on ARCH_PXA + help + If you say Y here , the system will support dynamic allocation into + the sram region. + config PREEMPT bool "Preemptible Kernel (EXPERIMENTAL)" depends on CPU_32 && EXPERIMENTAL diff -uNr a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S --- a/arch/arm/kernel/entry-armv.S 2004-10-19 05:53:46.000000000 +0800 +++ b/arch/arm/kernel/entry-armv.S 2005-01-27 09:56:48.000000000 +0800 @@ -638,7 +638,22 @@ and \irqstat, \irqstat, \irqnr clz \irqnr, \irqstat rsb \irqnr, \irqnr, #(31 - PXA_IRQ_SKIP) +#ifdef CONFIG_PXA27x + b 1002f +#endif 1001: +#ifdef CONFIG_PXA27x + mrc p6, 0, \irqstat, c6, c0, 0 @ ICIP2 + mrc p6, 0, \irqnr, c7, c0, 0 @ ICMR2 + ands \irqstat, \irqstat, \irqnr + beq 1002f + rsb \irqnr, \irqstat, #0 + and \irqstat, \irqstat, \irqnr + clz \irqnr, \irqstat + rsb \irqnr, \irqnr, #31 + add \irqnr, \irqnr, #(32 - PXA_IRQ_SKIP) +1002: +#endif .endm .macro irq_prio_table diff -uNr a/arch/arm/mach-pxa/cpu-freq-pxa27x.c b/arch/arm/mach-pxa/cpu-freq-pxa27x.c --- a/arch/arm/mach-pxa/cpu-freq-pxa27x.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/cpu-freq-pxa27x.c 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,678 @@ +/* + * CPUfreq driver for PXA27x + * + * cpufreq driver for PXA27x by Chao Xie + * Copyright (C) 2004, Intel Corporation + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu-freq-voltage-pxa27x.h" + +#define N_NUM 8 +#define L_NUM 31 + +#define CPUFREQ_SET_BASE (0x1 << 8) +#define CPUFREQ_SET_FREQ CPUFREQ_SET_BASE << 0x1 +#define CPUFREQ_SET_B CPUFREQ_SET_BASE << 0x2 +#define CPUFREQ_SET_T_HT CPUFREQ_SET_BASE << 0x3 +#define CPUFREQ_SET_A CPUFREQ_SET_BASE << 0x4 + +#define MSC0_MASK 0x7ff07ff0 +#define DRI_MASK 0xfff + +struct pxa27x_mem_set { + unsigned int memc_clock; + unsigned int msc0; + unsigned int dri; +}; + +static struct pxa27x_mem_set mem_op_val[] = { + {13000, 0x11101110, 0x002}, + {91000, 0x12701270, 0x015}, + {104000, 0x12801280, 0x018}, + {208000, 0x15d015d0, 0x031}, + {0, 0, 0}, +}; + +static unsigned int cpufreq_matrix[N_NUM-1][L_NUM-1]; +static unsigned int cpufreq_cur; +static DECLARE_MUTEX (pxa27x_freq_sem); + +struct cpufreq_info { + unsigned int l; + unsigned int n2; + unsigned int b; + unsigned int t; + unsigned int a; +}; + +static struct cpufreq_info cpufreq_mode; + +extern unsigned int get_clk_frequency_khz(int); +extern int pxa27x_set_voltage(unsigned int, unsigned int, unsigned int); +extern unsigned int pxa27x_get_voltage(void); +extern struct cpufreq_governor cpufreq_gov_performance; + +static int pxa27x_cpufreq_governor(struct cpufreq_policy *policy, + unsigned int event) +{ + return 0; +} + +static struct cpufreq_governor pxa27x_cpufreq_gov = { + .name = "pxa27x_governor", + .governor = pxa27x_cpufreq_governor, + .owner = THIS_MODULE, +}; + +static inline int set_mode(unsigned int l, unsigned int n2, unsigned int b, + unsigned int t, unsigned int a) +{ + unsigned int ret = 0; + + if (n2 == cpufreq_mode.n2 && l == cpufreq_mode.l && b == cpufreq_mode.b + && t == cpufreq_mode.t && a == cpufreq_mode.a) + return 0; + if (l == cpufreq_mode.l && n2 == cpufreq_mode.n2) { + if (b != cpufreq_mode.b) + ret |= CPUFREQ_SET_B; + if (t != cpufreq_mode.t) + ret |= CPUFREQ_SET_T_HT; + if (a != cpufreq_mode.a) + ret |= CPUFREQ_SET_A; + } + else { + ret |= CPUFREQ_SET_FREQ; + cpufreq_mode.l = l; + cpufreq_mode.n2 = n2; + } + cpufreq_mode.b = b; + cpufreq_mode.t = t; + cpufreq_mode.a = a; + return ret; +} + +#ifdef CONFIG_FAST_DVFM +void pxa27x_setspeed(unsigned int CLKCFGValue) +#else +static void pxa27x_setspeed(unsigned int CLKCFGValue) +#endif +{ + unsigned long flags; + unsigned int unused; + + /* NOTE: IRQs are already turned off in dpm idle, so it is not + necessary to do it here. */ + local_irq_save(flags); + + __asm__ __volatile__(" \n\ + ldr r4, [%1] @load MDREFR \n\ + mcr p14, 0, %2, c6, c0, 0 @ set CCLKCFG[FCS] \n\ + ldr r5, =0xe3dfefff \n\ + and r4, r4, r5 \n\ + str r4, [%1] @restore \n\ + " + : "=&r" (unused) + : "r" (&MDREFR), "r" (CLKCFGValue) + : "r4", "r5"); + + /* NOTE: if we don't turn off IRQs up top, there is no point + to restoring them here. */ + local_irq_restore(flags); +} +#ifdef CONFIG_FAST_DVFM +EXPORT_SYMBOL(pxa27x_setspeed); +#endif + +#ifdef CONFIG_FAST_DVFM +extern void pxafb_wait_for_eof(unsigned int); +#else +extern void pxafb_wait_for_eof(void); +#endif + +static void pxa27x_change_freq(unsigned int CLKCFGvalue) +{ +#ifdef CONFIG_FAST_DVFM + pxafb_wait_for_eof(CLKCFGvalue); +#else + pxafb_wait_for_eof(); + pxa27x_setspeed(CLKCFGvalue); +#endif +} + +static void pxa27x_set_mem_before_freq(unsigned int memc_clock, + unsigned int *pmdrefr, unsigned int *pmsc0, unsigned int *pdri) +{ + int i = 0; + + while(mem_op_val[i].memc_clock < memc_clock && mem_op_val[i].memc_clock != 0) + i++; + /* if current msc0 > next msc0, change after */ + if ( (MSC0 & MSC0_MASK) > mem_op_val[i].msc0) { + *pmsc0 = mem_op_val[i].msc0; + } + else { + *pmsc0 = 0; + MSC0 = (MSC0 & ~MSC0_MASK) | mem_op_val[i].msc0; + } + /* if current dri > next dri, change after */ + if ( (MDREFR & DRI_MASK) > mem_op_val[i].dri) { + *pdri = mem_op_val[i].dri; + } + else { + *pdri = 0; + MDREFR = (MDREFR & ~DRI_MASK) | mem_op_val[i].dri; + } + + if (memc_clock > 104000) { + /* K1DB2, K2DB2 set; memc/2 for sdram */ + /* K0DB4 set; memc/4 for flash */ + MDREFR |= ((1 << 14) | (1 << 17) | (1 << 19) | (1 << 29)); + *pmdrefr = 0; + } + else if (memc_clock > 52000) { + MDREFR |= (1 << 14); + /* K1DB2, K2DB2 will be clear; memc for sdram */ + /* K0DB4 will be clear; memc/2 for flash */ + *pmdrefr = (1 << 17) | (1 << 19) | (1 << 29); + } + else { + /* memc for flash and sdram*/ + *pmdrefr = (1 << 14) | (1 << 17) | (1 << 19) | (1 << 29); + } + +} + +void pxa27x_set_mem_after_freq(unsigned int mdrefr, unsigned int msc0, + unsigned int dri) +{ + if (mdrefr || dri) + MDREFR = (MDREFR & (~DRI_MASK | mdrefr)) | dri; + if (msc0) + MSC0 = (MSC0 & ~MSC0_MASK) | msc0; +} + +/* turbo_mode_flag = 2 : indicates Turbo + * turbo_mode_flag = 1 : indicates HalfTurbo + */ +static void pxa27x_set_core_freq(unsigned int l, unsigned int n2, + unsigned int fast_bus_mode_flag, + unsigned int turbo_mode_flag, + unsigned int memc_clock_flag, + unsigned int relation) +{ + int CLKCFGValue = 0; + int turbo_mode = 0; + int memc_clock, m, l_pll; + unsigned int mdrefr, msc0, dri; + + if (turbo_mode_flag == 2) + turbo_mode = 1; + else if (turbo_mode_flag == 1) + turbo_mode = 1 << 2; + + m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4; + l_pll = l*13000; + memc_clock = (!memc_clock_flag) ? (l_pll/m) : ((fast_bus_mode_flag) ? l_pll : (l_pll/2)); + pxa27x_set_mem_before_freq(memc_clock, &mdrefr, &msc0, &dri); + /* SDRAM can not be greater than 104Mhz, and flash can not be greater + than 52Mhz*/ + if (relation & (CPUFREQ_SET_FREQ | CPUFREQ_SET_B | CPUFREQ_SET_A)) { + CCCR = (n2 << 7) | l | (memc_clock_flag << 25); + + /* set up the new CLKCFG value, for an new frequency */ + /* 0x2 is used to set FC bit in CLKCFG. */ + CLKCFGValue = ( 0x2 | (fast_bus_mode_flag << 3) | turbo_mode); + } + else { + CLKCFGValue = (fast_bus_mode_flag << 3) | turbo_mode; + } + + /* + * Program the CLKCFG (CP14, reigster 6) for frequency change + */ + pxa27x_change_freq(CLKCFGValue); + pxa27x_set_mem_after_freq(mdrefr, msc0, dri); +} + +unsigned int pxa27x_read_clkcfg(void) +{ + unsigned int value=0; + unsigned int un_used; + + __asm__ __volatile__("mrc p14, 0, %1, c6, c0, 0" :"=&r" (un_used) + :"r" (value)); + + return value; +} +EXPORT_SYMBOL_GPL(pxa27x_read_clkcfg); + +#define CCCR_CPDIS_BIT_ON (1 << 31) +#define CCCR_PPDIS_BIT_ON (1 << 30) +#define CCCR_PLL_EARLY_EN_BIT_ON (1 << 26) +#define CCCR_LCD_26_BIT_ON (1 << 27) + +static int old_clkcfg; +static int old_mdrefr; +static int old_msc0; +static int enter_13M(void) +{ + int cccr; + int clkcfg; + + if (CCCR & (1 << 31)) + return 1; + old_clkcfg = pxa27x_read_clkcfg(); + old_mdrefr = MDREFR; + old_msc0 = MSC0; +#ifdef CONFIG_13M_TWOSTEP + if (old_clkcfg & 0x5) { + pxa27x_setspeed(old_clkcfg & 0x8); + cccr = CCCR; + while (pxa27x_read_clkcfg() != (old_clkcfg & 0x8)) + ; + + } +#endif + cccr = CCCR; + cccr |= CCCR_CPDIS_BIT_ON; + cccr &= ~CCCR_PPDIS_BIT_ON; + cccr |= CCCR_LCD_26_BIT_ON; + CCCR = cccr; + LCCR4 |= (1 << 25); + pxa27x_setspeed(0x2); + MDREFR = (MDREFR & ~((1 << 14) | (1 << 17) | (1 << 19) | (1 << 29) | DRI_MASK)) | 0x002; + /* maybe this can optmize 13Mhz */ + MSC0 = (MSC0 & ~MSC0_MASK) | 0x11101110; + return 0; +} + +/* using new L, N2 to enbale CPDIS first, then change frequency */ +static void exit_13M_change_freq(unsigned int l, unsigned int n2, + unsigned int fast_bus_mode_flag, + unsigned int turbo_mode_flag, + unsigned int memc_clock_flag) +{ + int cccr, ccsr, clkcfg; + unsigned int time_delay; + + if (!(CCCR & (1 << 31))) + return; + + clkcfg = 0x2; + if (turbo_mode_flag) + clkcfg |= 0x1; + if (fast_bus_mode_flag) + clkcfg |= (0x1 << 3); + + cccr = CCCR; + cccr |= (CCCR_CPDIS_BIT_ON | CCCR_PLL_EARLY_EN_BIT_ON); + /* clear L and 2N, A bit */ + cccr &= ~(0x3ffffff); + cccr |= l | n2 << 7 | (memc_clock_flag << 25); + CCCR = cccr; + + /* Step 2 */ + cccr = CCCR; + if ((cccr & 0x84000000) != 0x84000000) { /* CPDIS, pll_early_en */ + printk("DPM: Warning: CPDIS or PLL_EARLY_EN not on\n"); + } + time_delay = OSCR; + while ((OSCR - time_delay) < 390) + ; + /* Step 3 */ + while ((CCSR & 0x30000000) == 0x30000000) + break; + /* Step 4: NOP */ + + /* Step 5 */ + /* Now clear the PLL disable bits */ + /* But leave EARLY_EN on; it will be cleared by the frequency change */ + cccr &= ~(CCCR_CPDIS_BIT_ON | CCCR_PPDIS_BIT_ON); /* Not ON */ + cccr |= CCCR_PLL_EARLY_EN_BIT_ON; + CCCR = cccr; + MDREFR = old_mdrefr; + MSC0 = old_msc0; +#ifdef CONFIG_13M_TWOSTEP + pxa27x_setspeed(0x2); +#endif + LCCR4 &= ~((1 << 25)); +#ifdef CONFIG_13M_TWOSTEP + cccr = CCCR; + while(pxa27x_read_clkcfg() != 0x2) + ; + if (turbo_mode_flag || fast_bus_mode_flag) { + CKEN &= ~CKEN16_LCD; + pxa27x_setspeed(clkcfg); + CKEN |= CKEN16_LCD; + } +#else + pxa27x_setspeed(clkcfg); +#endif +} + +void pxa27x_cpufreq_restore(void) +{ + int CLKCFGValue = 0; + int turbo_mode = 0; + int m, l_pll, memc_clock; + unsigned int mdrefr, msc0, dri; + + if (cpufreq_cur == 13000) { + enter_13M(); + return; + } + m = (cpufreq_mode.l <= 10) ? 1 : (cpufreq_mode.l <= 20) ? 2 : 4; + l_pll = cpufreq_mode.l*13000; + memc_clock = (!cpufreq_mode.a) ? (l_pll/m) : ((cpufreq_mode.b) ? l_pll : (l_pll/2)); + pxa27x_set_mem_before_freq(memc_clock, &mdrefr, &msc0, &dri); + if (cpufreq_mode.t == 2) + turbo_mode = 1; + else if (cpufreq_mode.t == 1) + turbo_mode = 1 << 2; + + CCCR = (cpufreq_mode.n2 << 7) | cpufreq_mode.l | (cpufreq_mode.a << 25); + CLKCFGValue = ( 0x2 | (cpufreq_mode.b << 3) | turbo_mode); + pxa27x_setspeed(CLKCFGValue); + pxa27x_set_mem_after_freq(mdrefr, msc0, dri); +} +EXPORT_SYMBOL_GPL(pxa27x_cpufreq_restore); + +static int pxa27x_cpufreq_init(struct cpufreq_policy *policy) +{ + unsigned int n2, l; + + /* we only have one CPU */ + if (policy->cpu != 0) + return -EINVAL; + /* init policy */ + policy->cur = cpufreq_cur; + /* we use CPU limits as default */ + policy->min = PXA27X_MIN_FREQ; + policy->max = PXA27X_MAX_FREQ; + policy->cpuinfo.min_freq = PXA27X_MIN_FREQ; + policy->cpuinfo.max_freq = PXA27X_MAX_FREQ; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + /* Only simple governer is needed. Directly using pxa27x + * governor. In fact it is a NULL governor. + */ + policy->governor = &pxa27x_cpufreq_gov; + /* based on manual to set freq table */ + memset(&cpufreq_matrix, 0 ,sizeof(cpufreq_matrix)); + for (n2 = 2; n2 <= N_NUM; n2++) { + for (l = 2; l <= L_NUM; l++) { + cpufreq_matrix[n2-2][l-2] = n2*l*6500; + if( cpufreq_matrix[n2-2][l-2] > PXA27X_MAX_FREQ ) + cpufreq_matrix[n2-2][l-2] = 0; + } + } + return 0; +} + +static int pxa27x_cpufreq_exit(struct cpufreq_policy *policy) +{ + return 0; +} + +/* the frequency is gotten form L, N base on cpufreq_matrix */ +static int pxa27x_cpufreq_verify(struct cpufreq_policy *policy) +{ + if (policy->min < PXA27X_MIN_FREQ || policy->max > PXA27X_MAX_FREQ) + return -1; + return 0; +} + +/* every time invoke the function, frequency is set even nothing has changed */ +static int pxa27x_cpufreq_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int n2, l, b, t = 0, a; + struct cpufreq_freqs freqs; + + freqs.cpu = 0; + freqs.old = cpufreq_cur; + freqs.new = target_freq; + + if (target_freq == 13000) { + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + enter_13M(); + cpufreq_cur = target_freq; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + calibrate_delay(); + return 0; + } + l = cpufreq_mode.l; + n2 = cpufreq_mode.n2; + b = cpufreq_mode.b; + t = cpufreq_mode.t; + a = cpufreq_mode.a; + +/* System hang when enabling RUN/TURBO switching at 520MHZ */ +#ifdef CONFIG_PXA27x_E37 + if (target_freq == 520000 && (relation & CPUFREQ_SET_T_HT)) { + printk("Workround for E37 about enabling RUN/TURBO switching at 520MHZ.\n If you want to disable workround, DO NOT set \"CONFIG_PXA27x_E37=y\"\n"); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + enter_13M(); + exit_13M_change_freq(l, n2, b, t, a); + cpufreq_cur = target_freq; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + calibrate_delay(); + return 0; + } +#endif + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + /* Using CCCR to make sure it is 13M */ + if ((cpufreq_cur == 13000) && (CCSR & (1 << 31))) + exit_13M_change_freq(l, n2, b, t, a); + else + pxa27x_set_core_freq(l, n2, b, t, a, relation); + cpufreq_cur = target_freq; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + calibrate_delay(); + return 0; + +} +static unsigned int pxa27x_get_cur_freq(unsigned int cpu) +{ + if (cpu) + return 0; + return get_clk_frequency_khz(0); +} + +static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf) +{ + unsigned int n2, l, count = 0; + + count += sprintf(&buf[count], "%s\t%s\t%s\n", "L", "2N", "Freq"); + for (n2 = 2; n2 <= N_NUM ; n2++) { + for (l = 2; l <= L_NUM; l++) { + if (cpufreq_matrix[n2-2][l-2] >= policy->min + && cpufreq_matrix[n2-2][l-2] <= policy->max) + count += sprintf(&buf[count], "%d\t%d\t%d\n", l, + n2, cpufreq_matrix[n2-2][l-2]); + } + } + return count; +} + +static struct freq_attr pxa27x_available_freqs = { + .attr = { .name = "scaling_available_frequencies", .mode = 0444 }, + .show = show_available_freqs, +}; + +static ssize_t show_freq_voltage (struct cpufreq_policy *policy, char *buf) +{ + int i = 0, count = 0; + + count += sprintf(&buf[count], "%s\t%s\n", "Freq", "Vol"); + while (ipm_fv_table[i].freq != 0 ) { + count += sprintf(&buf[count], "%u\t%u\n", ipm_fv_table[i].freq, ipm_fv_table[i].voltage); + i++; + } + return count; +} + +static struct freq_attr pxa27x_freq_voltage = { + .attr = { .name = "show_frequency_and_voltage", .mode = 0444 }, + .show = show_freq_voltage, +}; + +static ssize_t show_cpu_voltage (struct cpufreq_policy *policy, char *buf) +{ + unsigned int vol, count; + + vol = pxa27x_get_voltage(); + count = sprintf(&buf[0], "%dmv\n", vol); + return count; +} + +static ssize_t store_cpu_voltage (struct cpufreq_policy *policy, + const char *buf, size_t count) +{ + unsigned int vol, ret, n; + + n = sscanf(buf, "%u", &vol); + ret = pxa27x_set_voltage(cpufreq_cur, vol, 0); + if (ret < 0) { + printk(KERN_ERR "Error:Wrong voltage"); + } + return count; +} + +static struct freq_attr pxa27x_cpu_voltage = { + .attr = { .name = "cpu-voltage", .mode = 0644 }, + .show = show_cpu_voltage, + .store = store_cpu_voltage, +}; + +static struct freq_attr* pxa27x_attr[] = { + &pxa27x_available_freqs, + &pxa27x_cpu_voltage, + &pxa27x_freq_voltage, + NULL, +}; + +static struct cpufreq_driver pxa27x_cpufreq_driver = { + .name = "pxa27x", /* there's a 16 char limit */ + .flags = CPUFREQ_CONST_LOOPS, + .init = pxa27x_cpufreq_init, + .exit = pxa27x_cpufreq_exit, + .verify = pxa27x_cpufreq_verify, + .target = pxa27x_cpufreq_target, + .get = pxa27x_get_cur_freq, + .attr = pxa27x_attr, + .owner = THIS_MODULE, +}; + +/* + * validate l, n2 , b, t +*/ +int pxa27x_validate(unsigned int l, unsigned int n2, unsigned int b, + unsigned int t, unsigned int a) +{ + printk("L:%u, 2N:%u, b:%u, t:%u\n", l, n2 , b, t); +#ifdef CONFIG_PXA27x_E38 + if (t == 1) { + printk("HaltTurbo mode is disabled because it may hang the system.\n If you want to enbale it, DO NOT set \"CONFIG_PXA27x_E38=y\"\n"); + return -EINVAL; + } +#endif + /* This is 13M mode */ + if (b > 1 || t > 2 || a > 1) + return -EINVAL; + if (l == 1 && n2 == 2 && b == 0 && t == 0) + return 0; + if ((n2 > N_NUM) || (n2 < 2)) + return -EINVAL; + if (l < 2 || l > L_NUM) + return -EINVAL; + /* when B = 1, Max L = 16 */ + if (b && l > 16) + return -EINVAL; + if (t == 1 && (n2 != 6 && n2 != 8)) + return -EINVAL; + if (cpufreq_matrix[n2-2][l-2] == 0) + return -EINVAL; + return 0; +} + +EXPORT_SYMBOL(pxa27x_validate); +/* + * The interface for other module to change the frequency. + * If freq, n2, turbo, b, a are same as before, no frequency change occurs. + */ +int pxa27x_set_cpufreq(unsigned int l, unsigned int n2, unsigned int b, + unsigned int t, unsigned int a) +{ + struct cpufreq_policy policy; + int ret = 0; + unsigned int freq; + + down(&pxa27x_freq_sem); + ret = set_mode(l, n2, b, t, a); + if (!ret) { + up(&pxa27x_freq_sem); + return ret; + } + policy.cpu = 0; + freq = l*((t == 0)? 13000 : ((t == 2)? 6500*n2 : 3250*n2)); + printk("Set frequency to %u with L:%u, 2N:%u, B:%u, %s, A:%u\n", freq, + l, n2, b, (t==0)? "Run mode":(t==2)? "Turbo Mode":"Half Turbo mode", a); + ret = cpufreq_driver_target(&policy, freq, ret); + up(&pxa27x_freq_sem); + return ret; +} + +EXPORT_SYMBOL(pxa27x_set_cpufreq); + +static int __init pxa27x_init_cpufreq(void) +{ + unsigned int clkcfg, ccsr, cccr, l, n2, b, t, a; + int ret; + + ret = cpufreq_register_governor(&pxa27x_cpufreq_gov); + if (ret) + return ret; + clkcfg = pxa27x_read_clkcfg(); + ccsr = CCSR; + cccr = CCCR; + cpufreq_cur = get_clk_frequency_khz(0); + l = ccsr & 0x1F; + n2 = (ccsr >> 7) & 0xF; + b = clkcfg & (0x1 << 3); + t = (clkcfg & 0x1)? 2: (clkcfg & (0x1 << 2))? 1:0; + a = (cccr >> 25) & 0x1; + set_mode(l, n2, b, t, a); + return cpufreq_register_driver(&pxa27x_cpufreq_driver); +} + +static void __exit pxa27x_exit_cpufreq(void) +{ + cpufreq_unregister_driver(&pxa27x_cpufreq_driver); + cpufreq_unregister_governor(&pxa27x_cpufreq_gov); +} + +MODULE_AUTHOR ("Chao Xie "); +MODULE_DESCRIPTION ("cpufreq driver for Intel pxa27x."); +MODULE_LICENSE ("GPL"); + +late_initcall(pxa27x_init_cpufreq); +module_exit(pxa27x_exit_cpufreq); + diff -uNr a/arch/arm/mach-pxa/cpu-freq-voltage-pxa27x.h b/arch/arm/mach-pxa/cpu-freq-voltage-pxa27x.h --- a/arch/arm/mach-pxa/cpu-freq-voltage-pxa27x.h 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/cpu-freq-voltage-pxa27x.h 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2003-2004 Intel Corporation. + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + */ + +#ifndef CPU_FREQ_VOLTAGE_PXA27x_H +#define CPU_FREQ_VOLTAGE_PXA27x_H + +#define PXA27X_MAX_VOL 1500 /* in mV. */ +#define PXA27X_MIN_VOL 900 /* in Mv. */ +#define PXA27X_DEFAULT_VOL 1500 /* the default voltage. */ + +#define PXA27X_MIN_FREQ 13000 +#define PXA27X_MAX_FREQ 624000 + +struct fv_table { + unsigned int freq; + unsigned int voltage; +}; +extern struct fv_table ipm_fv_table[]; +#endif diff -uNr a/arch/arm/mach-pxa/cpu-voltage-pxa27x.c b/arch/arm/mach-pxa/cpu-voltage-pxa27x.c --- a/arch/arm/mach-pxa/cpu-voltage-pxa27x.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/cpu-voltage-pxa27x.c 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,199 @@ +/* + * + * Bulverde voltage change driver. + * + * Author: Cain Yuan + * + * Upgrade for 2.6 kernel by Chao Xie + * + * Copyright (C) 2003-2004 Intel Corporation. + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cpu-freq-voltage-pxa27x.h" + +/* + * Transfer desired mv to required DAC value. + * Vcore = 1.5v - ( 587uv * DACIn ) + */ +#define MV2DAC(mv) ((1500-mv)*1000/587) +struct fv_table ipm_fv_table[] = { + {26000, 900}, + {104000, 1100}, + {208000, 1200}, + {312000, 1300}, + {416000, 1400}, + {520000, 1500}, + {624000, 1500}, + {0, 0} +}; + +static unsigned int cpuvoltage_cur = PXA27X_DEFAULT_VOL; +static DECLARE_MUTEX (pxa27x_voltage_sem); + +extern void vm_setvoltage(unsigned int); +extern void vm_pre_setvoltage(unsigned int); + +static unsigned int mv2DAC(unsigned int mv) +{ + if (mv > PXA27X_MAX_VOL) + return MV2DAC(mv); + if (mv < PXA27X_MIN_VOL) + return MV2DAC(mv); + return MV2DAC(mv); +} + +static int check_voltage(unsigned int freq, unsigned int vol) +{ + int i = 0; + + printk("check:freq %u, vol %u",freq, vol); + while (ipm_fv_table[i].freq != 0 ) { + if (freq <= ipm_fv_table[i].freq) { + if(vol < ipm_fv_table[i].voltage) { + printk(KERN_WARNING "Warnning: CPU voltage is lower than standard, may cause error.\n"); + return 1; + } + else + return 0; + } + i++; + } + printk(KERN_ERR "Error: Can not find the voltage for frequency %u.\n", freq); + return -EINVAL; +} + +unsigned int pxa27x_find_voltage(unsigned int freq) +{ + int i = 0; + + while (ipm_fv_table[i].freq != 0 ) { + if (freq <= ipm_fv_table[i].freq) { + return ipm_fv_table[i].voltage; + } + i++; + } + return 0; +} +EXPORT_SYMBOL_GPL(pxa27x_find_voltage); + +/* + * According to bulverde's manual, set the core's voltage. + * mv == 0 indicates using default voltage arrcording frequency. + * If mv == cpuvoltage_cur, no voltage change happens. Because there + * is no convenient way of reading back voltage, it is important to mainstain + * cpuvoltage_cur correctly. + * combo == 0 means this is seperated voltage change process, otherwise it is + * combo change. + */ +int pxa27x_set_voltage(unsigned int freq, unsigned int mv, unsigned int combo) +{ + int ret; + + /* + * Currently voltage change is seperated with frequency change. + */ + if ((mv < PXA27X_MIN_VOL) && (mv > PXA27X_MAX_VOL) && mv != 0) + return -EINVAL; + if (mv == 0) { + if ((mv = pxa27x_find_voltage(freq)) == 0) + return -EINVAL; + } + else { + ret = check_voltage(freq, mv); + if (ret < 0) + return ret; + } + down(&pxa27x_voltage_sem); + if (mv == cpuvoltage_cur) { + up(&pxa27x_voltage_sem); + return 1; + } + if (!combo) + vm_setvoltage(mv2DAC(mv)); + else + vm_pre_setvoltage(mv2DAC(mv)); + cpuvoltage_cur = mv; + up(&pxa27x_voltage_sem); + return 0; +} +EXPORT_SYMBOL_GPL(pxa27x_set_voltage); + +unsigned int pxa27x_get_voltage(void) +{ + int vol; + + down(&pxa27x_voltage_sem); + vol = cpuvoltage_cur; + up(&pxa27x_voltage_sem); + + return vol; +} +EXPORT_SYMBOL_GPL(pxa27x_get_voltage); +#if 0 +int pxa27x_combo_set_voltage(unsigned int freq) +{ + unsigned int mv; + + if ((mv = pxa27x_find_voltage(freq)) == 0) + return -EINVAL; + vm_pre_setvoltage(mv2DAC(mv)); + cpuvoltage_cur = mv; + return mv; +} +/* This is the notifier of seperated voltage change for frequency change */ +static int voltage_cpufreq_notifier(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_freqs *freq = data; + + if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || + (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { + /* using default voltage according to the frequency */ + return pxa27x_set_voltage(freq->new, 0); + } + return 0; +} + +static struct notifier_block voltage_cpufreq_notifier_block = { + .notifier_call = voltage_cpufreq_notifier +}; + +/* This is the notifier of combo voltage change for frequency change */ +static int combo_voltage_cpufreq_notifier(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_freqs *freq = data; + + if (val == CPUFREQ_PRECHANGE) { + return pxa27x_combo_set_voltage(freq->new); + } + return 0; +} + +static struct notifier_block combo_voltage_cpufreq_notifier_block = { + .notifier_call = combo_voltage_cpufreq_notifier +}; + + +static int __init pxa27x_voltage_init(void) +{ + int ret; + + ret = cpufreq_register_notifier(&voltage_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + return ret; +} +late_initcall(pxa27x_voltage_init); +#endif diff -uNr a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c --- a/arch/arm/mach-pxa/generic.c 2004-10-19 05:53:45.000000000 +0800 +++ b/arch/arm/mach-pxa/generic.c 2005-01-27 09:56:48.000000000 +0800 @@ -219,6 +219,63 @@ .id = 2, }; +static struct resource pxacamera_resources[] = { + [0] = { + .start = 0x50000000, + .end = 0x50000fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_CAMERA, + .end = IRQ_CAMERA, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 pxa_camera_dmamask = 0xffffffffUL; + +static struct platform_device pxacamera_device = { + .name = "pxa2xx-camera", + .id = -1, + .dev = { + .dma_mask = &pxa_camera_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(pxacamera_resources), + .resource = pxacamera_resources, +}; + +static struct resource pxaac97_resources[] = { + [0] = { + .start = 0x40500000, + .end = 0x40500fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_AC97, + .end = IRQ_AC97, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 pxa_ac97_dmamask = 0xffffffffUL; + +static struct platform_device pxaac97_device = { + .name = "pxa2xx-ac97", + .id = -1, + .dev = { + .dma_mask = &pxa_ac97_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(pxaac97_resources), + .resource = pxaac97_resources, +}; + +static struct platform_device pxaflash_device = { + .name = "pxa27x-flash", + .id = -1, +}; + static struct platform_device *devices[] __initdata = { &pxamci_device, &udc_device, @@ -226,6 +283,9 @@ &ffuart_device, &btuart_device, &stuart_device, + &pxacamera_device, + &pxaac97_device, + &pxaflash_device, }; static int __init pxa_init(void) diff -uNr a/arch/arm/mach-pxa/ipmc.c b/arch/arm/mach-pxa/ipmc.c --- a/arch/arm/mach-pxa/ipmc.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/ipmc.c 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,562 @@ +/* + * linux/arch/arm/mach-pxa/ipmc.c + * + * Provide ioctl interface to application, to specify more detailed info and change + * system's behaviour. + * + * Copyright (C) 2003-2004 Intel Corporation. + * + * Author: Cain Yuan + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * If wana use it please use "mknod /dev/ipmc c 10 90" to create the dev file. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ipmc.h" + +extern unsigned int pxa27x_validate(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); +extern unsigned int pxa27x_read_clkcfg(void); +extern int pxa27x_set_cpufreq(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); +extern int pm_updatetimer(int); +extern int pxa27x_set_voltage(unsigned int, unsigned int, unsigned int); +extern unsigned int pxa27x_get_voltage(void); +#if 0 +extern void ipm_start_pmu(); +#endif + +static int ipmq_get(struct ipm_event *); +static int ipmq_put(struct ipm_event *); +//static int ipmq_empty(void); +static int ipmq_clear(void); + +struct ipm_config global_conf; +static DECLARE_MUTEX (ipm_conf_sem); +static struct ipme_queue ipme_queue; + +int ipmc_open(struct inode *inode, struct file *filep) +{ + MOD_INC_USE_COUNT; + return 0; /* success */ +} + +int ipmc_close( struct inode *inode, struct file *filep ) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Return a ipm event or get blocked until there is a event. + */ + +static __inline int ipmq_empty(void) +{ + return (ipme_queue.len>0)?0:1; +} + +ssize_t ipmc_read(struct file *filep, char *buf, size_t count, + loff_t *f_pos) +{ + DECLARE_WAITQUEUE(wait, current); + struct ipm_event data; + ssize_t retval; + + if (count < sizeof(struct ipm_event)) + return -EINVAL; + + add_wait_queue(&ipme_queue.waitq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + if (filep->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + /* Get the event out. If no, blocked.*/ + if ( !ipmq_empty()){ + ipmq_get(&data); + break; + } + /* No events and no error, block it. */ + schedule(); + } + + /* pass the event to user space. */ + retval = copy_to_user( (struct ipm_event *)buf, &data, + sizeof(struct ipm_event) ); + if (retval) { + retval = -EFAULT; + goto out; + } + retval = sizeof(struct ipm_event); + +out: + set_current_state(TASK_RUNNING); + remove_wait_queue(&ipme_queue.waitq, &wait); + return retval; +} + +/* + * Write will do nothing. If need to pass down some information use ioctl + * interface instead. + */ +ssize_t ipmc_write(struct file *filep, const char *buf, size_t count, + loff_t *f_pos) +{ + return 0; +} + +/* poll for ipm event */ +unsigned int ipmc_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &ipme_queue.waitq, wait); + if (!ipmq_empty()) + return POLLIN | POLLRDNORM; + + return 0; +} + +#if 0 +/* + * This function will change voltage and freq together using + * VCS command and set PCMD[FVC] bit. + */ +static void combine_vltg_freq_change(struct ipm_config *conf) +{ + unsigned int l, n; + unsigned int turbo_mode, dac_value; + + cpu_voltage_cur = conf->core_vltg; + + l = bulverde_freq_getL(conf->core_freq, *conf); + n = conf->turbo_mode; + turbo_mode = (conf->turbo_mode ==0 )? 0:1; + dac_value = mv2DAC(conf->core_vltg ); + + combochange(l, n ,turbo_mode, conf->fast_bus_mode, dac_value); +} + +unsigned int check_ipm_config(struct ipm_config *target) +{ + int i=0; + struct ipm_config cur; + + cur.core_freq = cpufreq_get(0); + + /* Get current voltage. */ + while( ipm_fv_table[i].freq != 0 ) { + if( cur.core_freq < ipm_fv_table[i].freq ) { + cur.core_vltg = ipm_fv_table[i].voltage; + break; + } + i++; + } + i=0; + /* Get target voltage. */ + while( ipm_fv_table[i].freq != 0 ) { + if( target->core_freq < ipm_fv_table[i].freq ) { + target->core_vltg = ipm_fv_table[i].voltage; + break; + } + i++; + } +#ifdef DEBUG + printk(KERN_INFO "Current freq: %d, target freq: %d.\n", cur.core_freq, target->core_freq); + printk(KERN_INFO "Current vol: %d, target vol: %d.\n",cur.core_vltg, target->core_vltg); +#endif + if( target->core_vltg == cur.core_vltg ) return 0; + if( target->core_vltg > cur.core_vltg ) return HIGHER; + return LOWER; +} +#endif + + +void get_ipm_config(struct ipm_config *ret_conf) +{ + struct ipm_config conf; + unsigned long clk_cfg = 0; + unsigned int l, n2, m, k, run_freq, ccsr, cccr_a; + + memset(&conf, 0, sizeof(struct ipm_config)); + conf.cpu_mode =0; /* definitly in RUN mode. */ + + ccsr = CCSR; + l = ccsr & 0x1f; + n2 = (ccsr>>7) & 0xf; + m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4; + k = (l <= 7) ? 1 : (l <= 16) ? 2 : 4; + cccr_a = CCCR & (1 << 25); + + clk_cfg = pxa27x_read_clkcfg(); + conf.fast_bus_mode = (clk_cfg >> 0x3) & 0x1; + conf.turbo_mode = (clk_cfg & 0x1)? 2: (clk_cfg & 0x4)? 1: 0; + conf.n2 = n2; + conf.l = l; + conf.mem_clk_conf = cccr_a >> 25; + run_freq = 13000*l; + if (ccsr & (1 << 31)) { + conf.core_freq = conf.sys_bus_freq = conf.mem_bus_freq = 13000; + conf.lcd_freq = (CCCR & (1 << 27))? 26000 : 13000; + memcpy(ret_conf, &conf,sizeof(struct ipm_config)); + return ; + } + conf.core_freq = l*((conf.turbo_mode == 0)? 13000 : + ((conf.turbo_mode == 2)? 6500*n2 : 3250*n2)); + conf.sys_bus_freq = (conf.fast_bus_mode)? run_freq : run_freq/2; + conf.mem_bus_freq = (!cccr_a) ? (run_freq/m) : ((conf.fast_bus_mode) ? + run_freq : (run_freq/2)); + conf.lcd_freq = run_freq / k; + + memcpy(ret_conf, &conf,sizeof(struct ipm_config)); + + return; +} + +/* + * Write the desired voltage to + * DPM voltage changer and the desired freq to DPM freq changer. + */ +void set_ipm_conf(struct ipm_config *conf) +{ + int mode, ret; + unsigned int vol = conf->core_vltg; + unsigned int freq, new_freq; + unsigned int l = conf->l, n2 = conf->n2; + unsigned int t = conf->turbo_mode, b = conf->fast_bus_mode; + unsigned int a = conf->mem_clk_conf; + int pre_change = 0; + + mode = conf->cpu_mode; + /* want to change CPU mode? */ + if( mode != 0) { /* not RUN mode. */ + /* allow to use this method to sleep the system...*/ + pm_suspend(mode); + } + + ret = pxa27x_validate(l, n2, b, t, a); + if (ret) { + printk(KERN_ERR "Error: Wrong L: %d, 2N: %d, B: %d, T: %d, A:%d\n", l, n2, b, t, a); + return ; + } + + freq = cpufreq_get(0); + new_freq = l*((t == 0)? 13000 : ((t == 2)? 6500*n2 : 3250*n2)); + /* + * It may need to change frequency. The voltage change is also invoked + * according to the frequency. + */ + if (vol == 0) { + if (freq < new_freq) + pre_change = 1; + } + else { + if (pxa27x_get_voltage() < vol) + pre_change = 1; + } + if (pre_change == 1) { + if (pxa27x_set_voltage(new_freq, vol, 0) < 0 && vol) + pxa27x_set_voltage(new_freq, 0, 0); + pxa27x_set_cpufreq(l, n2, b, t, a); + } + else { + pxa27x_set_cpufreq(l, n2, b, t, a); + if (pxa27x_set_voltage(new_freq, vol, 0) < 0 && vol) + pxa27x_set_voltage(new_freq, 0, 0); + } + /* + * combochange of voltage and frequency + */ +#if 0 + if (pxa27x_set_voltage(new_freq, vol, 1) < 0 && vol) + pxa27x_set_voltage(new_freq, 0, 1); + pxa27x_set_cpufreq(l, n2, b, t); +#endif + return; +} + +#define SLEEP_SYSTEM 0 +extern unsigned int ipm_sleep_level; +extern unsigned int pm_sleeptime; +extern unsigned int pm_waketime; +extern unsigned int pm_uitimeout; +extern unsigned int ipm_sleep_level; +#if 0 +extern unsigned long WindowSize; +#endif +int ipmc_ioctl (struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ipm_config conf, target_conf; + int result = 0; + + memset(&conf, 0 ,sizeof(struct ipm_config)); + + switch (cmd) { + case IPMC_IOCTL_GET_DPM_CONFIG: + get_ipm_config(&conf); + return (copy_to_user((unsigned long *)arg, &conf,sizeof(conf)))? -EFAULT:0; + break; + + case IPMC_IOCTL_SET_DPM_CONFIG: + if(copy_from_user(&target_conf,(struct ipmc_conf *)arg,sizeof(conf))) { + printk("Erro from copy_from_user.\n"); + return -EFAULT; + } + + set_ipm_conf(&target_conf); + break; + + /* Reset the UI timer. */ + case IPMC_IOCTL_RESET_UI_TIMER: + pm_updatetimer(0); + break; + + /* get rid of those event before. */ + case IPMC_IOCTL_CLEAR_EVENTLIST: + ipmq_clear(); + break; + + case IPMC_IOCTL_SET_SLEEPTIME: + if( copy_from_user(&pm_sleeptime,(unsigned int *)arg,sizeof(int)) ) + return -EFAULT; + break; +#if 0 + case IPMC_IOCTL_SET_WINDOWSIZE: + if( copy_from_user(&WindowSize,(unsigned int)arg,sizeof(int)) ) + return -EFAULT; + break; +#endif + case IPMC_IOCTL_GET_SLEEPTIME: + return copy_to_user((unsigned int *)arg, &pm_sleeptime, sizeof(int)); + break; + + case IPMC_IOCTL_SET_WAKETIME: + if (copy_from_user(&pm_waketime,(unsigned int *)arg,sizeof(int)) ) + return -EFAULT; + break; + + case IPMC_IOCTL_GET_WAKETIME: + return copy_to_user((unsigned int *)arg, &pm_waketime, sizeof(int)); + break; + + case IPMC_IOCTL_SET_UITIME: + if( copy_from_user(&pm_uitimeout,(unsigned int *)arg,sizeof(int)) ) + return -EFAULT; + if( pm_uitimeout !=0 ) /* stop it. */ + pm_updatetimer(0); + break; + + case IPMC_IOCTL_GET_UITIME: + return copy_to_user((unsigned int *)arg, &pm_uitimeout, sizeof(int)); + break; + + case IPMC_IOCTL_SET_SLEEPLEVEL: + if( copy_from_user(&ipm_sleep_level,(unsigned int *)arg,sizeof(int)) ) + return -EFAULT; + break; + + case IPMC_IOCTL_GET_SLEEPLEVEL: + return copy_to_user((unsigned int *)arg, &ipm_sleep_level, sizeof(int)); + break; + + /* + * Do we need to decide those two ioctls into four? + * IPMC_IOCTL_CLAIMPMU, IPMC_IOCTL_STARTPMU, + * IPMC_IOCTL_STOPPMU, IPMC_IOCTL_RELEASEPMU + * or just + * IPMC_IOCTL_STARTPMU, IPMC_IOCTL_STOPPMU ? + */ + /* + * Did not need PMU events to policy maker? That 's really good. + * Still keep this bez we need to test PMU driver, right? + */ +#if 0 + case IPMC_IOCTL_STARTPMU: + ipm_start_pmu(); + break; + /* + * When using stop pmu the user application should provide a place + * to save the result. + */ + case IPMC_IOCTL_STOPPMU: + /* pmu should already stopped. */ + pmu_stop(&presult); + /* + * Release it? Since only one user can have it we just + * use the recorded pmu id. + */ + pmu_release(pmu_id); + /* Shall we check the arg pointer first? */ + if( arg!=NULL ) + return copy_to_user( (unsigned int)arg, &presult, + sizeof(struct pmu_results) ); + else return 0; + break; +#endif + + default: + result = -ENOIOCTLCMD; + break; + } + return result; +} + +static struct file_operations ipmc_fops = { + owner: THIS_MODULE, + open: ipmc_open, + read: ipmc_read, + write: ipmc_write, + poll: ipmc_poll, + ioctl: ipmc_ioctl, + release:ipmc_close, +}; + +static struct miscdevice ipmc_misc_device = { + minor: IPMC_MINOR, + name: "ipmc", + fops: &ipmc_fops +}; + +/* + * Below is the event list maintain functions, the same as keypad.c + */ +static int ipmq_init(void) +{ + /* init ipme queue */ + ipme_queue.head = ipme_queue.tail = 0; + ipme_queue.len = 0; + init_waitqueue_head(&ipme_queue.waitq); + return 0; +} + +static int __init ipmc_init( void ) +{ + int rc; + + /* Clear event queue. */ + ipmq_init(); + + if ( (rc = misc_register( &ipmc_misc_device )) != 0 ) { + printk( KERN_INFO "Could not register device ipmc, res = %d.\n ",rc ); + return -EBUSY; + } + printk( KERN_INFO "Register device ipmc successgul.\n " ); + return 0; +} + +static void ipmc_exit( void ) +{ + misc_deregister(&ipmc_misc_device); +} + + +static int ipmq_get(struct ipm_event *ipme) +{ + unsigned long flags; + + local_irq_save(flags); + + if (!ipme_queue.len) { + local_irq_restore(flags); + return -1; + } + + memcpy(ipme, ipme_queue.ipmes + ipme_queue.tail, sizeof(struct ipm_event)); + + ipme_queue.len--; + ipme_queue.tail = (ipme_queue.tail + 1) % MAX_IPME_NUM; + + local_irq_restore(flags); + + return 0; + +} + +static int ipmq_clear(void) +{ + unsigned long flags; + + local_irq_save(flags); + ipme_queue.head = ipme_queue.tail = 0; + ipme_queue.len = 0; + local_irq_restore(flags); + + return 0; +} + +static int ipmq_put(struct ipm_event *ipme) +{ + unsigned long flags; + + local_irq_save(flags); + + if (ipme_queue.len == MAX_IPME_NUM) { + local_irq_restore(flags); + return -1; + } + + memcpy(ipme_queue.ipmes + ipme_queue.head, ipme, sizeof(struct ipm_event)); + + ipme_queue.len ++; + ipme_queue.head = (ipme_queue.head + 1) % MAX_IPME_NUM; + + local_irq_restore(flags); + + /* wake up the waiting process */ + wake_up_interruptible(&ipme_queue.waitq); + + return 0; +} + +static struct ipm_event __inline IPM_Events(int type, int kind, int info) +{ + struct ipm_event event; + event.type = type; + event.kind = kind; + event.info = info; + return event; +} + +/* + * IPM event can be posted by this function. + * If we need to do some pre-processing of those events we can add code here. + * Also attach the processed result to info. + */ +void ipm_event_notify(int type, int kind, int info) +{ + struct ipm_event events; + events = IPM_Events(type, kind, info); + ipmq_put(&events); +} + +EXPORT_SYMBOL(ipm_event_notify); + +module_init(ipmc_init); +module_exit(ipmc_exit); diff -uNr a/arch/arm/mach-pxa/ipmc.h b/arch/arm/mach-pxa/ipmc.h --- a/arch/arm/mach-pxa/ipmc.h 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/ipmc.h 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2003-2004 Intel Corporation. + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + */ + +#ifndef __IPMC_H +#define __IPMC_H + +#ifdef __KERNEL__ +#include +#include +//#include +#endif + +/* Use 'K' as magic number */ +#define IPMC_IOC_MAGIC 'K' + +/* To keep compitable with old cpufreqd user application. */ +#if 0 +#define IPMC_IOCTL_GET _IOR(IPMC_IOC_MAGIC, 1, struct ipm_config) +#define IPMC_IOCTL_SET _IOW(IPMC_IOC_MAGIC, 2, struct ipm_config) + +#endif +#define IPMC_IOCTL_GET_DPM_CONFIG _IOR(IPMC_IOC_MAGIC, 3, struct ipm_config) +#define IPMC_IOCTL_SET_DPM_CONFIG _IOW(IPMC_IOC_MAGIC, 4, struct ipm_config) + +#define IPMC_IOCTL_GET_DVFM_CONFIG _IOR(IPMC_IOC_MAGIC, 3, struct ipm_config) +#define IPMC_IOCTL_SET_DVFM_CONFIG _IOW(IPMC_IOC_MAGIC, 4, struct ipm_config) + +#define IPMC_IOCTL_GET_EVENT _IOR(IPMC_IOC_MAGIC, 5, int) +#define IPMC_IOCTL_SET_EVENT _IOW(IPMC_IOC_MAGIC, 6, int) + +#define IPMC_IOCTL_RESET_UI_TIMER _IOW(IPMC_IOC_MAGIC, 8, int) + +#define IPMC_IOCTL_GET_SLEEPTIME _IOR(IPMC_IOC_MAGIC, 9, int) +#define IPMC_IOCTL_SET_SLEEPTIME _IOW(IPMC_IOC_MAGIC, 10, int) + +#define IPMC_IOCTL_GET_WAKETIME _IOR(IPMC_IOC_MAGIC, 11, int) +#define IPMC_IOCTL_SET_WAKETIME _IOW(IPMC_IOC_MAGIC, 12, int) + +#define IPMC_IOCTL_GET_UITIME _IOR(IPMC_IOC_MAGIC, 13, int) +#define IPMC_IOCTL_SET_UITIME _IOW(IPMC_IOC_MAGIC, 14, int) + +#define IPMC_IOCTL_GET_SLEEPLEVEL _IOR(IPMC_IOC_MAGIC, 15, int) +#define IPMC_IOCTL_SET_SLEEPLEVEL _IOW(IPMC_IOC_MAGIC, 16, int) + +#define IPMC_IOCTL_STARTPMU _IOW(IPMC_IOC_MAGIC, 17, int) +#define IPMC_IOCTL_STOPPMU _IOW(IPMC_IOC_MAGIC, 18, struct pmu_results) + +#define IPMC_IOCTL_CLEAR_EVENTLIST _IOW(IPMC_IOC_MAGIC, 20, int) + +#define IPMC_IOCTL_SET_WINDOWSIZE _IOW(IPMC_IOC_MAGIC, 22, int) +#define NOVOLCHG 0 +#define HIGHER 1 +#define LOWER 2 + + +#define MAX_IPME_NUM 20 /* 20 IPM event max */ +/* IPM events queue */ + +struct ipm_config { + /* Below items must be set to set configurations. */ + unsigned int cpu_mode; + unsigned int l; /* L */ + unsigned int n2; /* 2N */ + unsigned int core_vltg; /* in mV. */ + unsigned int turbo_mode; /* =2 turbo, =1 half turbo */ + unsigned int fast_bus_mode; + unsigned int mem_clk_conf; + /* Below items may need to get system DPM configurations. */ + unsigned int core_freq; + unsigned int sys_bus_freq; + unsigned int mem_bus_freq; + unsigned int lcd_freq; + unsigned int enabled_device; +}; + +struct ipm_event { + unsigned int type; /* What type of IPM events. */ + unsigned int kind; /* What kind, or sub-type of events.*/ +// void *infodata; /* events specific data. */ + unsigned int info; +}; + +#ifdef __KERNEL__ +struct ipme_queue{ + int head; + int tail; + int len; + struct ipm_event ipmes[MAX_IPME_NUM]; + wait_queue_head_t waitq; +}; +#endif + +#define IPM_EVENTS_TYPE(x) ((x&0xFF000000)>>24) +#define IPM_EVENTS_KIND(x) ((x&0x00F00000)>>16) +#define IPM_EVENTS_INFO(x) (x&0xFF) + +/* IPM event types. */ +#define IPM_EVENT_DEVICE 0x1 /* Device interrupt event. */ +#define IPM_EVENT_TIMER 0x2 /* Device Timer timeout event. */ + +#define IPM_EVENT_PROFILER 0x3 /* Profiler events. */ +#define IPM_EVENT_SYSTEM_WAKEUP 0x4 +#define IPM_EVENT_CPU 0x5 /* CPU utilization change event. */ + +/* IPM event kinds. */ +#define IPM_EVENT_POWER_LOW 0x1 +#define IPM_EVENT_POWER_FAULT 0x2 +#define IPM_EVENT_POWER_OK 0x3 + +#define IPM_EVENT_DEVICE_TIMEOUT 0x4 +#define IPM_EVENT_DEVICE_INT 0x5 + +#define IPM_EVENT_IDLE_PROFILER 0x0 +#define IPM_EVENT_PERF_PROFILER 0x1 + +#define IPM_EVENT_RTCWAKEUP 0x0 +#define IPM_EVENT_UIWAKEUP 0x1 + +#define IPM_EVENT_CPUVERYBUSY 0x0 /* report CPU is very busy now. */ +#define IPM_EVENT_CPUBUSY 0x1 /* report CPU is very busy now. */ +#define IPM_EVENT_CPUFREE 0x2 /* report CPU is free now. */ + +/* IPM event infos, not defined yet. */ +#define IPM_EVENT_NULLINFO 0x0 +#define IPM_WAKEUPBYRTC 0x1 +#define IPM_WAKEUPBYUI 0x2 + +/* IPM functions */ +#ifdef __KERNEL__ +int ipmc_open(struct inode *inode, struct file *filep); +int ipmc_close( struct inode *inode, struct file *filep ); +ssize_t ipmc_read(struct file *filep, char *buf, size_t count,loff_t *f_pos); +ssize_t ipmc_write(struct file *filep, const char *buf, size_t count,loff_t *f_pos); +int ipmc_ioctl (struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg); +void set_ipm_conf(struct ipm_config *conf); +void ipm_event_notify(int type, int kind, int info); +#endif + + +#endif diff -uNr a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig --- a/arch/arm/mach-pxa/Kconfig 2004-10-19 05:53:43.000000000 +0800 +++ b/arch/arm/mach-pxa/Kconfig 2005-01-27 09:56:48.000000000 +0800 @@ -20,6 +20,61 @@ endchoice +menu "Intel PXA27x Errata Fixes" +depends on PXA27x + +config PXA27x_E11 + bool "Intel PXA27x Errata 11" + help + KEYPAD: Extra Keypad matrix interrupt in IMKP Mode + default y + +config PXA27x_E17 + bool "Intel PXA27x Errata 17" + help + LCD: Overlay1 is not enabled intermittently after re-enabling LCD. + default y + +config PXA27x_E20 + bool "Intel PXA27x Errata 20" + help + UART: Character timeout interrupt remains set under certain software + conditions + default y + +config PXA27x_E23 + bool "Intel PXA27x Errata 23" + help + CIP: Receiver Aborts randomly occur prematurely and without End of + frame/Error in FIFO interrupt + default y + +config PXA27x_E25 + bool "Intel PXA27x Errata 25" + help + LCD: Enabling Overlay 2 for YUV420 hangs LCD controller. + default y + +config PXA27x_E28 + bool "Intel PXA27x Errata 28" + help + Core hangs during voltage change when there are outstanding transaction on the bus. + default y + +config PXA27x_E37 + bool "Intel PXA27x Errata 37" + help + System Hangs when enabling RUN/TURBO switching at 520MHZ + default y + +config PXA27x_E38 + bool "Intel PXA27x Errata 38" + help + System Hangs when enabling HalfTurbo Switching + default y + +endmenu + endmenu config PXA25x diff -uNr a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c --- a/arch/arm/mach-pxa/leds-mainstone.c 2004-10-19 05:53:06.000000000 +0800 +++ b/arch/arm/mach-pxa/leds-mainstone.c 2005-01-27 09:56:48.000000000 +0800 @@ -23,16 +23,6 @@ #include "leds.h" -/* 8 discrete leds available for general use: */ -#define D28 (1 << 0) -#define D27 (1 << 1) -#define D26 (1 << 2) -#define D25 (1 << 3) -#define D24 (1 << 4) -#define D23 (1 << 5) -#define D22 (1 << 6) -#define D21 (1 << 7) - #define LED_STATE_ENABLED 1 #define LED_STATE_CLAIMED 2 diff -uNr a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c --- a/arch/arm/mach-pxa/mainstone.c 2004-10-19 05:55:29.000000000 +0800 +++ b/arch/arm/mach-pxa/mainstone.c 2005-01-27 09:56:48.000000000 +0800 @@ -159,11 +159,11 @@ .yres = 320, .bpp = 16, .hsync_len = 4, - .left_margin = 8, - .right_margin = 20, + .left_margin = 12, + .right_margin = 14, .vsync_len = 3, - .upper_margin = 1, - .lower_margin = 10, + .upper_margin = 5, + .lower_margin = 6, .sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, .lccr0 = LCCR0_Act, .lccr3 = LCCR3_PCP, @@ -172,14 +172,21 @@ static void __init mainstone_init(void) { + /* system bus arbiter setting + * - Core_Park + * - LCD_wt:DMA_wt:CORE_Wt = 2:3:4 + */ + ARB_CNTRL = ARB_CORE_PARK | 0x234; + platform_device_register(&smc91x_device); /* reading Mainstone's "Virtual Configuration Register" might be handy to select LCD type here */ - if (0) +#ifdef CONFIG_FB_PXA_LCD_VGA set_pxa_fb_info(&toshiba_ltm04c380k); - else +#elif CONFIG_FB_PXA_LCD_QVGA set_pxa_fb_info(&toshiba_ltm035a776c); +#endif } @@ -196,6 +203,8 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") MAINTAINER("MontaVista Software Inc.") BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) + /* FIXME: BLOB boot parameter setting */ + BOOT_PARAMS(0xa0000100) MAPIO(mainstone_map_io) INITIRQ(mainstone_init_irq) INITTIME(pxa_init_time) diff -uNr a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile --- a/arch/arm/mach-pxa/Makefile 2004-10-19 05:54:27.000000000 +0800 +++ b/arch/arm/mach-pxa/Makefile 2005-01-27 09:56:48.000000000 +0800 @@ -5,7 +5,7 @@ # Common support (must be linked before board specific support) obj-y += generic.o irq.o dma.o time.o obj-$(CONFIG_PXA25x) += pxa25x.o -obj-$(CONFIG_PXA27x) += pxa27x.o +obj-$(CONFIG_PXA27x) += pxa27x.o pmu-bvd.o pmu.o # Specific board support obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o @@ -22,3 +22,5 @@ # Misc features obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_DVFM) += vcs.o cpu-freq-pxa27x.o cpu-voltage-pxa27x.o ipmc.o +obj-$(CONFIG_SRAM_ALLOCATE) += sram.o diff -uNr a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c --- a/arch/arm/mach-pxa/pm.c 2004-10-19 05:54:32.000000000 +0800 +++ b/arch/arm/mach-pxa/pm.c 2005-01-27 09:56:48.000000000 +0800 @@ -7,11 +7,17 @@ * Modified for the PXA250 by Nicolas Pitre: * Copyright (c) 2002 Monta Vista Software, Inc. * + * Modified for the PXA27x based on Mainstone by Chao Xie + * Copyright (C) 2004, Intel Corporation + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License. + * */ + #include #include +#include #include #include #include @@ -20,17 +26,26 @@ #include #include #include -#include +#include #include +#include "cpu-freq-voltage-pxa27x.h" /* * Debug macros */ #undef DEBUG +extern struct subsystem power_subsys; + +extern int pxa27x_set_voltage(unsigned int, unsigned int, unsigned int); +extern void pxa27x_cpufreq_restore(void); extern void pxa_cpu_suspend(void); extern void pxa_cpu_resume(void); +extern void pxa_cpu_standby(void); +static int check_wakeup_src(void); +int pm_updatetimer(int); +void pm_timeout_proc(unsigned long); #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] @@ -40,6 +55,31 @@ GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ } while (0) +/* How long we will in sleep mode if duty cycle. */ +unsigned int pm_sleeptime=58; /* In seconds. */ + +/* How long we will in run mode if duty cycle. */ +unsigned int pm_waketime = 2; /* In seconds. */ + +/* After pm_uitimeout long without input from keypad/touch, we will sleep. */ +unsigned int pm_uitimeout= 30; /* In seconds. */ + +/* Timer timeout event handled in kernel or in policy maker? */ +/* 0 is in kernel and 1 is for policy maker in user space. */ +unsigned int ipm_event_handler = 1; /* In seconds. */ + +/* + * The default sleep level, if we want to use Standy to replace sleep. + * set this to PM_SUSPEND_STANDBY. + */ +unsigned int ipm_sleep_level = PM_SUSPEND_MEM; /* Default is to Sleep mode. */ + +/* Shall we use standby as idle? */ +unsigned int ipm_sai = 0; + +static struct timer_list pm_timer; +struct semaphore pm_timer_wait; + /* * List of global PXA peripheral registers to preserve. * More ones like CP and general purpose register values are preserved @@ -57,12 +97,37 @@ SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U, - SLEEP_SAVE_ICMR, - SLEEP_SAVE_CKEN, +#if defined(CONFIG_PXA27x) + SLEEP_SAVE_GPDR3, SLEEP_SAVE_GRER3, SLEEP_SAVE_GFER3, + SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U, + SLEEP_SAVE_KPC, +#endif - SLEEP_SAVE_CKSUM, + SLEEP_SAVE_ICMR, + SLEEP_SAVE_CKEN, +#ifdef CONFIG_MACH_MAINSTONE + SLEEP_SAVE_MST_GPSWR, + SLEEP_SAVE_MST_MSCWR1, + SLEEP_SAVE_MST_MSCWR2, + SLEEP_SAVE_MST_MSCWR3, + SLEEP_SAVE_MST_MSCRD, + SLEEP_SAVE_MST_INTMSKENA, + SLEEP_SAVE_MST_INTSETCLR, +#endif - SLEEP_SAVE_SIZE + SLEEP_SAVE_PWER, + SLEEP_SAVE_PSTR, + SLEEP_SAVE_OMCR4, + SLEEP_SAVE_OSCR4, + SLEEP_SAVE_OSMR4, + SLEEP_SAVE_MDREFR, + SLEEP_SAVE_OSSR, + SLEEP_SAVE_PGSR0, + SLEEP_SAVE_PGSR1, + SLEEP_SAVE_PGSR2, + SLEEP_SAVE_PGSR3, + SLEEP_SAVE_CKSUM, + SLEEP_SAVE_SIZE }; @@ -73,15 +138,30 @@ struct timespec delta, rtc; int i; - if (state != PM_SUSPEND_MEM) + if (state != PM_SUSPEND_MEM && state != PM_SUSPEND_STANDBY) return -EINVAL; +// leds_event(led_stop); /* preserve current time */ rtc.tv_sec = RCNR; rtc.tv_nsec = 0; save_time_delta(&delta, &rtc); +#if defined(CONFIG_MACH_MAINSTONE) + SAVE(MST_GPSWR); + SAVE(MST_MSCWR1); + SAVE(MST_MSCWR2); + SAVE(MST_MSCWR3); + SAVE(MST_MSCRD); + SAVE(MST_INTMSKENA); + SAVE(MST_INTSETCLR); +#endif + + /* For SDRAM sightings. */ + SAVE(MDREFR); + /* save vital registers */ + SAVE(OSSR); SAVE(OSMR0); SAVE(OSMR1); SAVE(OSMR2); @@ -95,31 +175,150 @@ SAVE(GAFR0_L); SAVE(GAFR0_U); SAVE(GAFR1_L); SAVE(GAFR1_U); SAVE(GAFR2_L); SAVE(GAFR2_U); +#if defined(CONFIG_PXA27x) + SAVE(GPDR3); + SAVE(GRER3); + SAVE(GFER3); + SAVE(GAFR3_L); SAVE(GAFR3_U); + + SAVE(KPC); /* new added. */ +#endif SAVE(ICMR); ICMR = 0; SAVE(CKEN); - CKEN = 0; - - /* Note: wake up source are set up in each machine specific files */ + SAVE(PGSR0); + SAVE(PGSR1); + SAVE(PGSR2); + SAVE(PGSR3); + +#ifdef CONFIG_PXA27x + if (state == PM_SUSPEND_STANDBY) + CKEN = CKEN22_MEMC | CKEN9_OSTIMER | CKEN16_LCD |CKEN0_PWM0; + else + CKEN = CKEN22_MEMC | CKEN9_OSTIMER; + + PCFR = 0x66; + /* + * PSLR |= 0x4 is OK for serial console but not OK for + * LCD which is configured to use ISRAM as framebuffer when using QVGA. + * + * PSLR |= 0xF04 is OK for LCD driver but not OK for serial console, + * UART doesn't work correctly when PSLR|=0xF04 + */ + /* PSLR |= 0X4; */ + PSLR |= 0xF04; + + /* For Keypad wakeup. */ +#if defined(CONFIG_MACH_MAINSTONE) + KPC &=~KPC_ASACT; + KPC |=KPC_AS; +#endif + PGSR0 = 0x00008800; + PGSR1 = 0x00000002; + PGSR2 = 0x0001FC00; + PGSR3 = 0x00001F81; + + /* PWER = 0x80000002; */ + PWER = 0xC0000002; + PRER = 0x2; + PFER = 0x2; + + PKWR = 0x000FD001; + /* Need read PKWR back after set it. */ + PKWR; +#else + CKEN = 0; +#endif /* clear GPIO transition detect bits */ GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; - /* Clear sleep reset status */ - RCSR = RCSR_SMR; + /* Clear sleep reset status */ + RCSR = RCSR_SMR; - /* set resume return address */ - PSPR = virt_to_phys(pxa_cpu_resume); + /* Clear edge-detect status register. */ + PEDR = 0xCE00FE1B; + + /* set resume return address */ +#if defined(CONFIG_PXA27x) + if (state != PM_SUSPEND_STANDBY) + PSPR = virt_to_phys(pxa_cpu_resume); + + if (state == PM_SUSPEND_STANDBY) { + SAVE(PSTR); + SAVE(OMCR4); + SAVE(OSCR4); + SAVE(OSMR4); + SAVE(OIER); + } +#else + PSPR = virt_to_phys(pxa_cpu_resume); +#endif /* before sleeping, calculate and save a checksum */ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) checksum += sleep_save[i]; sleep_save[SLEEP_SAVE_CKSUM] = checksum; - /* *** go zzz *** */ - pxa_cpu_suspend(); + /* Use RTC to wakeup system from sleep. */ + if (state != PM_SUSPEND_STANDBY) { + /* Check the sleeptime to see how we need to wake up,in ms. */ + /* come back sometimes later.*/ + if (pm_sleeptime != 0) { + /*65s,use periodic interrupt*/ + if (pm_sleeptime < 65) { + /* Clear PICE bit in RTSR. */ + RTSR &= ~RTSR_PICE; + /*set to sleep time,inms.*/ + /* set PIAR */ + PIAR = pm_sleeptime*1000; + /* Ensure at least 2 CPY cycles pass.*/ + udelay(10); + /* Clear PIALE bit in RTSR */ + RTSR &= ~RTSR_PIALE; + RTSR |= RTSR_PIALE; + RTSR |= RTSR_PICE; + } + else { /* we need to use RTC. */ + /* Need to use other RTC wakeep methods.. */ + } + + } + } + +#if defined(CONFIG_PXA27x) + /* Use OST 4 to wakeup system from standby */ + if (state == PM_SUSPEND_STANDBY) { + /* + * Here we use OS timer 4 as wakeup src. Maybe this is helpful + * when we decide to use standby to replace idle. + */ + /* All SRAM are on, PI is active with clock running. */ + PSTR = 0x00000F08; + /* For standby we use OSCR4 as prioridic wakeup source. */ + /* CRES field of OMCR is set to 011, ticks will be 1 seconds.*/ + OMCR4 = 0x0B; + OSCR4 = 1; + OSMR4 = OSCR4 + pm_sleeptime; + OIER = (OIER & 0xFFF) | 0x10; + } +#endif + + /* go Zzzz */ + switch (state) { + case PM_SUSPEND_MEM: + pxa_cpu_suspend(); + pxa27x_cpufreq_restore(); + break; +#if defined(CONFIG_PXA27x) + case PM_SUSPEND_STANDBY: + /* Standby the CPU. */ + pxa_cpu_standby(); + break; +#endif + } /* end of switch */ /* after sleeping, validate the checksum */ checksum = 0; @@ -137,6 +336,23 @@ /* ensure not to come back here if it wasn't intended */ PSPR = 0; +#ifdef CONFIG_PXA27x + if (state == PM_SUSPEND_STANDBY ) { + /* Clear PEDR */ + RESTORE(OIER); + RESTORE(MDREFR); + RESTORE(PSTR); + OSSR =0x10; + OSMR4 = OSCR4 + 3; + OSCR4 = OSCR4 + 4; + } + /* restore registers */ + RESTORE(PGSR0); + RESTORE(PGSR1); + RESTORE(PGSR2); + RESTORE(PGSR3); +#endif + /* restore registers */ RESTORE(GAFR0_L); RESTORE(GAFR0_U); RESTORE(GAFR1_L); RESTORE(GAFR1_U); @@ -146,7 +362,16 @@ RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); - PSSR = PSSR_RDH | PSSR_PH; +#if defined(CONFIG_PXA27x) + RESTORE(KPC); /* new added. */ + RESTORE(GAFR3_L); RESTORE(GAFR3_U); + RESTORE(GPDR3); + RESTORE(GRER3); + RESTORE(GFER3); + PSSR = PSSR_PH | PSSR_OTGPH; +#else + PSSR = PSSR_PH; +#endif RESTORE(OSMR0); RESTORE(OSMR1); @@ -163,6 +388,17 @@ ICCR = 1; RESTORE(ICMR); +#if defined(CONFIG_MACH_MAINSTONE) + /* Restore Mainstone Board registers. */ + RESTORE(MST_GPSWR); + RESTORE(MST_MSCWR1); + RESTORE(MST_MSCWR2); + RESTORE(MST_MSCWR3); + RESTORE(MST_MSCRD); + RESTORE(MST_INTMSKENA); + RESTORE(MST_INTSETCLR); +#endif + /* restore current time */ rtc.tv_sec = RCNR; restore_time_delta(&delta, &rtc); @@ -170,6 +406,8 @@ #ifdef DEBUG printk(KERN_DEBUG "*** made it back from resume\n"); #endif + //leds_event(led_start); + /* pm_updatetimer( check_wakeup_src() );*/ return 0; } @@ -180,10 +418,60 @@ } /* + * Return the source which bring the system out of sleep. + */ +static int check_wakeup_src(void) +{ + int temp = 0; + if ( PEDR & 0x80000000) /* wakeup by RTC. */ + temp = 1; + /* Clear PEDR */ + PEDR = 0xCE00FE1B; + return temp; +} + +/* + * Let ipm_event_handler to choose whether timer timeout event handle in + * kernel space or by policy maker. + * 0 is in kernel and 1 is for policy maker in user space. + */ +void pm_timeout_proc(unsigned long ptr) +{ +#if 0 + if (ipm_event_handler == 0) + up(&pm_timer_wait); /* Let ipm_thread to sleep the system. */ + else /* notice the policy maker. */ + up(&event_sem); +#endif +} + +/* + * Flag is used to say whether it was called from UI update or from + * sleep call. In UI device call it with flag = 0, in sleep return + * call it with flag = 1. + */ +int pm_updatetimer(int flag) +{ + if (flag) + mod_timer(&pm_timer, jiffies + pm_waketime*HZ ); + else + mod_timer(&pm_timer, jiffies + pm_uitimeout*HZ ); + return 0; +} + +EXPORT_SYMBOL_GPL(pm_updatetimer); + +/* * Called after processes are frozen, but before we shut down devices. */ +static unsigned int old_core_voltage; static int pxa_pm_prepare(u32 state) { + if (state == PM_SUSPEND_MEM) { + /* set to highest voltage */ + old_core_voltage = pxa27x_get_voltage(); + pxa27x_set_voltage(PXA27X_MAX_FREQ, 0, 0); + } return 0; } @@ -192,6 +480,10 @@ */ static int pxa_pm_finish(u32 state) { + /* restore voltage, this should after restore CKEN */ + if (state == PM_SUSPEND_MEM) { + pxa27x_set_voltage(PXA27X_MIN_FREQ, old_core_voltage, 0); + } return 0; } @@ -205,9 +497,40 @@ .finish = pxa_pm_finish, }; +#define pm_attr(_name, object) \ +static ssize_t _name##_store(struct subsystem * subsys, const char * buf, size_t n) \ +{ \ + sscanf(buf, "%u", &object); \ + return n; \ +} \ +static ssize_t _name##_show(struct subsystem * subsys, char * buf) \ +{ \ + return sprintf(buf, "%u\n", object); \ +} \ +static struct subsys_attribute _name##_attr = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = 0644, \ + }, \ + .show = _name##_show, \ + .store = _name##_store, \ +} + + +pm_attr(sleeptime, pm_sleeptime); + static int __init pxa_pm_init(void) { pm_set_ops(&pxa_pm_ops); + sema_init(&pm_timer_wait, 0); + init_timer(&pm_timer); + pm_timer.function = pm_timeout_proc; + + if (pm_uitimeout) { + mod_timer(&pm_timer, jiffies + pm_uitimeout*HZ ); + } + + sysfs_create_file(&power_subsys.kset.kobj, &sleeptime_attr.attr); return 0; } diff -uNr a/arch/arm/mach-pxa/pmu-bvd.S b/arch/arm/mach-pxa/pmu-bvd.S --- a/arch/arm/mach-pxa/pmu-bvd.S 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/pmu-bvd.S 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,177 @@ +/* + * Copyright 2000-2003 Intel Corporation All Rights Reserved. + * This file is for xsc2 PMU Access Assembly function + */ + +.text + +/* +@ +@ pmu_reg_read - Read the PMU Register +@ +@ Description: +@ This routine reads the designated PMU register via CoProcesser 14. +@ +@ Input Parameters: +@ r0 - arg1, PMU register number to read. Number between 0 to 8 +@ if r0 contains: +@ 0 -> PMNC, PMU Control Register +@ 1 -> CCNT, PMU Clock Counter +@ 2 -> PMN0, PMU Count Register 0 +@ 3 -> PMN1, PMU Count Register 1 +@ 4 -> PMN2, PMU Count Register 2 +@ 5 -> PMN3, PMU Count Register 3 +@ 6 -> INTEN, PMU Interupt Enable Register +@ 7 -> FLAG, PMU Overflow Flag Status Register +@ 8 -> EVTSEL PMU Event Select Register +@ +@ Returns: +@ r0 - 32-bit value read from CoProcessor +@ +@ Registers Modified: +@ CoProcessor Register Modified: None +@ General Purpose Registers Modified: r0 +@ +@ NOTE: +@ Error checking not included +@ +*/ +.global pmu_reg_read; +.align 0; +pmu_reg_read: + cmp r0, #8 + addls pc, pc, r0, lsl #2 + b RRet + b RdPMNC + b RdCCNT + b RdPMN0 + b RdPMN1 + b RdPMN2 + b RdPMN3 + b RdINTEN + b RdFLAG + b RdEVTSEL + +RdPMNC: + mrc p14, 0, r0, c0, c1, 0 @ Read PMNC + b RRet +RdCCNT: + mrc p14, 0, r0, c1, c1, 0 @ Read CCNT + b RRet +RdPMN0: + mrc p14, 0, r0, c0, c2, 0 @ Read PMN0 + b RRet +RdPMN1: + mrc p14, 0, r0, c1, c2, 0 @ Read PMN1 + b RRet +RdPMN2: + mrc p14, 0, r0, c2, c2, 0 @ Read PMN2 + b RRet +RdPMN3: + mrc p14, 0, r0, c3, c2, 0 @ Read PMN3 + b RRet +RdINTEN: + mrc p14, 0, r0, c4, c1, 0 @ Read INTEN + b RRet +RdFLAG: + mrc p14, 0, r0, c5, c1, 0 @ Read FLAG + b RRet +RdEVTSEL: + mrc p14, 0, r0, c8, c1, 0 @ Read EVTSEL + +RRet: + mov pc, lr @ return + +/* +@ +@ pmu_reg_write - Writes to the PMU Register +@ +@ Description: +@ This routine writes to the designated PMU register via CoProcesser 14. +@ +@ Input Parameters: +@ r0 - arg1 - PMU register number to write +@ r1 - arg2 - Value to write to PMU register +@ +@ if r0 contains: +@ 0 -> PMNC, PMU Control Register +@ 1 -> CCNT, PMU Clock Counter +@ 2 -> PMN0, PMU Count Register 0 +@ 3 -> PMN1, PMU Count Register 1 +@ 4 -> PMN2, PMU Count Register 2 +@ 5 -> PMN3, PMU Count Register 3 +@ 6 -> INTEN, PMU Interupt Enable Register +@ 7 -> FLAG, PMU Overflow Flag Status Register +@ 8 -> EVTSEL PMU Event Select Register +@ +@ Returns: +@ None +@ +@ Registers Modified: +@ CoProcessor Register Modified: PMU Register +@ General Purpose Registers Modified: None +@ +@ NOTE +@ Error checking not included +@ +*/ +.global pmu_reg_write; +.align 0; +pmu_reg_write: + cmp r0, #8 + addls pc, pc, r0, lsl #2 + b WRet + b WrPMNC + b WrCCNT + b WrPMN0 + b WrPMN1 + b WrPMN2 + b WrPMN3 + b WrINTEN + b WrFLAG + b WrEVTSEL + +WrPMNC: + mcr p14, 0, r1, c0, c1, 0 @ Write PMNC + b WRet +WrCCNT: + mcr p14, 0, r1, c1, c1, 0 @ Write CCNT + b WRet +WrPMN0: + mcr p14, 0, r1, c0, c2, 0 @ Write PMN0 + b WRet +WrPMN1: + mcr p14, 0, r1, c1, c2, 0 @ Write PMN1 + b WRet +WrPMN2: + mcr p14, 0, r1, c2, c2, 0 @ Write PMN2 + b WRet +WrPMN3: + mcr p14, 0, r1, c3, c2, 0 @ Write PMN3 + b WRet +WrINTEN: + mcr p14, 0, r1, c4, c1, 0 @ Write INTEN + b WRet +WrFLAG: + mcr p14, 0, r1, c5, c1, 0 @ Write FLAG + b WRet +WrEVTSEL: + mcr p14, 0, r1, c8, c1, 0 @ Write EVTSEL + +WRet: + mov pc, lr @ return + +/* +; XSC1GetCPUId - Get the CPU ID from CP15 R0 Register +; +; This routine reads R0 from CoProcesser 15 to get the CPU ID +; +; Uses r0 - return value of CPU ID +*/ +.global XSC1GetCPUId; +.align 0; +XSC1GetCPUId: + mrc p15, 0, r0, c0, c0, 0 + mov pc, lr + +.end diff -uNr a/arch/arm/mach-pxa/pmu.c b/arch/arm/mach-pxa/pmu.c --- a/arch/arm/mach-pxa/pmu.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/pmu.c 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,177 @@ +/* + * This function provides the implementation of the access functions to + * the Performance Monitoring Unit on all CPUs based on the XScale core. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License. + * + * Copyright (c) 2003 Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static atomic_t usage = ATOMIC_INIT(0); +static unsigned long id = 0; +struct pmu_results results; + +static u32 pmnc; +static u32 evtsel; + +#define PMNC 0 /* PMU Control Register */ +#define CCNT 1 /* PMU Clock Counter (CCNT) */ +#define PMN0 2 /* PMU Count Register 0 (PMN0) */ +#define PMN1 3 /* PMU Count Register 1 (PMN1) */ +#define PMN2 4 +#define PMN3 5 +#define INTEN 6 +#define FLAG 7 +#define EVTSEL 8 + +extern void pmu_reg_write(unsigned long regno, unsigned long value); +extern unsigned long pmu_reg_read(unsigned long regno); + +#define PMU_ENABLE 0x001 /* Enable counters */ +#define PMN_RESET 0x002 /* Reset event counters */ +#define CCNT_RESET 0x004 /* Reset clock counter */ +#define PMU_RESET CCNT_RESET | PMN_RESET +#define CLK_DIV 0x008 /* Clock divide enbable */ + +#define PMN3_OVERFLOW 0x10 /* Perfromance counter 0 overflow */ +#define PMN2_OVERFLOW 0x08 /* Performance counter 1 overflow */ +#define PMN1_OVERFLOW 0x04 /* Performance counter 1 overflow */ +#define PMN0_OVERFLOW 0x02 /* Performance counter 1 overflow */ +#define CCNT_OVERFLOW 0x01 /* Clock counter overflow */ + +static irqreturn_t pmu_irq_handler(int, void *, struct pt_regs *); + +int pmu_claim(void) +{ + int err = 0; + + if(atomic_read(&usage)) + return -EBUSY; + + err = request_irq(IRQ_PMU, pmu_irq_handler, SA_INTERRUPT, + NULL, (void *) &results); + if(err < 0) + { + printk(KERN_ERR "unable to request IRQ %d for 80200 PMU: %d\n", + IRQ_PMU, err); + return err; + } + + atomic_inc(&usage); + pmnc = 0; + pmu_reg_write(PMNC, pmnc); + return ++id; +} + +int pmu_release(int claim_id) +{ + if(!atomic_read(&usage)) + return 0; + + if(claim_id != id) + return -EPERM; + + free_irq(IRQ_PMU, (void *)&results); + atomic_dec(&usage); + + return 0; +} + +int pmu_start(u32 pmn0, u32 pmn1, u32 pmn2, u32 pmn3) +{ + memset(&results, 0, sizeof(results)); + + evtsel = (pmn3 <<24) | (pmn2 <<16) | (pmn1 <<8) | pmn0; + + pmnc |= PMU_ENABLE | PMU_RESET; + + pmu_reg_write(EVTSEL, evtsel); + /* All interrupt are turned on. */ + pmu_reg_write(INTEN, 0x1F); + pmu_reg_write(PMNC, pmnc); + + return 0; +} + +int pmu_stop(struct pmu_results *results) +{ + u32 ccnt; + u32 pmn0; + u32 pmn1; + u32 pmn2; + u32 pmn3; + + if(!pmnc) + return -ENOSYS; + + ccnt = pmu_reg_read(CCNT); + pmn0 = pmu_reg_read(PMN0); + pmn1 = pmu_reg_read(PMN1); + pmn2 = pmu_reg_read(PMN2); + pmn3 = pmu_reg_read(PMN3); + + pmnc = 0; + + pmu_reg_write(PMNC, pmnc); + + results->ccnt = ccnt; + results->pmn0 = pmn0; + results->pmn1 = pmn1; + results->pmn2 = pmn2; + results->pmn3 = pmn3; + + return 0; +} + +static irqreturn_t pmu_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pmu_results *results = (struct pmu_results *)dev_id; + unsigned int flag; + + /* read the status */ + flag = pmu_reg_read(FLAG); + pmnc = pmu_reg_read(PMNC); + + if(pmnc & PMN0_OVERFLOW) { + results->pmn0_of++; + } + + if(pmnc & PMN1_OVERFLOW) { + results->pmn1_of++; + } + + if(pmnc & PMN2_OVERFLOW) { + results->pmn2_of++; + } + + if(pmnc & PMN3_OVERFLOW) { + results->pmn3_of++; + } + + if(pmnc & CCNT_OVERFLOW) { + results->ccnt_of++; + } + + pmu_reg_write(FLAG, flag); + pmu_reg_write(PMNC, pmnc); + + return IRQ_HANDLED; +} + +EXPORT_SYMBOL(pmu_claim); +EXPORT_SYMBOL(pmu_release); +EXPORT_SYMBOL(pmu_start); +EXPORT_SYMBOL(pmu_stop); + + diff -uNr a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c --- a/arch/arm/mach-pxa/pxa27x.c 2004-10-19 05:54:08.000000000 +0800 +++ b/arch/arm/mach-pxa/pxa27x.c 2005-01-27 09:56:48.000000000 +0800 @@ -29,6 +29,7 @@ * Get the clock frequency as reflected by CCSR and the turbo flag. * We assume these values have been applied via a fcs. * If info is not 0 we also display the current settings. + * special situation about 13M */ unsigned int get_clk_frequency_khz( int info) { @@ -38,10 +39,11 @@ ccsr = CCSR; cccr_a = CCCR & (1 << 25); - + if (ccsr & (1 << 31)) + return 13000; /* Read clkcfg register: it has turbo, b, half-turbo (and f) */ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) ); - t = clkcfg & (1 << 1); + t = clkcfg & (1 << 0); ht = clkcfg & (1 << 2); b = clkcfg & (1 << 3); @@ -72,6 +74,7 @@ /* * Return the current mem clock frequency in units of 10kHz as * reflected by CCCR[A], B, and L + * in 13M, mem clock frequency is 13M */ unsigned int get_memclk_frequency_10khz(void) { @@ -81,7 +84,8 @@ ccsr = CCSR; cccr_a = CCCR & (1 << 25); - + if (ccsr & (1 << 31)) + return 1300; /* Read clkcfg register: it has turbo, b, half-turbo (and f) */ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) ); b = clkcfg & (1 << 3); @@ -97,6 +101,7 @@ /* * Return the current LCD clock frequency in units of 10kHz as + * in 13M, LCD clock frequency is 13M or 26 M */ unsigned int get_lcdclk_frequency_10khz(void) { @@ -105,12 +110,14 @@ ccsr = CCSR; + if (ccsr & (1 << 31)) + return (CCCR & (1 << 27))? 2600:1300; l = ccsr & 0x1f; k = (l <= 7) ? 1 : (l <= 16) ? 2 : 4; L = l * BASE_CLK; K = L / k; - + return (K / 10000); } diff -uNr a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S --- a/arch/arm/mach-pxa/sleep.S 2004-10-19 05:55:07.000000000 +0800 +++ b/arch/arm/mach-pxa/sleep.S 2005-01-27 09:56:48.000000000 +0800 @@ -7,6 +7,9 @@ * Adapted for PXA by Nicolas Pitre: * Copyright (c) 2002 Monta Vista Software, Inc. * + * Modified for sleep/standby/wakeup on PXA27x by Cain Yuan + * Copyright (C) 2004, Intel Corporation + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License. */ @@ -19,6 +22,25 @@ #include .text +/* + * pxa_cpu_standby() + * + * Forces CPU into Standby state + */ +ENTRY(pxa_cpu_standby) + stmfd sp!, {r1 - r9, lr} @ save registers on stack + mov r2, #2 + mov r7, #UNCACHED_PHYS_0 @ Read mem context in. + ldr r8, [r7] + + b 1f + + .align 5 +1: + + mcr p14, 0, r2, c7, c0, 0 @ put the system into Standby + + ldmfd sp!, {r1 - r9, pc} @ Restore regs and return to caller /* * pxa_cpu_suspend() @@ -58,6 +80,7 @@ @ prepare value for sleep mode mov r1, #3 @ sleep mode +#ifndef CONFIG_PXA27x @ prepare to put SDRAM into self-refresh manually ldr r4, =MDREFR ldr r5, [r4] @@ -96,6 +119,7 @@ bic r0, r0, #2 @ clear change bit mcr p14, 0, r0, c6, c0, 0 orr r0, r0, #2 @ initiate change bit +#endif @ align execution to a cache line b 1f @@ -107,6 +131,7 @@ @ All needed values are now in registers. @ These last instructions should be in cache +#ifndef CONFIG_PXA27x @ initiate the frequency change... str r7, [r6] mcr p14, 0, r0, c6, c0, 0 @@ -119,6 +144,7 @@ @ force address lines low by reading at physical address 0 ldr r3, [r2] +#endif @ enter sleep mode mcr p14, 0, r1, c7, c0, 0 @@ -140,7 +166,7 @@ .data .align 5 ENTRY(pxa_cpu_resume) - mov r0, #PSR_I_BIT | PSR_F_BIT | MODE_SVC @ set SVC, irqs off + mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE @ set SVC, irqs off msr cpsr_c, r0 ldr r0, sleep_save_sp @ stack phys addr diff -uNr a/arch/arm/mach-pxa/sram.c b/arch/arm/mach-pxa/sram.c --- a/arch/arm/mach-pxa/sram.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/sram.c 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,283 @@ +/* + * linux/arch/arm/mach-pxa/sram.c + * + * PXA27x Internal Memory + * + * Copyright (c) 2003, Intel Corporation (yu.tang@intel.com) + * + * This software program is licensed subject to the GNU + * General Public License(GPL).Version 2,June 1991. + * available at http://www.fsf.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static u32 sram_mem = 0; + +struct sram_block_t { + u32 start; /* pointer to start of sram memory block */ + u32 end; /* pointer to first address after sram memory block */ + u32 pid; /* each entry is associated with a process id */ + struct sram_block_t *prev; + struct sram_block_t *next; +}; + +static struct sram_block_t sram_list = { 0, 0, 0, &sram_list, &sram_list }; +static u32 space_available = 0; + +int remove_sram_entry(u32 start) { + struct sram_block_t *p = sram_list.next; + int found = 0; + + while(p != &sram_list) { + if(p->start == start) { + found = 1; + break; + } + p = p->next; + } + + if(!found) return -1; + + /* p now points to the memory block to be removed */ + + p->prev->next = p->next; + p->next->prev = p->prev; + space_available += p->end - p->start; + kfree(p); + return 0; +} + +int remove_sram_pid(u32 pid) { + struct sram_block_t *p = sram_list.next; + + while(p != &sram_list) { + if(p->pid == pid) { + /* p now points to the memory block to be removed */ + p->prev->next = p->next; + p->next->prev = p->prev; + space_available += p->end - p->start; + kfree(p); + } + p = p->next; + } + + return 0; +} + +struct sram_block_t * create_sram_entry(u32 size, u32 pid) { + + struct sram_block_t *p = &sram_list, *new; + int found = 0; + + while(1) { + /* check to see if there's a gap big enough for the request */ + if(p->next == &sram_list) { + /* we're at the end of the list */ + if(SRAM_SIZE - p->end >= size) + found = 1; + break; + } else if(p->next->start - p->end >= size) { + /* middle of the list */ + found = 1; + break; + } + p = p->next; + } + + if(!found) return NULL; + + /* p now points to the memory block just prior to the new block */ + new = kmalloc(sizeof(struct sram_block_t), GFP_ATOMIC); + if(new == NULL) return NULL; + + space_available -= size; + new->start = p->end; + new->end = p->end + size; + new->pid = pid; + + new->prev = p; + new->next = p->next; + new->prev->next = new; + new->next->prev = new; + + return new; +} + +static int __init sram_init (void) +{ + /* cachable, bufferable */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + sram_mem = (u32)__ioremap( SRAM_MEM_PHYS, SRAM_SIZE, L_PTE_BUFFERABLE | L_PTE_CACHEABLE, 0); +#else + sram_mem = (u32)__ioremap( SRAM_MEM_PHYS, SRAM_SIZE, L_PTE_BUFFERABLE | L_PTE_CACHEABLE); +#endif + if(!sram_mem) goto err; + +/* Enable clcok */ + CKEN |= CKEN20_IM; + + /* All the banks are + * - Automatic wakeup enabled + * - Enter Stand-by after 255 ms + */ + IMPMCR = ( 0xff << 16) | (0x0f << 8) | (0xff); + + space_available = SRAM_SIZE; + goto out; + +err: + if (sram_mem) { + iounmap((void*)sram_mem); + sram_mem = 0; + } + + printk (KERN_WARNING "Failed to initialize SRAM\n"); + + space_available = 0; +out: + return 0; +} + +/************************************************************************* + * + * Function: xscale_sram_malloc_local + * Description: Allocates a block and returns the offest + * into the sram array, not called externally + * + * Arguments: + * size - the size in bytes of the requested allocation + * res - the return val for the allocated address + * pid - the process id of the caller (0 for drivers) + * + *************************************************************************/ + +int xscale_sram_malloc_local(size_t size, u32 *res, u32 pid) { +struct sram_block_t *new; + + if((size < 4)||(size%4 != 0)) { + printk(KERN_WARNING "SRAM Memory Full, allocation failed\n"); + return -1; + } + if(size > space_available) { + printk(KERN_WARNING "SRAM Memory Full, allocation failed\n"); + return -1; + } + new = create_sram_entry(size, pid); + if(new == NULL) { + printk(KERN_WARNING "SRAM Memory Full, allocation failed\n"); + return -1; + } + *res = new->start; + return 0; +} + +/************************************************************************* + * + * Function: xscale_sram_malloc + * Description: Allocates a block and returns the kernel space + * address (sram array offset plus kernel virtual sram start) + * + * Arguments: + * size - the size in bytes of the requested allocation + * + *************************************************************************/ + +void *xscale_sram_malloc(size_t size) { +u32 addr; + + if(xscale_sram_malloc_local(size, &addr, 0)) return NULL; + return((void *)(sram_mem + addr)); +} + +/************************************************************************* +* + * Function: xscale_sram_malloc_user + * Description: Allocates a block and returns the user + * space address by adding it to the given virtual sram base address + * + * Arguments: + * size - the size in bytes of the requested allocation + * virtual_sram_base - the virtual address of sram_base as assigned + * by a call to mmap. + * pid - the pid of the calling process + * + *************************************************************************/ + +void *xscale_sram_malloc_user(size_t size, u32 virtual_sram_base, u32 pid) { +u32 addr; + + if(xscale_sram_malloc_local(size, &addr, pid)) return NULL; + return((void *)(virtual_sram_base + addr)); +} + +/************************************************************************* + * + * Function: xscale_sram_free + * Description: Frees a block of sram from kernel space + * + * Arguments: + * ptr - the address of the block to free + * + *************************************************************************/ + +void xscale_sram_free(void *ptr) { + + if((u32)ptr >= sram_mem) + remove_sram_entry((u32)ptr - sram_mem); +} +/************************************************************************* + * + * Function: xscale_sram_free + * Description: Frees a block of sram from user space + * + * Arguments: + * ptr - the address of the block to free + * + *************************************************************************/ + +void xscale_sram_free_user(void *ptr, u32 virtual_sram_base) { + + if((u32)ptr >= virtual_sram_base) + remove_sram_entry((u32)ptr - virtual_sram_base); +} + +/************************************************************************* + * + * Function: xscale_sram_free + * Description: Frees all sram blocks for a given process + * + * Arguments: + * pid - the pid for whom all sram allocations should be freed + * +*************************************************************************/ + +void xscale_sram_free_all_pid(u32 pid) { + + if(pid == 0) { + printk(KERN_WARNING "Attempt to free memory for invalid pid, free failed\n"); + return; + } + remove_sram_pid(pid); +} + +EXPORT_SYMBOL(xscale_sram_malloc); +EXPORT_SYMBOL(xscale_sram_free); +EXPORT_SYMBOL(xscale_sram_malloc_user); +EXPORT_SYMBOL(xscale_sram_free_user); +EXPORT_SYMBOL(xscale_sram_free_all_pid); + +__initcall(sram_init); + diff -uNr a/arch/arm/mach-pxa/vcs.c b/arch/arm/mach-pxa/vcs.c --- a/arch/arm/mach-pxa/vcs.c 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm/mach-pxa/vcs.c 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,234 @@ +/* + * linux/arch/arm/mach-pxa/vcs.c + * + * Bulverde voltage change sequencer driver. + * + * Copyright (C) 2003-2004 Intel Corporation. + * + * Author: Cain Yuan + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Functionality: Initialize PWR I2C. + * Argument: None + * Return: void + */ +static int __init vcs_init(void) +{ + CKEN |= 0x1 << 15; + CKEN |= 0x1 << 14; + PCFR = PCFR_PI2CEN; +// PCFR = 0x60; + return 0; +} + +#ifdef CONFIG_PXA27x_E28 + +/* + * The voltage change process is the workround for + * E28: Core hangs during voltage change when there are outstanding + * transaction on the bus. + */ +static void pxa27x_change_voltage(void) +{ + unsigned long flags; + volatile int *ramstart; + unsigned int unused; + + printk("Workround for E28 about Core hangs during voltage change when there are outstanding transaction on the bus.\n If you want to disable workround, DO NOT set \"CONFIG_PXA27x_E28=y\"\n"); + + /* map the first page of sdram to an uncached virtual page */ + ramstart = (int *)ioremap(PHYS_OFFSET, 4096); + + local_irq_save(flags); + + __asm__ __volatile__("\n\ + @ WORKAROUND - Core hangs on voltage change at different \n\ + @ alignments and at different core clock frequencies \n\ + @ To ensure that no external fetches occur, we want to \n\ + @ store the next several instructions that occur after the \n\ + @ voltage change inside the cache. The load dependency \n\ + @ stall near the retry label ensures that any outstanding \n\ + @ instruction cacheline loads are complete before \n\ + @ the mcr instruction is executed on the 2nd pass. \n\ + @ This procedure ensures us that the internal bus will not \n\ + @ be busy. \n\ + \n\ + b 2f \n\ + nop \n\ + .align 5 \n\ + 2: \n\ + ldr r0, [%1] @ APB register read and compare \n\ + cmp r0, #0 @ fence for pending slow apb reads \n\ + \n\ + mov r0, #8 @ VC bit for PWRMODE \n\ + movs r1, #1 @ don't execute mcr on 1st pass \n\ + \n\ + @ %1 points to uncacheable memory to force memory read \n\ + \n\ + retry: \n\ + ldreq r3, [%2] @ only stall on the 2nd pass\n\ + cmpeq r3, #0 @ cmp causes fence on mem transfers\n\ + cmp r1, #0 @ is this the 2nd pass? \n\ + mcreq p14, 0, r0, c7, c0, 0 @ write to PWRMODE on 2nd pass only \n\ + \n\ + @ Read VC bit until it is 0, indicates that the VoltageChange is done.\n\ + @ On first pass, we never set the VC bit, so it will be clear already.\n\ + \n\ + VoltageChange_loop: \n\ + mrc p14, 0, r3, c7, c0, 0 \n\ + tst r3, #0x8 \n\ + bne VoltageChange_loop \n\ + \n\ + subs r1, r1, #1 @ update conditional execution counter\n\ + beq retry" + + : "=&r" (unused) + : "r" (&CCCR), "r" (ramstart) + : "r0", "r1", "r3" ); + + local_irq_restore(flags); + + /* unmap the page we used */ + iounmap(ramstart); +} + +#else + +static void pxa27x_change_voltage(void) +{ + unsigned long flags; + + local_irq_save(flags); + + __asm__ __volatile__(" \n\ + mrc p14, 0, r0, c7, c0, 0 @ read c7 \n\ + orr r0, r0, #0x8 @ Voltage change sequence begins \n\ + mcr p14, 0, r0, c7, c0, 0 @ set the bit. \n\ + mrc p14, 0, r0, c7, c0, 0 @ read c7 \n\ + mov r0, r0 \n\ + nop \n\ + nop" + : + : + :"r0" ); + + local_irq_restore(flags); +} + +#endif + +static void clr_all_sqc(void) +{ + int i = 0; + for (i = 0; i < 32; i++) + PCMD(i) &= ~PCMD_SQC; +} + +static void clr_all_mbc(void) +{ + int i = 0; + for (i = 0; i < 32; i++) + PCMD(i) &= ~PCMD_MBC; +} + +static void clr_all_dce(void) +{ + int i = 0; + for (i = 0; i < 32; i++) + PCMD(i) &= ~PCMD_DCE; +} + +static void set_mbc_bit(int ReadPointer, int NumOfBytes) +{ + PCMD0 |= PCMD_MBC; + PCMD1 |= PCMD_MBC; +} + +static void set_lc_bit(int ReadPointer, int NumOfBytes) +{ + PCMD0 |= PCMD_LC; + PCMD1 |= PCMD_LC; + PCMD2 |= PCMD_LC; +} + +static void set_cmd_data(unsigned char *DataArray, int StartPoint, int size) +{ + PCMD0 &= 0xFFFFFF00; + PCMD0 |= DataArray[0]; + PCMD1 &= 0xFFFFFF00; + PCMD1 |= DataArray[1]; + PCMD2 &= 0xFFFFFF00; + PCMD2 |= DataArray[2]; +} + +static void ipm_power_change_cmd(unsigned int DACValue) +{ + unsigned char dataArray[3]; + + dataArray[0] = 0; /* Command 0 */ + dataArray[1] = (DACValue & 0x000000FF); /* data LSB */ + dataArray[2] = (DACValue & 0x0000FF00) >> 8; /* data MSB */ + + PVCR = 0; + + PCFR &= ~PCFR_FVC; + PVCR &= 0xFFFFF07F; /* no delay is necessary */ + PVCR &= 0xFFFFFF80; /* clear slave address */ + PVCR |= 0x20; /* set slave address */ + + PVCR &= 0xFE0FFFFF; /* clear read pointer 0 */ + PVCR |= 0; + + /* DCE and SQC are not necessary for single command */ + clr_all_sqc(); + clr_all_dce(); + + clr_all_mbc(); + set_mbc_bit(0, 2); + + /* indicate the last byte of this command is holded in this register */ + PCMD2 &= ~PCMD_MBC; + + /* indicate this is the first command and last command also */ + set_lc_bit(0, 3); + + /* programming the command data bit */ + set_cmd_data(dataArray, 0, 2); +} + +void vm_setvoltage(unsigned int DACValue) +{ + printk("vm_setvoltage\n"); + ipm_power_change_cmd(DACValue); + /* Enable Power I2C */ + PCFR |= PCFR_PI2CEN; + /* Execute voltage change sequence */ + pxa27x_change_voltage(); //set VC on the PWRMODE on CP14 +} + +/* + * Prepare for a coupled voltage & frequency change + */ +void vm_pre_setvoltage(unsigned int DACValue) +{ + ipm_power_change_cmd(DACValue); + /* Enable Power I2C */ + PCFR |= (PCFR_PI2CEN | PCFR_FVC); +} + + +module_init(vcs_init); diff -uNr a/drivers/char/Kconfig b/drivers/char/Kconfig --- a/drivers/char/Kconfig 2004-10-19 05:53:07.000000000 +0800 +++ b/drivers/char/Kconfig 2005-01-27 09:56:48.000000000 +0800 @@ -729,6 +729,12 @@ To compile this driver as a module, choose M here: the module will be called rtc. +config PXA_RTC + tristate "PXA27x/25x/21x or SA1100 Real Time Clock Support" + depends on ARCH_PXA || ARCH_SA1100 + default y + ---help--- + config SGI_DS1286 tristate "SGI DS1286 RTC support" depends on SGI_IP22 diff -uNr a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile 2004-10-19 05:55:28.000000000 +0800 +++ b/drivers/char/Makefile 2005-01-27 09:56:48.000000000 +0800 @@ -58,6 +58,7 @@ obj-$(CONFIG_APPLICOM) += applicom.o obj-$(CONFIG_SONYPI) += sonypi.o obj-$(CONFIG_RTC) += rtc.o +obj-$(CONFIG_PXA_RTC) += sa1100-rtc.o obj-$(CONFIG_HPET) += hpet.o obj-$(CONFIG_GEN_RTC) += genrtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o diff -uNr a/drivers/char/sa1100-rtc.c b/drivers/char/sa1100-rtc.c --- a/drivers/char/sa1100-rtc.c 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/char/sa1100-rtc.c 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,491 @@ +/* + * Real Time Clock interface for Linux on StrongARM SA1100 + * and XScale PXA250/210. + * + * Copyright (c) 2000 Nils Faerber + * + * Based on rtc.c by Paul Gortmaker + * Date/time conversion routines taken from arch/arm/kernel/time.c + * by Linus Torvalds and Russel King + * and the GNU C Library + * ( ... I love the GPL ... just take what you need! ;) + * + * 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. + * + * 1.00 2001-06-08 Nicolas Pitre + * - added periodic timer capability using OSMR1 + * - flag compatibility with other RTC chips + * - permission checks for ioctls + * - major cleanup, partial rewrite + * + * 0.03 2001-03-07 CIH + * - Modify the bug setups RTC clock. + * + * 0.02 2001-02-27 Nils Faerber + * - removed mktime(), added alarm irq clear + * + * 0.01 2000-10-01 Nils Faerber + * - initial release + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "1.00" + +#if defined(CONFIG_PXA27x) +/* + * Bulverde timer + */ +#define TIMER_FREQ 3250000 +#else +/* + * PXA250/210/SA timer + */ +#define TIMER_FREQ 3686400 +#endif + + +#define RTC_DEF_DIVIDER 32768 - 1 +#define RTC_DEF_TRIM 0 + +/* Those are the bits from a classic RTC we want to mimic */ +#define RTC_IRQF 0x80 /* any of the following 3 is active */ +#define RTC_PF 0x40 +#define RTC_AF 0x20 +#define RTC_UF 0x10 + +static unsigned long rtc_status; +static unsigned long rtc_irq_data; +static unsigned long rtc_freq = 1024; + +static struct fasync_struct *rtc_async_queue; +static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); + +extern spinlock_t rtc_lock; + +static const unsigned char days_in_mo[] = + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +#define is_leap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +/* + * Converts seconds since 1970-01-01 00:00:00 to Gregorian date. + */ + +static void decodetime (unsigned long t, struct rtc_time *tval) +{ + long days, month, year, rem; + + days = t / 86400; + rem = t % 86400; + tval->tm_hour = rem / 3600; + rem %= 3600; + tval->tm_min = rem / 60; + tval->tm_sec = rem % 60; + tval->tm_wday = (4 + days) % 7; + +#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) + + year = 1970 + days / 365; + days -= ((year - 1970) * 365 + + LEAPS_THRU_END_OF (year - 1) + - LEAPS_THRU_END_OF (1970 - 1)); + if (days < 0) { + year -= 1; + days += 365 + is_leap(year); + } + tval->tm_year = year - 1900; + tval->tm_yday = days + 1; + + month = 0; + if (days >= 31) { + days -= 31; + month++; + if (days >= (28 + is_leap(year))) { + days -= (28 + is_leap(year)); + month++; + while (days >= days_in_mo[month]) { + days -= days_in_mo[month]; + month++; + } + } + } + tval->tm_mon = month; + tval->tm_mday = days + 1; +} + +static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int rtsr = RTSR; + + /* clear interrupt sources */ + RTSR = 0; + RTSR = (RTSR_AL|RTSR_HZ); + + /* clear alarm interrupt if it has occurred */ + if (rtsr & RTSR_AL) + rtsr &= ~RTSR_ALE; + RTSR = rtsr & (RTSR_ALE|RTSR_HZE); + + /* update irq data & counter */ + if (rtsr & RTSR_AL) + rtc_irq_data |= (RTC_AF|RTC_IRQF); + if (rtsr & RTSR_HZ) + rtc_irq_data |= (RTC_UF|RTC_IRQF); + rtc_irq_data += 0x100; + + /* wake up waiting process */ + wake_up_interruptible(&rtc_wait); + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); + + return IRQ_HANDLED; +} + +static irqreturn_t timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * If we match for the first time, the periodic interrupt flag won't + * be set. If it is, then we did wrap around (very unlikely but + * still possible) and compute the amount of missed periods. + * The match reg is updated only when the data is actually retrieved + * to avoid unnecessary interrupts. + */ + OSSR = OSSR_M1; /* clear match on timer1 */ + if (rtc_irq_data & RTC_PF) { + rtc_irq_data += (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))) << 8; + } else { + rtc_irq_data += (0x100|RTC_PF|RTC_IRQF); + } + + wake_up_interruptible(&rtc_wait); + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); + + return IRQ_HANDLED; +} + +static int rtc_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit (1, &rtc_status)) + return -EBUSY; + rtc_irq_data = 0; + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + spin_lock_irq (&rtc_lock); + RTSR = 0; + RTSR = (RTSR_AL|RTSR_HZ); + OIER &= ~OIER_E1; + OSSR = OSSR_M1; + spin_unlock_irq (&rtc_lock); + rtc_status = 0; + return 0; +} + +static int rtc_fasync (int fd, struct file *filp, int on) +{ + return fasync_helper (fd, filp, on, &rtc_async_queue); +} + +static unsigned int rtc_poll(struct file *file, poll_table *wait) +{ + poll_wait (file, &rtc_wait, wait); + return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM; +} + +static loff_t rtc_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long data; + ssize_t retval; + + if (count < sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&rtc_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + for (;;) { + spin_lock_irq (&rtc_lock); + data = rtc_irq_data; + if (data != 0) { + rtc_irq_data = 0; + break; + } + spin_unlock_irq (&rtc_lock); + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + schedule(); + } + + if (data & RTC_PF) { + /* interpolate missed periods and set match for the next one */ + unsigned long period = TIMER_FREQ/rtc_freq; + unsigned long oscr = OSCR; + unsigned long osmr1 = OSMR1; + unsigned long missed = (oscr - osmr1)/period; + data += missed << 8; + OSSR = OSSR_M1; /* clear match on timer 1 */ + OSMR1 = osmr1 + (missed + 1)*period; + /* ensure we didn't miss another match in the mean time */ + while( (signed long)((osmr1 = OSMR1) - OSCR) <= 0 ) { + data += 0x100; + OSSR = OSSR_M1; /* clear match on timer 1 */ + OSMR1 = osmr1 + period; + } + } + spin_unlock_irq (&rtc_lock); + + data -= 0x100; /* the first IRQ wasn't actually missed */ + + retval = put_user(data, (unsigned long *)buf); + if (!retval) + retval = sizeof(unsigned long); + +out: + set_current_state(TASK_RUNNING); + remove_wait_queue(&rtc_wait, &wait); + return retval; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct rtc_time tm, tm2; + + switch (cmd) { + case RTC_AIE_OFF: + spin_lock_irq(&rtc_lock); + RTSR &= ~RTSR_ALE; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + case RTC_AIE_ON: + spin_lock_irq(&rtc_lock); + RTSR |= RTSR_ALE; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + case RTC_UIE_OFF: + spin_lock_irq(&rtc_lock); + RTSR &= ~RTSR_HZE; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + case RTC_UIE_ON: + spin_lock_irq(&rtc_lock); + RTSR |= RTSR_HZE; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + case RTC_PIE_OFF: + spin_lock_irq(&rtc_lock); + OIER &= ~OIER_E1; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + case RTC_PIE_ON: + if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE)) + return -EACCES; + spin_lock_irq(&rtc_lock); + OSMR1 = TIMER_FREQ/rtc_freq + OSCR; + OIER |= OIER_E1; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + case RTC_ALM_READ: + decodetime (RTAR, &tm); + break; + case RTC_ALM_SET: + if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2))) + return -EFAULT; + decodetime (RCNR, &tm); + if ((unsigned)tm2.tm_hour < 24) + tm.tm_hour = tm2.tm_hour; + if ((unsigned)tm2.tm_min < 60) + tm.tm_min = tm2.tm_min; + if ((unsigned)tm2.tm_sec < 60) + tm.tm_sec = tm2.tm_sec; + RTAR = mktime ( tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + return 0; + case RTC_RD_TIME: + decodetime (RCNR, &tm); + break; + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + return -EACCES; + if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm))) + return -EFAULT; + tm.tm_year += 1900; + if (tm.tm_year < 1970 || (unsigned)tm.tm_mon >= 12 || + tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] + + (tm.tm_mon == 1 && is_leap(tm.tm_year))) || + (unsigned)tm.tm_hour >= 24 || + (unsigned)tm.tm_min >= 60 || + (unsigned)tm.tm_sec >= 60) + return -EINVAL; + RCNR = mktime ( tm.tm_year, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + return 0; + case RTC_IRQP_READ: + return put_user(rtc_freq, (unsigned long *)arg); + case RTC_IRQP_SET: + if (arg < 1 || arg > TIMER_FREQ) + return -EINVAL; + if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) + return -EACCES; + rtc_freq = arg; + return 0; + case RTC_EPOCH_READ: + return put_user (1970, (unsigned long *)arg); + default: + return -EINVAL; + } + return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0; +} + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: rtc_llseek, + read: rtc_read, + poll: rtc_poll, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, + fasync: rtc_fasync, +}; + +static struct miscdevice sa1100rtc_miscdev = { + RTC_MINOR, + "rtc", + &rtc_fops +}; + +static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *p = page; + int len; + struct rtc_time tm; + + decodetime (RCNR, &tm); + p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1970); + decodetime (RTAR, &tm); + p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n" + "alrm_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + p += sprintf(p, "trim/divider\t: 0x%08x\n", RTTR); + p += sprintf(p, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" ); + p += sprintf(p, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no"); + p += sprintf(p, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no"); + p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; +} + +static int __init rtc_init(void) +{ + int ret; + + misc_register (&sa1100rtc_miscdev); + create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); + ret = request_irq (IRQ_RTC1Hz, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL); + if (ret) { + printk (KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTC1Hz); + goto IRQ_RTC1Hz_failed; + } + ret = request_irq (IRQ_RTCAlrm, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL); + if (ret) { + printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTCAlrm); + goto IRQ_RTCAlrm_failed; + } + ret = request_irq (IRQ_OST1, timer1_interrupt, SA_INTERRUPT, "rtc timer", NULL); + if (ret) { + printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_OST1); + goto IRQ_OST1_failed; + } + + printk (KERN_INFO "SA1100 Real Time Clock driver v" DRIVER_VERSION "\n"); + + /* + * According to the manual we should be able to let RTTR be zero + * and then a default diviser for a 32.768KHz clock is used. + * Apparently this doesn't work, at least for my SA1110 rev 5. + * If the clock divider is uninitialized then reset it to the + * default value to get the 1Hz clock. + */ + if (RTTR == 0) { + RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); + printk (KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n"); + /* The current RTC value probably doesn't make sense either */ + RCNR = 0; + } + + return 0; + +IRQ_OST1_failed: + free_irq (IRQ_RTCAlrm, NULL); +IRQ_RTCAlrm_failed: + free_irq (IRQ_RTC1Hz, NULL); +IRQ_RTC1Hz_failed: + remove_proc_entry ("driver/rtc", NULL); + misc_deregister (&sa1100rtc_miscdev); + return ret; +} + +static void __exit rtc_exit(void) +{ + free_irq (IRQ_OST1, NULL); + free_irq (IRQ_RTCAlrm, NULL); + free_irq (IRQ_RTC1Hz, NULL); + remove_proc_entry ("driver/rtc", NULL); + misc_deregister (&sa1100rtc_miscdev); +} + +module_init(rtc_init); +module_exit(rtc_exit); + +MODULE_AUTHOR("Nils Faerber "); +MODULE_DESCRIPTION("SA1100/PXA Realtime Clock Driver (RTC)"); diff -uNr a/drivers/i2c/algos/i2c-algo-pxa.c b/drivers/i2c/algos/i2c-algo-pxa.c --- a/drivers/i2c/algos/i2c-algo-pxa.c 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/i2c/algos/i2c-algo-pxa.c 2005-01-27 09:56:48.000000000 +0800 @@ -0,0 +1,381 @@ +/* + * i2c-algo-pxa.c + * + * I2C algorithm for the PXA I2C bus access. + * Byte driven algorithm similar to pcf. + * + * Copyright (C) 2002 Intrinsyc Software Inc. + * + * 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. + * + * History: + * Apr 2002: Initial version [CS] + * Jun 2002: Properly seperated algo/adap [FB] + * Jan 2003: added limited signal handling [Kai-Uwe Bloem] + * Jan 2003: allow SMBUS_QUICK as valid msg [FB] + * Sep 2004: ported to 2.6 kernel, Yan Yin + * + */ +#include +#include + +#include +#include +#include +#include /* struct i2c_msg and others */ +#include + +#include + +/* + * Set this to zero to remove all the debug statements via dead code elimination. + */ +//#define DEBUG 1 + +#if DEBUG +static unsigned int i2c_debug = DEBUG; +#else +#define i2c_debug 0 +#endif + +static int pxa_scan = 1; + +static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num) +{ + int i; + if (num < 1 || num > MAX_MESSAGES){ + if( i2c_debug) + printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n", + MAX_MESSAGES, num); + return -EINVAL; + } + + /* check consistency of our messages */ + for (i=0;ialgo_data; + + /* increment number of bytes to read by one -- read dummy byte */ + for (i = 0; i <= count; i++) { + if (i!=0){ + /* set ACK to NAK for last received byte ICR[ACKNAK] = 1 + only if not a repeated start */ + + if ((i == count) && last) { + adap->transfer( last, I2C_RECEIVE, 0); + }else{ + adap->transfer( 0, I2C_RECEIVE, 1); + } + + timeout = adap->wait_for_interrupt(I2C_RECEIVE); + +#ifdef DEBUG + if (timeout==BUS_ERROR){ + printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing reset\n"); + adap->reset(); + return I2C_RETRY; + } else +#endif + if (timeout == -ERESTARTSYS) { + adap->abort(); + return timeout; + } else + if (timeout){ +#ifdef DEBUG + printk(KERN_INFO "i2c_pxa_readbytes: timeout -> forcing reset\n"); +#endif + adap->reset(); + return I2C_RETRY; + } + + } + + if (i) { + buf[i - 1] = adap->read_byte(); + } else { + adap->read_byte(); /* dummy read */ + } + } + return (i - 1); +} + +static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, + int count, int last) +{ + + struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; + int wrcount, timeout; + + for (wrcount=0; wrcountwrite_byte(buf[wrcount]); + if ((wrcount==(count-1)) && last) { + adap->transfer( last, I2C_TRANSMIT, 0); + }else{ + adap->transfer( 0, I2C_TRANSMIT, 1); + } + + timeout = adap->wait_for_interrupt(I2C_TRANSMIT); + +#ifdef DEBUG + if (timeout==BUS_ERROR) { + printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.\n"); + adap->reset(); + return I2C_RETRY; + } else +#endif + if (timeout == -ERESTARTSYS) { + adap->abort(); + return timeout; + } else + if (timeout) { +#ifdef DEBUG + printk(KERN_INFO "i2c_pxa_sendbytes: timeout -> forcing reset\n"); +#endif + adap->reset(); + return I2C_RETRY; + } + } + return (wrcount); +} + + +static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg) +{ + u16 flags = msg->flags; + u8 addr; + addr = (u8) ( (0x7f & msg->addr) << 1 ); + if (flags & I2C_M_RD ) + addr |= 1; + if (flags