From 2467f6cd5542806395559f583e69a57fa84a2fb8 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 9 May 2015 06:24:56 -0300 Subject: openexr-2.2.0-2.parabola1: updating version --- libre/openexr/PKGBUILD | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'libre') diff --git a/libre/openexr/PKGBUILD b/libre/openexr/PKGBUILD index 715bb6a1f..334326e07 100644 --- a/libre/openexr/PKGBUILD +++ b/libre/openexr/PKGBUILD @@ -1,17 +1,17 @@ -# $Id: PKGBUILD 212797 2014-05-15 10:44:29Z tpowa $ +# $Id: PKGBUILD 238700 2015-05-08 16:56:07Z tpowa $ # Maintainer (Arch): Tobias Powalowski # Maintainer: André Silva pkgname=openexr _pkgname=$pkgname-libre -pkgver=2.1.0 -pkgrel=1.parabola1 +pkgver=2.2.0 +pkgrel=2.parabola1 pkgdesc="An high dynamic-range image file format library, without embedded nonfree fonts in the documentation" url="http://www.$pkgname.com/" arch=('i686' 'x86_64' 'mips64el') license=('BSD') depends=('zlib' 'ilmbase') -makedepends=('jre7-openjdk-headless' 'libcups' 'libreoffice-writer' 'libxinerama') +makedepends=('unoconv') replaces=("$_pkgname") conflicts=("$_pkgname") mksource=("http://download.savannah.nongnu.org/releases/${pkgname}/${pkgname}-${pkgver}.tar.gz" @@ -33,11 +33,9 @@ mksource() { install -m644 -v "${srcdir}/"{InterpretingDeepPixels.docx,{MultiViewOpenEXR,OpenEXRFileLayout,ReadingAndWritingImageFiles,TechnicalIntroduction}.odt} doc # convert source documentation to pdf format and clean source code - if [ "$CARCH" != "mips64el" ]; then - cd doc - libreoffice --headless --invisible --convert-to pdf {InterpretingDeepPixels.docx,{MultiViewOpenEXR,OpenEXRFileLayout,ReadingAndWritingImageFiles,TechnicalIntroduction}.odt} - rm -rv "${srcdir}/"{_rels,Configurations2,customXml,docProps,META-INF,ObjBFFFDCA{1,3,4,5,7},Object\ 1,ObjectReplacements,Pictures,Thumbnails,word} - fi + cd doc + unoconv -v -f pdf {InterpretingDeepPixels.docx,{MultiViewOpenEXR,OpenEXRFileLayout,ReadingAndWritingImageFiles,TechnicalIntroduction}.odt} + rm -rv "${srcdir}/"{_rels,Configurations2,customXml,docProps,META-INF,ObjBFFFDCA{1,3,4,5,7},Object\ 1,ObjectReplacements,Pictures,Thumbnails,word} } prepare() { @@ -59,10 +57,10 @@ package() { install -D -m644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" install -m644 "doc/"{InterpretingDeepPixels.docx,{MultiViewOpenEXR,OpenEXRFileLayout,ReadingAndWritingImageFiles,TechnicalIntroduction}.odt} "${pkgdir}/usr/share/doc/OpenEXR-${pkgver}" } -mkmd5sums=('33735d37d2ee01c6d8fbd0df94fb8b43' +mkmd5sums=('b64e931c82aa3790329c21418373db4e' 'a59a8516d9dbb76755cb258d18cf4e72' '0b0b41269d6a3ee1a7090067cc89895f' '6889a150ab9f2f35fbc9835373dd3c34' 'ef6912faf2ab7516678bd0fa56b832f8' '232a6be90fd36ce49e213492a60d335d') -md5sums=('97613563c17dc3a1aa3359e05b7b37da') +md5sums=('0c25d11578b23e9f5b12a3071187b171') -- cgit v1.2.3 From e45fbbf93a20bbae0a421bc87e04b7428321ba1f Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 9 May 2015 11:06:12 -0300 Subject: blender-16:2.74-3.parabola1: rebuild against openexr 2.2 --- libre/blender/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libre') diff --git a/libre/blender/PKGBUILD b/libre/blender/PKGBUILD index 2accda59e..704831dcc 100644 --- a/libre/blender/PKGBUILD +++ b/libre/blender/PKGBUILD @@ -29,7 +29,7 @@ _pkgver=2.74 _depver=${_pkgver%[a-z]} [[ $_git == no ]] && pkgver=$_pkgver [[ $_git == yes ]] && pkgver=$_pkgver.git1.$_gitcommit -pkgrel=2.parabola1 +pkgrel=3.parabola1 epoch=16 _jpgver=1.5 _llvmver=3.5 -- cgit v1.2.3 From 55a48004dd3e6ec98df57254cf3be4b4a7dba38b Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 9 May 2015 11:43:40 -0300 Subject: linux-libre-4.0.2_gnu-1: updating version * reenable CONFIG_MEMCG_KMEM --- ...-enable-CS_PARSER_ERROR-interrupts-at-all.patch | 66 ---------------------- libre/linux-libre/PKGBUILD | 16 ++---- libre/linux-libre/config.i686 | 6 +- libre/linux-libre/config.mips64el | 6 +- libre/linux-libre/config.x86_64 | 6 +- 5 files changed, 14 insertions(+), 86 deletions(-) delete mode 100644 libre/linux-libre/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch (limited to 'libre') diff --git a/libre/linux-libre/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch b/libre/linux-libre/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch deleted file mode 100644 index 4e801b3cc..000000000 --- a/libre/linux-libre/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch +++ /dev/null @@ -1,66 +0,0 @@ -From b27b2ff4bd6f0327ee550baa0397ccf0a559821f Mon Sep 17 00:00:00 2001 -From: Daniel Vetter -Date: Wed, 1 Apr 2015 13:40:48 +0200 -Subject: [PATCH] drm/i915: Dont enable CS_PARSER_ERROR interrupts at all - -We stopped handling them in - -commit aaecdf611a05cac26a94713bad25297e60225c29 -Author: Daniel Vetter -Date: Tue Nov 4 15:52:22 2014 +0100 - - drm/i915: Stop gathering error states for CS error interrupts - -but just clearing is apparently not enough: A sufficiently dead gpu -left behind by firmware (*cough* coreboot *cough*) can keep the gpu in -an endless loop of such interrupts, eventually leading to the nmi -firing. And definitely to what looks like a machine hang. - -Since we don't even enable these interrupts on gen5+ let's do the same -on earlier platforms. - -Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=93171 -Signed-off-by: Daniel Vetter ---- - drivers/gpu/drm/i915/i915_irq.c | 8 ++------ - 1 file changed, 2 insertions(+), 6 deletions(-) - -diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index 14ecb4d13a1a..6d494432b19f 100644 ---- a/drivers/gpu/drm/i915/i915_irq.c -+++ b/drivers/gpu/drm/i915/i915_irq.c -@@ -3598,14 +3598,12 @@ static int i8xx_irq_postinstall(struct drm_device *dev) - ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | -- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); -+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); - I915_WRITE16(IMR, dev_priv->irq_mask); - - I915_WRITE16(IER, - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | - I915_USER_INTERRUPT); - POSTING_READ16(IER); - -@@ -3767,14 +3765,12 @@ static int i915_irq_postinstall(struct drm_device *dev) - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | -- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); -+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); - - enable_mask = - I915_ASLE_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | - I915_USER_INTERRUPT; - - if (I915_HAS_HOTPLUG(dev)) { --- -2.1.4 - diff --git a/libre/linux-libre/PKGBUILD b/libre/linux-libre/PKGBUILD index 951f6429a..b4c00da84 100644 --- a/libre/linux-libre/PKGBUILD +++ b/libre/linux-libre/PKGBUILD @@ -9,7 +9,7 @@ pkgbase=linux-libre # Build stock "" kernel _pkgbasever=4.0-gnu -_pkgver=4.0.1-gnu +_pkgver=4.0.2-gnu _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -34,22 +34,20 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li 'linux.preset' 'logo_linux_'{clut224.ppm,vga16.ppm,mono.pbm} 'change-default-console-loglevel.patch' - '0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch' # loongson-community patch: http://linux-libre.fsfla.org/pub/linux-libre/lemote/gnewsense/pool/debuginfo/ '4.0-rc7-37af2c8aae-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - 'b99335ed7c60ba2701d81923de4e3e9efbbfa3ad0782e7d94cd48b92adb1fbd6' + '6b559c4393922896752822a63d22fb51f4aad0d8feb123a9c7a518d25ca7b378' 'SKIP' - '872203c34c5db72a1dc62e8152c89c90469743b39f3e91cbdb1f9bb5c24ab4c1' - '2d76fb20424573559289ab061312971ae1a508a15375513c9f28e5cb84f4515a' - '4e05992849d2db2caaa3cc56f307c82ca4376441d4cad51a5f3611f10866a2a4' + 'a9a0590e45ec7b3913f0da294c52bbd6f4c0034a1ef1fedb83f3c6347003f499' + '69f73083d02e937e4c47a88c559da55a45efa17a6740459d0a002aa8ccfd89c2' + '254fff11b9dc1e33637615cfafebaa2838ed6e5b59b4200dcfbe775cbbe7f2c2' 'f0d90e756f14533ee67afda280500511a62465b4f76adcc5effa95a40045179c' 'bfd4a7f61febe63c880534dcb7c31c5b932dde6acf991810b41a939a93535494' '6de8a8319271809ffdb072b68d53d155eef12438e6d04ff06a5a4db82c34fa8a' '13bd7a8d9ed6b6bc971e4cd162262c5a20448a83796af39ce394d827b0e5de74' '1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99' - '66cb2d859b253bc4e793baa3c0b95523d647a773b957dbc79b3eaacccf8692b5' '6fd223e0e11421f87ff4c913b61636ecbbecf249f431ba87a1288463b847f26c') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva @@ -85,10 +83,6 @@ prepare() { # (relevant patch sent upstream: https://lkml.org/lkml/2011/7/26/227) patch -p1 -i "${srcdir}/change-default-console-loglevel.patch" - # drm/i915: Stop gathering error states for CS error interrupts - # https://bugzilla.kernel.org/show_bug.cgi?id=93171 - patch -p1 -i "${srcdir}/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch" - # Adding loongson-community patch if [ "${CARCH}" == "mips64el" ]; then patch -p1 -i ${srcdir}/4.0-rc7-37af2c8aae-loongson-community.patch diff --git a/libre/linux-libre/config.i686 b/libre/linux-libre/config.i686 index 0219f13de..0754e396b 100644 --- a/libre/linux-libre/config.i686 +++ b/libre/linux-libre/config.i686 @@ -151,8 +151,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_HUGETLB is not set # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y @@ -5770,7 +5770,7 @@ CONFIG_VIRTIO=m # Virtio drivers # CONFIG_VIRTIO_PCI=m -CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_PCI_LEGACY=y CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y diff --git a/libre/linux-libre/config.mips64el b/libre/linux-libre/config.mips64el index c4a665344..f5961b335 100644 --- a/libre/linux-libre/config.mips64el +++ b/libre/linux-libre/config.mips64el @@ -273,8 +273,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y CONFIG_FAIR_GROUP_SCHED=y @@ -5055,7 +5055,7 @@ CONFIG_VIRTIO=m # Virtio drivers # CONFIG_VIRTIO_PCI=m -CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_PCI_LEGACY=y CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y diff --git a/libre/linux-libre/config.x86_64 b/libre/linux-libre/config.x86_64 index f254e91cf..cc69f030f 100644 --- a/libre/linux-libre/config.x86_64 +++ b/libre/linux-libre/config.x86_64 @@ -159,8 +159,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_HUGETLB is not set # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y @@ -5541,7 +5541,7 @@ CONFIG_VIRTIO=m # Virtio drivers # CONFIG_VIRTIO_PCI=m -CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_PCI_LEGACY=y CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y -- cgit v1.2.3 From 38c4074ea8ab6039cbdbb03052f73fcf65666e50 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 9 May 2015 15:44:13 -0300 Subject: linux-libre-lts-3.14.41_gnu-1: updating version * build with testing gcc-5; apply some upstream fixes for gcc-5 related build problems, disable a few modules that are not trivial to fix and where no simple upstream fix is available --- libre/linux-libre-lts/PKGBUILD | 18 +++-- libre/linux-libre-lts/config.i686 | 14 ++-- libre/linux-libre-lts/config.mips64el | 14 ++-- libre/linux-libre-lts/config.x86_64 | 14 ++-- libre/linux-libre-lts/gcc5_buildfixes.diff | 115 +++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+), 26 deletions(-) create mode 100644 libre/linux-libre-lts/gcc5_buildfixes.diff (limited to 'libre') diff --git a/libre/linux-libre-lts/PKGBUILD b/libre/linux-libre-lts/PKGBUILD index fa2557be6..8c7aa4b08 100644 --- a/libre/linux-libre-lts/PKGBUILD +++ b/libre/linux-libre-lts/PKGBUILD @@ -9,7 +9,7 @@ pkgbase=linux-libre-lts # Build kernel with -lts localname _pkgbasever=3.14-gnu -_pkgver=3.14.40-gnu +_pkgver=3.14.41-gnu _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -38,15 +38,16 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li '0002-module-allow-multiple-calls-to-MODULE_DEVICE_TABLE-p.patch' '0003-module-remove-MODULE_GENERIC_TABLE.patch' '0006-genksyms-fix-typeof-handling.patch' + 'gcc5_buildfixes.diff' # loongson-community patch: http://linux-libre.fsfla.org/pub/linux-libre/lemote/gnewsense/pool/debuginfo/ '3.14.26-8475f027b4-loongson-community.patch') sha256sums=('477555c709b9407fe37dbd70d3331ff9dde1f9d874aba2741f138d07ae6f281b' 'SKIP' - 'ce132b3c3e72019cea2ab9bf5cb11871531ee60f06157e9ed8edf2115fa07693' + '120e97db433d48fb6d099497baa0da5b335eeb5ec48882a5c6911e93b6b08781' 'SKIP' - 'a3d5c9546d61a84c93e59ba0a5cd725715b87cb1171aa224ff1ff960331e3fb1' - '66edce909f5e051966c42ed104effb2fb706ef1340a4e248b184059f0ae90ab8' - '18a94cb727c2cae80b1dbd3cddbb1e5484458d4c01b026b69cea68bc2df162d7' + 'b4cc9c49948fc1d571c27ddeddd93b5b499ccc17fb06fa75bfe41ecddfbc12e4' + '3fa8ce26aea9b5e596ccfc842baa3f2a8be8ef4a62bc13d75e8da2bafd89141c' + 'f15f2cf744d402e575713e4d500b82e7bcf8983aef5c97f82dcc9400ba4487f0' 'f0d90e756f14533ee67afda280500511a62465b4f76adcc5effa95a40045179c' 'bfd4a7f61febe63c880534dcb7c31c5b932dde6acf991810b41a939a93535494' '6de8a8319271809ffdb072b68d53d155eef12438e6d04ff06a5a4db82c34fa8a' @@ -56,6 +57,7 @@ sha256sums=('477555c709b9407fe37dbd70d3331ff9dde1f9d874aba2741f138d07ae6f281b' '52dec83a8805a8642d74d764494acda863e0aa23e3d249e80d4b457e20a3fd29' '65d58f63215ee3c5f9c4fc6bce36fc5311a6c7dbdbe1ad29de40647b47ff9c0d' 'cf2e7a2d00787f754028e7459688c2755a406e632ce48b60952fa4ff7ed6f4b7' + '470d6d019d288dce02b4a9758a34ea71d41715663a19a164749212a470a131e7' '7c2d1e257acce0ea6f260f3acf18e30e21c12a9a6b3d7d1d4097dafd287388e2') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva @@ -83,6 +85,12 @@ prepare() { install -m644 -t drivers/video/logo \ "${srcdir}/logo_linux_"{clut224.ppm,vga16.ppm,mono.pbm} + # buildfixes for gcc5 + # https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/scsi/qla2xxx/qla_nx2.c?id=9493c2422cae272d6f1f567cbb424195defe4176 + # https://lkml.org/lkml/2014/11/9/27 + # https://lkml.org/lkml/2014/12/14/55 + patch -p1 -i "${srcdir}/gcc5_buildfixes.diff" + # add latest fixes from stable queue, if needed # http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git diff --git a/libre/linux-libre-lts/config.i686 b/libre/linux-libre-lts/config.i686 index 70e91244f..cd24fdfcb 100644 --- a/libre/linux-libre-lts/config.i686 +++ b/libre/linux-libre-lts/config.i686 @@ -1870,7 +1870,7 @@ CONFIG_MEGARAID_NEWGEN=y CONFIG_MEGARAID_MM=m CONFIG_MEGARAID_MAILBOX=m CONFIG_MEGARAID_LEGACY=m -CONFIG_MEGARAID_SAS=m +# CONFIG_MEGARAID_SAS is not set CONFIG_SCSI_MPT2SAS=m CONFIG_SCSI_MPT2SAS_MAX_SGE=128 # CONFIG_SCSI_MPT2SAS_LOGGING is not set @@ -5631,21 +5631,21 @@ CONFIG_FB_OLPC_DCON=m CONFIG_FB_OLPC_DCON_1=y CONFIG_FB_OLPC_DCON_1_5=y # CONFIG_PANEL is not set -CONFIG_R8187SE=m +# CONFIG_R8187SE is not set CONFIG_RTL8192U=m CONFIG_RTLLIB=m CONFIG_RTLLIB_CRYPTO_CCMP=m CONFIG_RTLLIB_CRYPTO_TKIP=m CONFIG_RTLLIB_CRYPTO_WEP=m -CONFIG_RTL8192E=m -CONFIG_R8712U=m +# CONFIG_RTL8192E is not set +# CONFIG_R8712U is not set CONFIG_R8188EU=m CONFIG_88EU_AP_MODE=y CONFIG_88EU_P2P=y CONFIG_R8821AE=m CONFIG_RTS5139=m # CONFIG_RTS5139_DEBUG is not set -CONFIG_RTS5208=m +# CONFIG_RTS5208 is not set # CONFIG_RTS5208_DEBUG is not set # CONFIG_TRANZPORT is not set CONFIG_IDE_PHISON=m @@ -5655,8 +5655,8 @@ CONFIG_USB_SERIAL_QUATECH2=m CONFIG_VT6655=m CONFIG_VT6656=m CONFIG_DX_SEP=m -CONFIG_WLAGS49_H2=m -CONFIG_WLAGS49_H25=m +# CONFIG_WLAGS49_H2 is not set +# CONFIG_WLAGS49_H25 is not set CONFIG_FB_SM7XX=m CONFIG_CRYSTALHD=m CONFIG_FB_XGI=m diff --git a/libre/linux-libre-lts/config.mips64el b/libre/linux-libre-lts/config.mips64el index 96a39960a..96426a215 100644 --- a/libre/linux-libre-lts/config.mips64el +++ b/libre/linux-libre-lts/config.mips64el @@ -1603,7 +1603,7 @@ CONFIG_MEGARAID_NEWGEN=y CONFIG_MEGARAID_MM=m CONFIG_MEGARAID_MAILBOX=m CONFIG_MEGARAID_LEGACY=m -CONFIG_MEGARAID_SAS=m +# CONFIG_MEGARAID_SAS is not set CONFIG_SCSI_MPT2SAS=m CONFIG_SCSI_MPT2SAS_MAX_SGE=128 # CONFIG_SCSI_MPT2SAS_LOGGING is not set @@ -5051,21 +5051,21 @@ CONFIG_COMEDI_DAS08=m CONFIG_COMEDI_NI_LABPC=m CONFIG_COMEDI_NI_TIO=m # CONFIG_PANEL is not set -CONFIG_R8187SE=m +# CONFIG_R8187SE is not set CONFIG_RTL8192U=m CONFIG_RTLLIB=m CONFIG_RTLLIB_CRYPTO_CCMP=m CONFIG_RTLLIB_CRYPTO_TKIP=m CONFIG_RTLLIB_CRYPTO_WEP=m -CONFIG_RTL8192E=m -CONFIG_R8712U=m +# CONFIG_RTL8192E is not set +# CONFIG_R8712U is not set CONFIG_R8188EU=m CONFIG_88EU_AP_MODE=y CONFIG_88EU_P2P=y CONFIG_R8821AE=m CONFIG_RTS5139=m # CONFIG_RTS5139_DEBUG is not set -CONFIG_RTS5208=m +# CONFIG_RTS5208 is not set # CONFIG_RTS5208_DEBUG is not set # CONFIG_TRANZPORT is not set CONFIG_IDE_PHISON=m @@ -5075,8 +5075,8 @@ CONFIG_USB_SERIAL_QUATECH2=m CONFIG_VT6655=m CONFIG_VT6656=m CONFIG_DX_SEP=m -CONFIG_WLAGS49_H2=m -CONFIG_WLAGS49_H25=m +# CONFIG_WLAGS49_H2 is not set +# CONFIG_WLAGS49_H25 is not set CONFIG_FB_SM7XX=m CONFIG_CRYSTALHD=m CONFIG_FB_XGI=m diff --git a/libre/linux-libre-lts/config.x86_64 b/libre/linux-libre-lts/config.x86_64 index 71b21d7c9..ec000e4ac 100644 --- a/libre/linux-libre-lts/config.x86_64 +++ b/libre/linux-libre-lts/config.x86_64 @@ -1834,7 +1834,7 @@ CONFIG_MEGARAID_NEWGEN=y CONFIG_MEGARAID_MM=m CONFIG_MEGARAID_MAILBOX=m CONFIG_MEGARAID_LEGACY=m -CONFIG_MEGARAID_SAS=m +# CONFIG_MEGARAID_SAS is not set CONFIG_SCSI_MPT2SAS=m CONFIG_SCSI_MPT2SAS_MAX_SGE=128 # CONFIG_SCSI_MPT2SAS_LOGGING is not set @@ -5420,21 +5420,21 @@ CONFIG_COMEDI_DAS08=m CONFIG_COMEDI_NI_LABPC=m CONFIG_COMEDI_NI_TIO=m # CONFIG_PANEL is not set -CONFIG_R8187SE=m +# CONFIG_R8187SE is not set CONFIG_RTL8192U=m CONFIG_RTLLIB=m CONFIG_RTLLIB_CRYPTO_CCMP=m CONFIG_RTLLIB_CRYPTO_TKIP=m CONFIG_RTLLIB_CRYPTO_WEP=m -CONFIG_RTL8192E=m -CONFIG_R8712U=m +# CONFIG_RTL8192E is not set +# CONFIG_R8712U is not set CONFIG_R8188EU=m CONFIG_88EU_AP_MODE=y CONFIG_88EU_P2P=y CONFIG_R8821AE=m CONFIG_RTS5139=m # CONFIG_RTS5139_DEBUG is not set -CONFIG_RTS5208=m +# CONFIG_RTS5208 is not set # CONFIG_RTS5208_DEBUG is not set # CONFIG_TRANZPORT is not set CONFIG_IDE_PHISON=m @@ -5444,8 +5444,8 @@ CONFIG_USB_SERIAL_QUATECH2=m CONFIG_VT6655=m CONFIG_VT6656=m CONFIG_DX_SEP=m -CONFIG_WLAGS49_H2=m -CONFIG_WLAGS49_H25=m +# CONFIG_WLAGS49_H2 is not set +# CONFIG_WLAGS49_H25 is not set CONFIG_FB_SM7XX=m CONFIG_CRYSTALHD=m CONFIG_FB_XGI=m diff --git a/libre/linux-libre-lts/gcc5_buildfixes.diff b/libre/linux-libre-lts/gcc5_buildfixes.diff new file mode 100644 index 000000000..f29d60674 --- /dev/null +++ b/libre/linux-libre-lts/gcc5_buildfixes.diff @@ -0,0 +1,115 @@ +From 9493c2422cae272d6f1f567cbb424195defe4176 Mon Sep 17 00:00:00 2001 +From: Chen Gang +Date: Sat, 1 Nov 2014 19:46:12 +0800 +Subject: qla2xxx: remove redundant declaration in 'qla_gbl.h' + +Remove 2 redundant extern inline functions: qla8044_set_qsnt_ready() and +qla8044_need_reset_handler(). At present, within upstream next kernel +source code, they are only used within "drivers/scsi/qla2xxx/qla_nx2.c". + +The related error and warnings (with allmodconfig under tile): + + CC [M] drivers/scsi/qla2xxx/qla_nx2.o + drivers/scsi/qla2xxx/qla_nx2.c:1633:1: error: static declaration of 'qla8044_need_reset_handler' follows non-static declaration + qla8044_need_reset_handler(struct scsi_qla_host *vha) + ^ + In file included from drivers/scsi/qla2xxx/qla_def.h:3706:0, + from drivers/scsi/qla2xxx/qla_nx2.c:11: + drivers/scsi/qla2xxx/qla_gbl.h:756:20: note: previous declaration of 'qla8044_need_reset_handler' was here + extern inline void qla8044_need_reset_handler(struct scsi_qla_host *vha); + ^ + drivers/scsi/qla2xxx/qla_gbl.h:756:20: warning: inline function 'qla8044_need_reset_handler' declared but never defined + make[3]: *** [drivers/scsi/qla2xxx/qla_nx2.o] Error 1 + make[2]: *** [drivers/scsi/qla2xxx] Error 2 + make[1]: *** [drivers/scsi] Error 2 + make: *** [drivers] Error 2 + + CC [M] drivers/scsi/qla2xxx/qla_tmpl.o + In file included from drivers/scsi/qla2xxx/qla_def.h:3706:0, + from drivers/scsi/qla2xxx/qla_tmpl.c:7: + drivers/scsi/qla2xxx/qla_gbl.h:755:20: warning: inline function 'qla8044_set_qsnt_ready' declared but never defined + extern inline void qla8044_set_qsnt_ready(struct scsi_qla_host *vha); + ^ + +Signed-off-by: Chen Gang +Acked-by: Saurav Kashyap +Signed-off-by: Christoph Hellwig + +diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h +index b1865a7..7686bfe 100644 +--- a/drivers/scsi/qla2xxx/qla_gbl.h ++++ b/drivers/scsi/qla2xxx/qla_gbl.h +@@ -752,8 +752,6 @@ extern void qla8044_set_idc_dontreset(struct scsi_qla_host *ha); + extern int qla8044_rd_direct(struct scsi_qla_host *vha, const uint32_t crb_reg); + extern void qla8044_wr_direct(struct scsi_qla_host *vha, + const uint32_t crb_reg, const uint32_t value); +-extern inline void qla8044_set_qsnt_ready(struct scsi_qla_host *vha); +-extern inline void qla8044_need_reset_handler(struct scsi_qla_host *vha); + extern int qla8044_device_state_handler(struct scsi_qla_host *vha); + extern void qla8044_clear_qsnt_ready(struct scsi_qla_host *vha); + extern void qla8044_clear_drv_active(struct qla_hw_data *); +diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c +index 24a8528..ed4d6b6 100644 +--- a/drivers/scsi/qla2xxx/qla_nx2.c ++++ b/drivers/scsi/qla2xxx/qla_nx2.c +@@ -238,7 +238,7 @@ qla8044_rmw_crb_reg(struct scsi_qla_host *vha, + return; + } + +-inline void ++static inline void + qla8044_set_qsnt_ready(struct scsi_qla_host *vha) + { + uint32_t qsnt_state; +-- +cgit v0.10.2 + +diff --git a/lib/mpi/mpi-inline.h b/lib/mpi/mpi-inline.h +index e2b3985..c245ea3 100644 +--- a/lib/mpi/mpi-inline.h ++++ b/lib/mpi/mpi-inline.h +@@ -30,7 +30,7 @@ + #define G10_MPI_INLINE_H + + #ifndef G10_MPI_INLINE_DECL +-#define G10_MPI_INLINE_DECL extern inline ++#define G10_MPI_INLINE_DECL static inline + #endif + + G10_MPI_INLINE_DECL mpi_limb_t +diff --git a/lib/mpi/mpi-internal.h b/lib/mpi/mpi-internal.h +index 60cf765..91ef8ac 100644 +--- a/lib/mpi/mpi-internal.h ++++ b/lib/mpi/mpi-internal.h +@@ -168,20 +168,24 @@ void mpi_rshift_limbs(MPI a, unsigned int count); + int mpi_lshift_limbs(MPI a, unsigned int count); + + /*-- mpihelp-add.c --*/ ++#ifndef __GNUC__ + mpi_limb_t mpihelp_add_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb); +-mpi_limb_t mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, +- mpi_ptr_t s2_ptr, mpi_size_t size); + mpi_limb_t mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, + mpi_ptr_t s2_ptr, mpi_size_t s2_size); ++#endif ++mpi_limb_t mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, ++ mpi_ptr_t s2_ptr, mpi_size_t size); + + /*-- mpihelp-sub.c --*/ ++#ifndef __GNUC__ + mpi_limb_t mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb); +-mpi_limb_t mpihelp_sub_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, +- mpi_ptr_t s2_ptr, mpi_size_t size); + mpi_limb_t mpihelp_sub(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, + mpi_ptr_t s2_ptr, mpi_size_t s2_size); ++#endif ++mpi_limb_t mpihelp_sub_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, ++ mpi_ptr_t s2_ptr, mpi_size_t size); + + /*-- mpihelp-cmp.c --*/ + int mpihelp_cmp(mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size); +-- +1.9.3 + -- cgit v1.2.3 From 2723bef6e2305f14f1f0d408ad402a07159386d9 Mon Sep 17 00:00:00 2001 From: Omar Vega Ramos Date: Sat, 9 May 2015 16:13:27 -0500 Subject: Removing xmlstarlet: This package is in communityy repo --- libre/xmlstarlet/PKGBUILD | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 libre/xmlstarlet/PKGBUILD (limited to 'libre') diff --git a/libre/xmlstarlet/PKGBUILD b/libre/xmlstarlet/PKGBUILD deleted file mode 100644 index c8c126715..000000000 --- a/libre/xmlstarlet/PKGBUILD +++ /dev/null @@ -1,29 +0,0 @@ -# From https://aur.archlinux.org/packages.php?ID=20101. -# Maintainer (Arch): PyroPeter -# Contributor (Arch): BlackEagle -# Contributor (Arch): chochem - -pkgname=xmlstarlet -pkgver=1.3.1 -pkgrel=1 -pkgdesc="A set of tools to transform, query, validate, and edit XML documents" -arch=('i686' 'x86_64' 'mips64el') -url="http://xmlstar.sourceforge.net/" -license=('custom:MIT') -depends=('libxslt>=1.1.9') -source=("xmlstarlet-$pkgver.tar.gz::http://sourceforge.net/projects/xmlstar/files/xmlstarlet/$pkgver/xmlstarlet-$pkgver.tar.gz/download") -md5sums=('5173ad3f01ec0ba0d54bd1fbfc057abf') - -build() { - cd "$srcdir/$pkgname-$pkgver" - local xsltlibs=$(pkg-config --libs libxslt libexslt) - local xmllibs=$(pkg-config --libs libxml-2.0) - - LIBXSLT_PREFIX=/usr LIBXML_PREFIX=/usr LIBXSLT_LIBS="${xsltlibs}" LIBXML_LIBS="${xmllibs}" ./configure --prefix=/usr - - make - make DESTDIR="${pkgdir}" install - mkdir -p $pkgdir/usr/share/licenses/$pkgname - cp Copyright $pkgdir/usr/share/licenses/$pkgname/COPYING - ln -s /usr/bin/xml ${pkgdir}/usr/bin/xmlstarlet -} -- cgit v1.2.3 From e60e22efff20b01a74ddcee4f6af4559fe8fdd54 Mon Sep 17 00:00:00 2001 From: Omar Vega Ramos Date: Sat, 9 May 2015 16:17:32 -0500 Subject: xorg-fonts-75dpi-1.0.3-2.parabola2: rebuild --- libre/xorg-fonts-75dpi/PKGBUILD | 28 +++++++++++++++++++--------- libre/xorg-fonts-75dpi/xfonts.install | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'libre') diff --git a/libre/xorg-fonts-75dpi/PKGBUILD b/libre/xorg-fonts-75dpi/PKGBUILD index e02711ab5..21798e4a0 100644 --- a/libre/xorg-fonts-75dpi/PKGBUILD +++ b/libre/xorg-fonts-75dpi/PKGBUILD @@ -3,7 +3,7 @@ # Contributor (Arch): Jan de Groot pkgname=xorg-fonts-75dpi pkgver=1.0.3 -pkgrel=2.parabola1 +pkgrel=2.parabola2 pkgdesc="X.org 75dpi fonts" arch=(any) url="http://xorg.freedesktop.org/" @@ -15,22 +15,32 @@ replaces=('xorg-fonts-75dpi-libre') install=xfonts.install source=(${url}/releases/individual/font/font-adobe-75dpi-$pkgver.tar.bz2 ${url}/releases/individual/font/font-bitstream-75dpi-$pkgver.tar.bz2) +md5sums=('6c9f26c92393c0756f3e8d614713495b' + 'd7c0588c26fac055c0dd683fdd65ac34') build() { cd "${srcdir}" - install -m755 -d "${pkgdir}/usr/share/licenses/${pkgname}" for dir in *; do if [ -d "${dir}" ]; then pushd "${dir}" ./configure --prefix=/usr \ - --with-fontdir=/usr/share/fonts/75dpi || return 1 - make || return 1 - make DESTDIR="${pkgdir}" install || return 1 - install -m644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE.${dir%-75dpi-*}" || return 1 + --with-fontdir=/usr/share/fonts/75dpi + make popd fi done - rm -f "${pkgdir}"/usr/share/fonts/75dpi/fonts.* } -md5sums=('6c9f26c92393c0756f3e8d614713495b' - 'd7c0588c26fac055c0dd683fdd65ac34') + +package() { + cd "${srcdir}" + install -m755 -d "${pkgdir}/usr/share/licenses/${pkgname}" + for dir in *; do + if [ -d "${dir}" ]; then + pushd "${dir}" + make DESTDIR="${pkgdir}" install + install -m644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE.${dir%-75dpi-*}" + popd + fi + done + rm -f "${pkgdir}"/usr/share/fonts/75dpi/fonts.* +} \ No newline at end of file diff --git a/libre/xorg-fonts-75dpi/xfonts.install b/libre/xorg-fonts-75dpi/xfonts.install index e52603946..14080a0a5 100644 --- a/libre/xorg-fonts-75dpi/xfonts.install +++ b/libre/xorg-fonts-75dpi/xfonts.install @@ -1,6 +1,6 @@ post_install() { echo -n "Updating font cache... " - fc-cache -f > /dev/null + fc-cache -s mkfontscale /usr/share/fonts/75dpi mkfontdir /usr/share/fonts/75dpi echo "done." -- cgit v1.2.3 From 02289ff862bbb5c5ddec0473085046156d3a849a Mon Sep 17 00:00:00 2001 From: Omar Vega Ramos Date: Sat, 9 May 2015 16:19:22 -0500 Subject: xorg-fonts-100dpi-1.0.3-2.parabola2: rebuild --- libre/xorg-fonts-100dpi/PKGBUILD | 28 ++++++++++++++++++---------- libre/xorg-fonts-100dpi/xfonts.install | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'libre') diff --git a/libre/xorg-fonts-100dpi/PKGBUILD b/libre/xorg-fonts-100dpi/PKGBUILD index f4a3d5226..cce9f6a75 100644 --- a/libre/xorg-fonts-100dpi/PKGBUILD +++ b/libre/xorg-fonts-100dpi/PKGBUILD @@ -4,7 +4,7 @@ # Maintainer: fauno pkgname=xorg-fonts-100dpi pkgver=1.0.3 -pkgrel=2.parabola1 +pkgrel=2.parabola2 pkgdesc="X.org 100dpi fonts" arch=(any) url="http://xorg.freedesktop.org/" @@ -16,24 +16,32 @@ replaces=('xorg-fonts-100dpi-libre') install=xfonts.install source=(${url}/releases/individual/font/font-adobe-100dpi-$pkgver.tar.bz2 ${url}/releases/individual/font/font-bitstream-100dpi-$pkgver.tar.bz2) +md5sums=('1347c3031b74c9e91dc4dfa53b12f143' + '6b223a54b15ecbd5a1bc52312ad790d8') build() { cd "${srcdir}" - install -m755 -d "${pkgdir}/usr/share/licenses/${pkgname}" - for dir in font-*-100dpi*; do if [ -d "${dir}" ]; then pushd ${dir} ./configure --prefix=/usr \ --with-fontdir=/usr/share/fonts/100dpi - make || return 1 - make DESTDIR="${pkgdir}" install || return 1 - - install -m644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE.${dir%-100dpi-*}" || return 1 + make popd fi done - rm -f "${pkgdir}"/usr/share/fonts/100dpi/fonts.* } -md5sums=('1347c3031b74c9e91dc4dfa53b12f143' - '6b223a54b15ecbd5a1bc52312ad790d8') + +package() { + cd "${srcdir}" + install -m755 -d "${pkgdir}/usr/share/licenses/${pkgname}" + for dir in font-*-100dpi*; do + if [ -d "${dir}" ]; then + pushd ${dir} + make DESTDIR="${pkgdir}" install + install -m644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE.${dir%-100dpi-*}" + popd + fi + done + rm -f "${pkgdir}"/usr/share/fonts/100dpi/fonts.* +} \ No newline at end of file diff --git a/libre/xorg-fonts-100dpi/xfonts.install b/libre/xorg-fonts-100dpi/xfonts.install index 5c5e8a2b4..d8fac18a8 100644 --- a/libre/xorg-fonts-100dpi/xfonts.install +++ b/libre/xorg-fonts-100dpi/xfonts.install @@ -1,6 +1,6 @@ post_install() { echo -n "Updating font cache... " - fc-cache -f > /dev/null + fc-cache -s mkfontscale /usr/share/fonts/100dpi mkfontdir /usr/share/fonts/100dpi echo "done." -- cgit v1.2.3 From 49ca876e25571f0d3f781617062eddf993d89d22 Mon Sep 17 00:00:00 2001 From: Omar Vega Ramos Date: Sat, 9 May 2015 20:00:57 -0500 Subject: Removing lha in optional dependency of atool --- libre/atool/PKGBUILD | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'libre') diff --git a/libre/atool/PKGBUILD b/libre/atool/PKGBUILD index dca366b88..b136ac05c 100644 --- a/libre/atool/PKGBUILD +++ b/libre/atool/PKGBUILD @@ -8,7 +8,7 @@ pkgname=atool pkgver=0.39.0 -pkgrel=3.parabola1 +pkgrel=3.parabola2 pkgdesc="A script for managing file archives of various types, without nonfree unace and unrar support" arch=('any') url="http://www.nongnu.org/$pkgname/" @@ -19,7 +19,6 @@ conflicts=("$pkgname-libre") optdepends=("bzip2: for using $pkgname with bzip2 compressed archives" "cpio: for using $pkgname with cpio archives" "gzip: for using $pkgname with gzip compressed archives" - "lha: for using $pkgname with lha, lharc and similar archives" "xz: for using $pkgname with lzma compressed archives" "lzop: for using $pkgname with lzop compressed archives" "p7zip: for using $pkgname with 7z archives" -- cgit v1.2.3 From 255e1fa366aa59131f15b4e9771b5e7568c2da64 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sun, 10 May 2015 03:20:33 -0300 Subject: linux-libre-grsec{,-knock}-4.0.2_gnu.201505072057-1: updating version --- ...-enable-CS_PARSER_ERROR-interrupts-at-all.patch | 66 ---------------------- kernels/linux-libre-grsec-knock/PKGBUILD | 14 ++--- ...-enable-CS_PARSER_ERROR-interrupts-at-all.patch | 66 ---------------------- libre/linux-libre-grsec/PKGBUILD | 14 ++--- 4 files changed, 8 insertions(+), 152 deletions(-) delete mode 100644 kernels/linux-libre-grsec-knock/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch delete mode 100644 libre/linux-libre-grsec/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch (limited to 'libre') diff --git a/kernels/linux-libre-grsec-knock/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch b/kernels/linux-libre-grsec-knock/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch deleted file mode 100644 index 4e801b3cc..000000000 --- a/kernels/linux-libre-grsec-knock/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch +++ /dev/null @@ -1,66 +0,0 @@ -From b27b2ff4bd6f0327ee550baa0397ccf0a559821f Mon Sep 17 00:00:00 2001 -From: Daniel Vetter -Date: Wed, 1 Apr 2015 13:40:48 +0200 -Subject: [PATCH] drm/i915: Dont enable CS_PARSER_ERROR interrupts at all - -We stopped handling them in - -commit aaecdf611a05cac26a94713bad25297e60225c29 -Author: Daniel Vetter -Date: Tue Nov 4 15:52:22 2014 +0100 - - drm/i915: Stop gathering error states for CS error interrupts - -but just clearing is apparently not enough: A sufficiently dead gpu -left behind by firmware (*cough* coreboot *cough*) can keep the gpu in -an endless loop of such interrupts, eventually leading to the nmi -firing. And definitely to what looks like a machine hang. - -Since we don't even enable these interrupts on gen5+ let's do the same -on earlier platforms. - -Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=93171 -Signed-off-by: Daniel Vetter ---- - drivers/gpu/drm/i915/i915_irq.c | 8 ++------ - 1 file changed, 2 insertions(+), 6 deletions(-) - -diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index 14ecb4d13a1a..6d494432b19f 100644 ---- a/drivers/gpu/drm/i915/i915_irq.c -+++ b/drivers/gpu/drm/i915/i915_irq.c -@@ -3598,14 +3598,12 @@ static int i8xx_irq_postinstall(struct drm_device *dev) - ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | -- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); -+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); - I915_WRITE16(IMR, dev_priv->irq_mask); - - I915_WRITE16(IER, - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | - I915_USER_INTERRUPT); - POSTING_READ16(IER); - -@@ -3767,14 +3765,12 @@ static int i915_irq_postinstall(struct drm_device *dev) - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | -- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); -+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); - - enable_mask = - I915_ASLE_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | - I915_USER_INTERRUPT; - - if (I915_HAS_HOTPLUG(dev)) { --- -2.1.4 - diff --git a/kernels/linux-libre-grsec-knock/PKGBUILD b/kernels/linux-libre-grsec-knock/PKGBUILD index c2346e5ef..ac586b99f 100644 --- a/kernels/linux-libre-grsec-knock/PKGBUILD +++ b/kernels/linux-libre-grsec-knock/PKGBUILD @@ -12,9 +12,9 @@ pkgbase=linux-libre-grsec-knock # Build kernel with -grsec-knock localname _pkgbasever=4.0-gnu -_pkgver=4.0.1-gnu +_pkgver=4.0.2-gnu _grsecver=3.1 -_timestamp=201505042053 +_timestamp=201505072057 _knockpatchver=3.18_1 _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname @@ -44,15 +44,14 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li 'linux.preset' 'logo_linux_'{clut224.ppm,vga16.ppm,mono.pbm} 'change-default-console-loglevel.patch' - '0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch' # loongson-community patch: http://linux-libre.fsfla.org/pub/linux-libre/lemote/gnewsense/pool/debuginfo/ # Note: Makefile patching was removed due which we are using specific flags from grsecurity patch '4.0-rc7-37af2c8aae-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - 'b99335ed7c60ba2701d81923de4e3e9efbbfa3ad0782e7d94cd48b92adb1fbd6' + '6b559c4393922896752822a63d22fb51f4aad0d8feb123a9c7a518d25ca7b378' 'SKIP' - '9944bf62201fa0ad86bc9d4a5e0368d64967b626933261868b2402547abd039b' + '62b75881f2bc760c585f77b73c335fbf439db042eb456abb8765fc644d7b5b5a' 'SKIP' '93a1610c203ea4c187ac5b50dce105fac86df914b1406e1d85df5857d36201c9' 'SKIP' @@ -64,7 +63,6 @@ sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' '6de8a8319271809ffdb072b68d53d155eef12438e6d04ff06a5a4db82c34fa8a' '13bd7a8d9ed6b6bc971e4cd162262c5a20448a83796af39ce394d827b0e5de74' '1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99' - '66cb2d859b253bc4e793baa3c0b95523d647a773b957dbc79b3eaacccf8692b5' '8a070d193bc54db696b38ac844cfbfd62724f483ad74c9a288ccab462c32f80e') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva @@ -109,10 +107,6 @@ prepare() { # (relevant patch sent upstream: https://lkml.org/lkml/2011/7/26/227) patch -p1 -i "${srcdir}/change-default-console-loglevel.patch" - # drm/i915: Stop gathering error states for CS error interrupts - # https://bugzilla.kernel.org/show_bug.cgi?id=93171 - patch -p1 -i "${srcdir}/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch" - # Adding loongson-community patch if [ "${CARCH}" == "mips64el" ]; then patch -p1 -i ${srcdir}/4.0-rc7-37af2c8aae-loongson-community.patch diff --git a/libre/linux-libre-grsec/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch b/libre/linux-libre-grsec/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch deleted file mode 100644 index 4e801b3cc..000000000 --- a/libre/linux-libre-grsec/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch +++ /dev/null @@ -1,66 +0,0 @@ -From b27b2ff4bd6f0327ee550baa0397ccf0a559821f Mon Sep 17 00:00:00 2001 -From: Daniel Vetter -Date: Wed, 1 Apr 2015 13:40:48 +0200 -Subject: [PATCH] drm/i915: Dont enable CS_PARSER_ERROR interrupts at all - -We stopped handling them in - -commit aaecdf611a05cac26a94713bad25297e60225c29 -Author: Daniel Vetter -Date: Tue Nov 4 15:52:22 2014 +0100 - - drm/i915: Stop gathering error states for CS error interrupts - -but just clearing is apparently not enough: A sufficiently dead gpu -left behind by firmware (*cough* coreboot *cough*) can keep the gpu in -an endless loop of such interrupts, eventually leading to the nmi -firing. And definitely to what looks like a machine hang. - -Since we don't even enable these interrupts on gen5+ let's do the same -on earlier platforms. - -Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=93171 -Signed-off-by: Daniel Vetter ---- - drivers/gpu/drm/i915/i915_irq.c | 8 ++------ - 1 file changed, 2 insertions(+), 6 deletions(-) - -diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index 14ecb4d13a1a..6d494432b19f 100644 ---- a/drivers/gpu/drm/i915/i915_irq.c -+++ b/drivers/gpu/drm/i915/i915_irq.c -@@ -3598,14 +3598,12 @@ static int i8xx_irq_postinstall(struct drm_device *dev) - ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | -- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); -+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); - I915_WRITE16(IMR, dev_priv->irq_mask); - - I915_WRITE16(IER, - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | - I915_USER_INTERRUPT); - POSTING_READ16(IER); - -@@ -3767,14 +3765,12 @@ static int i915_irq_postinstall(struct drm_device *dev) - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | -- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); -+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); - - enable_mask = - I915_ASLE_INTERRUPT | - I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | -- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | - I915_USER_INTERRUPT; - - if (I915_HAS_HOTPLUG(dev)) { --- -2.1.4 - diff --git a/libre/linux-libre-grsec/PKGBUILD b/libre/linux-libre-grsec/PKGBUILD index b23737a31..084b10b17 100644 --- a/libre/linux-libre-grsec/PKGBUILD +++ b/libre/linux-libre-grsec/PKGBUILD @@ -12,9 +12,9 @@ pkgbase=linux-libre-grsec # Build kernel with -grsec localname _pkgbasever=4.0-gnu -_pkgver=4.0.1-gnu +_pkgver=4.0.2-gnu _grsecver=3.1 -_timestamp=201505042053 +_timestamp=201505072057 _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -41,15 +41,14 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li 'linux.preset' 'logo_linux_'{clut224.ppm,vga16.ppm,mono.pbm} 'change-default-console-loglevel.patch' - '0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch' # loongson-community patch: http://linux-libre.fsfla.org/pub/linux-libre/lemote/gnewsense/pool/debuginfo/ # Note: Makefile patching was removed due which we are using specific flags from grsecurity patch '4.0-rc7-37af2c8aae-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - 'b99335ed7c60ba2701d81923de4e3e9efbbfa3ad0782e7d94cd48b92adb1fbd6' + '6b559c4393922896752822a63d22fb51f4aad0d8feb123a9c7a518d25ca7b378' 'SKIP' - '9944bf62201fa0ad86bc9d4a5e0368d64967b626933261868b2402547abd039b' + '62b75881f2bc760c585f77b73c335fbf439db042eb456abb8765fc644d7b5b5a' 'SKIP' 'd1b2bfc86563d522562850556a2dd39f41b91b992cb4d839551e44e8d9df0ae3' '92580d3bd2f8c66ccc9467e9a4bfbc012e90a3d32953503750309313755a3ea2' @@ -59,7 +58,6 @@ sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' '6de8a8319271809ffdb072b68d53d155eef12438e6d04ff06a5a4db82c34fa8a' '13bd7a8d9ed6b6bc971e4cd162262c5a20448a83796af39ce394d827b0e5de74' '1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99' - '66cb2d859b253bc4e793baa3c0b95523d647a773b957dbc79b3eaacccf8692b5' '8a070d193bc54db696b38ac844cfbfd62724f483ad74c9a288ccab462c32f80e') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva @@ -100,10 +98,6 @@ prepare() { # (relevant patch sent upstream: https://lkml.org/lkml/2011/7/26/227) patch -p1 -i "${srcdir}/change-default-console-loglevel.patch" - # drm/i915: Stop gathering error states for CS error interrupts - # https://bugzilla.kernel.org/show_bug.cgi?id=93171 - patch -p1 -i "${srcdir}/0001-drm-i915-Dont-enable-CS_PARSER_ERROR-interrupts-at-all.patch" - # Adding loongson-community patch if [ "${CARCH}" == "mips64el" ]; then patch -p1 -i ${srcdir}/4.0-rc7-37af2c8aae-loongson-community.patch -- cgit v1.2.3 From 305a22609b468bc5d0f5a8010afee29275652147 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Mon, 11 May 2015 03:11:03 -0300 Subject: doublecmd-0.6.2-1.parabola1: updating version --- libre/doublecmd/PKGBUILD | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libre') diff --git a/libre/doublecmd/PKGBUILD b/libre/doublecmd/PKGBUILD index 77c199aef..3304cef44 100644 --- a/libre/doublecmd/PKGBUILD +++ b/libre/doublecmd/PKGBUILD @@ -1,5 +1,5 @@ # vim:set ft=sh: -# $Id: PKGBUILD 130194 2015-03-29 12:38:40Z idevolder $ +# $Id: PKGBUILD 133195 2015-05-10 18:42:31Z idevolder $ # Maintainer (Arch): BlackIkeEagle # Contributor (Arch): (sirocco AT ngs.ru) # Maintainer: André Silva @@ -7,7 +7,7 @@ pkgbase=doublecmd _pkgbase=$pkgbase-libre pkgname=("$pkgbase-gtk2" "$pkgbase-qt") -pkgver=0.6.1 +pkgver=0.6.2 _helpver=0.6.0 pkgrel=1.parabola1 url="http://$pkgbase.sourceforge.net/" @@ -106,8 +106,8 @@ package_doublecmd-qt() { cp -a * "$pkgdir/usr/share/$pkgbase/doc/" } -mksha256sums=('f5e06488edc5e1d7c7e6f4affd9f205341e5158524bd903e3a4bd5fda5a17642') -sha256sums=('dfab32bb8991b51818e3af00aefbce5d3e91f1256916caa9aaf67746a558f973' +mksha256sums=('76564e927b9bf372dec585df6a65880cfd6ff06086f8c56e7bcf9bbde960e3bb') +sha256sums=('a20c8c8a8aafe1729b0491c3f6c01f5b871166deeaf5c4954373310ee0b2597a' 'd50a58f0e8c25c07720f2afd987213f330dfce268e2aef349d1da3de2eef1c39' '16560ad7403ffbee1800384768828e1fad924d03068c6248b68a78c393fc4e20' '610b470ce9961d851b5dcc93d5103e70ea6b3b719df404c7c49b2d11909b8951' -- cgit v1.2.3 From ba56d2fe19f7bfb5b83f4505a32f7f29eb3b5f11 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Mon, 11 May 2015 04:51:36 -0300 Subject: kdelibs-4.14.7-3.parabola1: rebuild against openexr 2.2 --- libre/kdelibs/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libre') diff --git a/libre/kdelibs/PKGBUILD b/libre/kdelibs/PKGBUILD index 066aad9b7..75ed14522 100644 --- a/libre/kdelibs/PKGBUILD +++ b/libre/kdelibs/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 238284 2015-04-30 08:28:34Z arojas $ +# $Id: PKGBUILD 238946 2015-05-10 20:32:14Z arojas $ # Maintainer (Arch): Felix Yan # Contributor (Arch): Andrea Scarpino @@ -7,7 +7,7 @@ pkgname=kdelibs pkgver=4.14.7 _kdeappver=15.04.0 -pkgrel=2.parabola1 +pkgrel=3.parabola1 pkgdesc="KDE Core Libraries, without nonfree plugins recommendation support" arch=('i686' 'x86_64' 'mips64el') url='https://projects.kde.org/projects/kde/kdelibs' -- cgit v1.2.3 From 9faeb0ef5cff336defb35bc74752a771cc4c5fc2 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Mon, 11 May 2015 05:09:22 -0300 Subject: liferea-1.10.15-1.parabola1: updating version --- libre/liferea/PKGBUILD | 10 ++++---- libre/liferea/remove-non-free-suggestions.patch | 33 ++++++++++++------------- 2 files changed, 21 insertions(+), 22 deletions(-) (limited to 'libre') diff --git a/libre/liferea/PKGBUILD b/libre/liferea/PKGBUILD index 18933bb68..96bb8e6a2 100644 --- a/libre/liferea/PKGBUILD +++ b/libre/liferea/PKGBUILD @@ -1,10 +1,10 @@ -# $Id: PKGBUILD 232403 2015-03-02 03:49:28Z eric $ +# $Id: PKGBUILD 238777 2015-05-09 23:20:06Z eric $ # Maintainer (Arch): Eric Bélanger # Maintainer: André Silva # Contributor: bitlord pkgname=liferea -pkgver=1.10.14 +pkgver=1.10.15 pkgrel=1.parabola1 pkgdesc="A desktop news aggregator for online news feeds and weblogs, without nonfree suggestions" arch=('i686' 'x86_64' 'mips64el') @@ -14,7 +14,7 @@ conflicts=('liferea-libre') license=('GPL') depends=('webkitgtk' 'libnotify' 'json-glib' 'libpeas' 'python2-gobject' 'gnome-icon-theme' 'desktop-file-utils') -makedepends=('intltool') +makedepends=('intltool' 'gobject-introspection') optdepends=('gnome-keyring: for keyring plugin support' 'libgnome-keyring: for keyring plugin support' 'gst-plugins-base: for media player plugin support' @@ -24,8 +24,8 @@ options=('!emptydirs') install=liferea.install source=(https://github.com/lwindolf/liferea/releases/download/v${pkgver}/liferea-${pkgver}.tar.bz2 remove-non-free-suggestions.patch) -sha1sums=('ffdd505d01473b1ec29a3da292632f474b9b83fb' - '855de60c91b5fee71c7ec88dd04b7d24a02dc0d1') +sha1sums=('5325d1fc06417abd4de5568fa87daf0c7f3e9c82' + 'e787f9209415ed2574e54b020cf449268ece3583') build() { cd liferea-${pkgver} diff --git a/libre/liferea/remove-non-free-suggestions.patch b/libre/liferea/remove-non-free-suggestions.patch index 5024f19ee..b2a01bb49 100644 --- a/libre/liferea/remove-non-free-suggestions.patch +++ b/libre/liferea/remove-non-free-suggestions.patch @@ -1,20 +1,19 @@ -diff --git a/src/browser.c b/src/browser.c -index f91901f..28b0c2b 100644 ---- a/src/browser.c -+++ b/src/browser.c -@@ -35,23 +35,16 @@ static struct browser browsers[] = { +diff -Nur liferea-1.10.15.orig/src/browser.c liferea-1.10.15/src/browser.c +--- liferea-1.10.15.orig/src/browser.c 2015-04-20 18:22:55.000000000 -0300 ++++ liferea-1.10.15/src/browser.c 2015-05-11 05:02:46.503659599 -0300 +@@ -35,23 +35,16 @@ NULL, NULL }, { - /* tested with Firefox 1.5 and 2.0 */ - "firefox", "Firefox", "firefox \"%s\"", -- NULL, "firefox -a firefox -remote \"openURL(%s)\"", -- NULL, "firefox -a firefox -remote 'openURL(%s,new-window)'", -- NULL, "firefox -a firefox -remote 'openURL(%s,new-tab)'" -+ "iceweasel", "Iceweasel", "iceweasel %s", -+ NULL, "iceweasel \"%s\"", -+ NULL, "iceweasel -new-window \"%s\"", -+ NULL, "iceweasel -new-tab \"%s\"" +- "firefox \"%s\"", NULL, +- "firefox -a firefox -new-window \"%s\"", NULL, +- "firefox -a firefox -new-tab \"%s\"", NULL ++ "icecat", "Icecat", "icecat \"%s\"", ++ "icecat \"%s\"", NULL, ++ "icecat -a icecat -new-window \"%s\"", NULL, ++ "icecat -a icecat -new-tab \"%s\"", NULL }, { - "google-chrome", "Chrome", "google-chrome \"%s\"", @@ -27,14 +26,14 @@ index f91901f..28b0c2b 100644 - "opera \"%s\"", "opera -remote \"openURL(%s)\"", - "opera -newwindow \"%s\"", NULL, - "opera -newpage \"%s\"", NULL -+ "icecat", "Icecat", "icecat %s", -+ NULL, "icecat \"%s\"", -+ NULL, "icecat -new-window \"%s\"", -+ NULL, "icecat -new-tab \"%s\"" ++ "iceweasel", "Iceweasel", "iceweasel \"%s\"", ++ "iceweasel \"%s\"", NULL, ++ "iceweasel -a iceweasel -new-window \"%s\"", NULL, ++ "iceweasel -a iceweasel -new-tab \"%s\"", NULL }, { "epiphany", "Epiphany", "epiphany \"%s\"", -@@ -60,13 +53,6 @@ static struct browser browsers[] = { +@@ -60,13 +53,6 @@ "epiphany -n \"%s\"", NULL }, { -- cgit v1.2.3 From c3d4f682011785d23c3fbb93344304f313556cb8 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Mon, 11 May 2015 05:33:08 -0300 Subject: luxrender-1.4-6.parabola1: rebuild against openexr 2.2 --- libre/luxrender/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libre') diff --git a/libre/luxrender/PKGBUILD b/libre/luxrender/PKGBUILD index 20ada0647..9a883bb48 100644 --- a/libre/luxrender/PKGBUILD +++ b/libre/luxrender/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 132029 2015-04-23 03:41:06Z fyan $ +# $Id: PKGBUILD 133054 2015-05-09 12:38:26Z stativ $ # Maintainer (Arch): Lukas Jirkovsky # Contributor (Arch): flixie <69one@gmx.net> # Contributor (Arch): Imanol Celaya @@ -6,7 +6,7 @@ pkgname=luxrender pkgver=1.4 _pkgver=dfd211d6faa0 -pkgrel=5.parabola1 +pkgrel=6.parabola1 pkgdesc="Rendering system for physically correct, unbiased image synthesis, with opencl-mesa recommendation" arch=('i686' 'x86_64' 'mips64el') url="http://www.luxrender.net/" -- cgit v1.2.3 From c57c90e58c40c6ee9c860fad71ad62be4ca76017 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Mon, 11 May 2015 19:31:37 -0300 Subject: spacefm-1.0.1-1.parabola1: updating version --- libre/spacefm/PKGBUILD | 23 ++++++++--------------- libre/spacefm/libre.patch | 39 +++++++++++++++------------------------ 2 files changed, 23 insertions(+), 39 deletions(-) (limited to 'libre') diff --git a/libre/spacefm/PKGBUILD b/libre/spacefm/PKGBUILD index 31015bd9c..f7bd4207c 100644 --- a/libre/spacefm/PKGBUILD +++ b/libre/spacefm/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 120827 2014-10-16 15:48:31Z bpiotrowski $ +# $Id: PKGBUILD 133107 2015-05-09 18:23:35Z arojas $ # Maintainer (Arch): Bartłomiej Piotrowski # Contributor (Arch): IgnorantGuru http://igurublog.wordpress.com/contact-ignorantguru/ # Contributor (Arch): ridikulus_rat @@ -6,38 +6,31 @@ # Contributor: Edison Ibañez pkgname=spacefm -pkgver=0.9.4 -pkgrel=3.parabola1 +pkgver=1.0.1 +pkgrel=1.parabola1 pkgdesc='Multi-panel tabbed file manager, with unar support' arch=('i686' 'x86_64' 'mips64el') url='http://ignorantguru.github.com/spacefm/' license=('GPL3') install=$pkgname.install -depends=('gtk2' 'shared-mime-info' 'desktop-file-utils' 'startup-notification' - 'systemd' 'bash' 'unar') +depends=('gtk3' 'desktop-file-utils' 'startup-notification' 'ffmpegthumbnailer' 'unar') makedepends=('intltool' 'gettext') optdepends=('lsof: device processes' 'wget: plugin download' 'gksu: perform as root functionality' 'udevil: mount as non-root user and mount networks' - 'udisks: mount as non-root user' 'udisks2: mount as non-root user') replaces=(${pkgname}-libre) conflicts=(${pkgname}-libre) -source=(https://github.com/IgnorantGuru/spacefm/archive/$pkgver.tar.gz - spacefm-0.9.4-glib-2.41.patch +source=($pkgname-$pkgver.tar.gz::https://github.com/IgnorantGuru/spacefm/archive/$pkgver.tar.gz libre.patch) -md5sums=('daeee7dcccea33d6258a0a9d783470c4' - '1ec85afcb4fc881a8e876b3cf60c7028' - '30ba2b4b8f5ae7bf1552689b192eab89') +md5sums=('3665b0cf08dcbebefcc832afc19d613e' + '66cc35023050ff6664bf14b1073700e2') prepare() { cd $pkgname-$pkgver # replace nonfree unrar with unar support - patch -Np1 -i $srcdir/libre.patch src/ptk/ptk-file-archiver.c - - # fix freezes with glib 2.41 - patch -p1 -i ../spacefm-0.9.4-glib-2.41.patch + patch -Np1 -i $srcdir/libre.patch } build() { diff --git a/libre/spacefm/libre.patch b/libre/spacefm/libre.patch index 82d51f705..d27b1b850 100644 --- a/libre/spacefm/libre.patch +++ b/libre/spacefm/libre.patch @@ -1,24 +1,15 @@ -From 4605df33f85e5dbd4cc0238b9d289ff73601d898 Mon Sep 17 00:00:00 2001 -From: Edison Ibañez -Date: mar, 20 may 2014 10:27:55 -0500 -Subject: [PATCH] replace nonfree unrar with unar support - - -diff --git a/src/ptk/ptk-file-archiver.c b/src/ptk/ptk-file-archiver.c -index ec9fbd7..55648d2 100644 ---- a/src/ptk/ptk-file-archiver.c -+++ b/src/ptk/ptk-file-archiver.c -@@ -80,8 +80,8 @@ const ArchiveHandler handlers[]= - { - "application/x-rar", - "rar a -r %o", -- "unrar -o- x", -- "unrar lt", -+ "unar -D ", -+ "unar -D ", - ".rar", "arc_rar", TRUE - }, - { --- -Gitg - +diff -Nur spacefm-1.0.1.orig/src/ptk/ptk-handler.c spacefm-1.0.1/src/ptk/ptk-handler.c +--- spacefm-1.0.1.orig/src/ptk/ptk-handler.c 2015-05-04 09:33:53.000000000 -0300 ++++ spacefm-1.0.1/src/ptk/ptk-handler.c 2015-05-11 19:11:14.248923712 -0300 +@@ -173,9 +173,9 @@ + "*.rar *.RAR", + "rar a -r %o %N", + TRUE, +- "unrar -o- x %x", ++ "unar -D %x", + TRUE, +- "unrar lt %x", ++ "unar -D %x", + TRUE + }, + { -- cgit v1.2.3 From 93c7469eddf84de74c794e2de7ae19a6a4bc4da3 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Mon, 11 May 2015 19:57:47 -0300 Subject: spacefm: remove unneeded patch --- libre/spacefm/spacefm-0.9.4-glib-2.41.patch | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 libre/spacefm/spacefm-0.9.4-glib-2.41.patch (limited to 'libre') diff --git a/libre/spacefm/spacefm-0.9.4-glib-2.41.patch b/libre/spacefm/spacefm-0.9.4-glib-2.41.patch deleted file mode 100644 index 5795c77a8..000000000 --- a/libre/spacefm/spacefm-0.9.4-glib-2.41.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/src/main.c b/src/main.c -index a7307fb..af5dc5a 100644 ---- a/src/main.c -+++ b/src/main.c -@@ -1349,7 +1349,9 @@ int main ( int argc, char *argv[] ) - vfs_file_monitor_clean(); - return ret == -1 ? 0 : ret; - } -+ GDK_THREADS_ENTER(); - gtk_main(); -+ GDK_THREADS_LEAVE(); - vfs_file_monitor_clean(); - return 0; - } -@@ -1509,8 +1511,10 @@ int main ( int argc, char *argv[] ) - run = handle_parsed_commandline_args(); - app_settings.load_saved_tabs = TRUE; - -+ GDK_THREADS_ENTER(); - if( run ) /* run the main loop */ - gtk_main(); -+ GDK_THREADS_LEAVE(); - - main_window_event( NULL, NULL, "evt_exit", 0, 0, NULL, 0, 0, 0, FALSE ); - -- cgit v1.2.3 From baa7ad63bb33b955a614d2e78100a423729dbd3d Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 12 May 2015 06:40:35 -0300 Subject: epdfview-0.1.8-6.parabola1: fix FS#44936 -> https://bugs.archlinux.org/task/44936 --- libre/epdfview/PKGBUILD | 15 +++++++++------ libre/epdfview/epdfview-0.1.8-pictures.patch | 13 +++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 libre/epdfview/epdfview-0.1.8-pictures.patch (limited to 'libre') diff --git a/libre/epdfview/PKGBUILD b/libre/epdfview/PKGBUILD index adef21e0e..a8e27d41f 100644 --- a/libre/epdfview/PKGBUILD +++ b/libre/epdfview/PKGBUILD @@ -1,6 +1,6 @@ -# $Id: PKGBUILD 105182 2014-02-02 12:39:48Z bpiotrowski $ -# Maintainer (Arch): Bartłomiej Piotrowski +# $Id: PKGBUILD 133276 2015-05-12 02:42:33Z kkeen $ # Maintainer (Arch): Kyle Keen +# Contributor (Arch): Bartłomiej Piotrowski # Contributor (Arch): schuay # Contributor (Arch): Tom K # Contributor (Arch): Thayer Williams @@ -9,7 +9,7 @@ pkgname=epdfview pkgver=0.1.8 -pkgrel=5.parabola1 +pkgrel=6.parabola1 pkgdesc='Lightweight PDF document viewer, without nonfree suggestions' url="http://freecode.com/projects/$pkgname" arch=('i686' 'x86_64' 'mips64el') @@ -22,11 +22,13 @@ install="$pkgname.install" source=(ftp://ftp.slackware.com/.1/blfs/conglomeration/$pkgname/$pkgname-$pkgver.tar.bz2 $pkgname-0.1.8-swap-the-blue-and-red-channel.patch $pkgname-0.1.8-glib2-headers.patch - $pkgname-0.1.8-modern-cups.patch) + $pkgname-0.1.8-modern-cups.patch + $pkgname-0.1.8-pictures.patch) md5sums=('e50285b01612169b2594fea375f53ae4' '7f9ea101a41f5b4e999fd024f423d41f' '2fffa9c7cd4c5f0744803591c2f162a3' - '5c2cf5612d2a7dfe6cf005b94aeb5ada') + '5c2cf5612d2a7dfe6cf005b94aeb5ada' + '60064c976f273d86d6254c71b583cf4d') prepare() { cd $pkgname-$pkgver @@ -37,7 +39,8 @@ prepare() { patch -p1 -i ../$pkgname-0.1.8-swap-the-blue-and-red-channel.patch patch -p1 -i ../$pkgname-0.1.8-glib2-headers.patch # FS#30116 - patch -p1 -i ../$pkgname-0.1.8-modern-cups.patch # FS#32511 + patch -p1 -i ../$pkgname-0.1.8-modern-cups.patch # FS#32511 + patch -p1 -i ../$pkgname-0.1.8-pictures.patch # FS#44936 } build() { diff --git a/libre/epdfview/epdfview-0.1.8-pictures.patch b/libre/epdfview/epdfview-0.1.8-pictures.patch new file mode 100644 index 000000000..5c42cb266 --- /dev/null +++ b/libre/epdfview/epdfview-0.1.8-pictures.patch @@ -0,0 +1,13 @@ +diff --git a/src/PDFDocument.cxx b/src/PDFDocument.cxx +index df5d75f..782f806 100644 +--- a/src/PDFDocument.cxx ++++ b/src/PDFDocument.cxx +@@ -616,7 +616,7 @@ PDFDocument::renderPage (gint pageNum) + #if defined (HAVE_POPPLER_0_17_0) + cairo_surface_t *surface = cairo_image_surface_create_for_data ( + renderedPage->getData (), +- CAIRO_FORMAT_RGB24, width, height, ++ CAIRO_FORMAT_ARGB32, width, height, + renderedPage->getRowStride ()); + cairo_t *context = cairo_create (surface); + cairo_save(context); -- cgit v1.2.3 From 88bfa6bb351b107c2b250d01fb0375abe0458c50 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 02:02:57 -0300 Subject: rebuild module packages against linux-libre-4.0.2_gnu-1 --- libre/acpi_call/PKGBUILD | 2 +- libre/bbswitch/PKGBUILD | 2 +- libre/tp_smapi/PKGBUILD | 2 +- libre/vhba-module/PKGBUILD | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'libre') diff --git a/libre/acpi_call/PKGBUILD b/libre/acpi_call/PKGBUILD index f45d83e5c..5cd88cb4c 100644 --- a/libre/acpi_call/PKGBUILD +++ b/libre/acpi_call/PKGBUILD @@ -9,7 +9,7 @@ _kernelname= if [[ ${_kernelname} == "" ]]; then _basekernel=4.0 - _archrel=28 + _archrel=29 _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 diff --git a/libre/bbswitch/PKGBUILD b/libre/bbswitch/PKGBUILD index b165aed0b..6caa4ce93 100644 --- a/libre/bbswitch/PKGBUILD +++ b/libre/bbswitch/PKGBUILD @@ -9,7 +9,7 @@ _kernelname= if [[ ${_kernelname} == "" ]]; then _basekernel=4.0 - _archrel=30 + _archrel=31 _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 diff --git a/libre/tp_smapi/PKGBUILD b/libre/tp_smapi/PKGBUILD index d8da0c2f8..a4dbeda24 100644 --- a/libre/tp_smapi/PKGBUILD +++ b/libre/tp_smapi/PKGBUILD @@ -14,7 +14,7 @@ _kernelname= if [[ ${_kernelname} == "" ]]; then _basekernel=4.0 - _archrel=67 + _archrel=68 _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 diff --git a/libre/vhba-module/PKGBUILD b/libre/vhba-module/PKGBUILD index caf5dbad2..5017d64d5 100644 --- a/libre/vhba-module/PKGBUILD +++ b/libre/vhba-module/PKGBUILD @@ -9,7 +9,7 @@ _kernelname= if [[ ${_kernelname} == "" ]]; then _basekernel=4.0 - _archrel=11 + _archrel=12 _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 -- cgit v1.2.3 From ef1c222899e2389b931c7be8c6e015bd1fdafede Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 02:56:02 -0300 Subject: epiphany-3.16.1-1.parabola1: updating version --- libre/epiphany/PKGBUILD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libre') diff --git a/libre/epiphany/PKGBUILD b/libre/epiphany/PKGBUILD index 791e2363d..32ac2da01 100644 --- a/libre/epiphany/PKGBUILD +++ b/libre/epiphany/PKGBUILD @@ -1,10 +1,10 @@ -# $Id: PKGBUILD 234618 2015-03-24 11:52:11Z jgc $ +# $Id: PKGBUILD 239267 2015-05-12 21:57:11Z heftig $ # Maintainer (Arch): Jan de Groot # Maintainer: André Silva # Contributor: Márcio Silva pkgname=epiphany -pkgver=3.16.0 +pkgver=3.16.1 pkgrel=1.parabola1 install=epiphany.install pkgdesc="A GNOME web browser based on the WebKit rendering engine, with DuckDuckGo HTML support" @@ -18,7 +18,7 @@ options=('!emptydirs') groups=('gnome') url="https://wiki.gnome.org/Apps/Web" source=(http://ftp.gnome.org/pub/GNOME/sources/$pkgname/${pkgver:0:4}/$pkgname-$pkgver.tar.xz) -sha256sums=('e8471b492649ee2a5dbbb76ac9225f0131f95895c3962bc2842799e872d82cae') +sha256sums=('4e59a13c299d1ce726871958e1925b42f93d8c73bf1bb0decf79749be00e9666') prepare() { cd $pkgname-$pkgver -- cgit v1.2.3 From 2846e30526bbfcd2dfb64f928125f4d17146c81e Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 03:03:21 -0300 Subject: file-roller-3.16.2-1.parabola1: updating version --- libre/file-roller/PKGBUILD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libre') diff --git a/libre/file-roller/PKGBUILD b/libre/file-roller/PKGBUILD index 5dd047e9b..bf7ae1100 100644 --- a/libre/file-roller/PKGBUILD +++ b/libre/file-roller/PKGBUILD @@ -1,9 +1,9 @@ -# $Id: PKGBUILD 236427 2015-04-14 01:29:45Z heftig $ +# $Id: PKGBUILD 239229 2015-05-12 20:24:47Z heftig $ # Maintainer (Arch): Jan Alexander Steffens (heftig) # Contributor (Arch): Jan de Groot pkgname=file-roller -pkgver=3.16.1 +pkgver=3.16.2 pkgrel=1.parabola1 pkgdesc="Create and modify archives, with unar support included and nonfree unace recommendation removed" arch=('i686' 'x86_64' 'mips64el') @@ -18,7 +18,7 @@ options=('!emptydirs') install=file-roller.install url="http://www.gnome.org" source=(http://ftp.gnome.org/pub/gnome/sources/$pkgname/${pkgver:0:4}/$pkgname-$pkgver.tar.xz) -sha256sums=('d0e3cf1af1bc30e29e6bbf9444fed859092e999bc4686541c021d6c1f6a58689') +sha256sums=('60897ff24d4822395a227b62811c3b8768b701844961e93303d6d6d9463d7e3f') build() { cd $pkgname-$pkgver -- cgit v1.2.3 From 1ba1a688f35e4b6661ac8a1b272c15cfd9c707a5 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 03:23:54 -0300 Subject: gnome-boxes-3.16.2-1.parabola1: updating version --- libre/gnome-boxes/PKGBUILD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libre') diff --git a/libre/gnome-boxes/PKGBUILD b/libre/gnome-boxes/PKGBUILD index e253e733f..6a66da448 100644 --- a/libre/gnome-boxes/PKGBUILD +++ b/libre/gnome-boxes/PKGBUILD @@ -1,11 +1,11 @@ -# $Id: PKGBUILD 131333 2015-04-14 01:31:01Z heftig $ +# $Id: PKGBUILD 133347 2015-05-12 21:58:44Z heftig $ # Maintainer (Arch): Balló György # Contributor (Arch): Stefano Facchini # Maintainer: André Silva # Contributor: Daniel Milewski pkgname=gnome-boxes -pkgver=3.16.1 +pkgver=3.16.2 pkgrel=1.parabola1 pkgdesc="Simple GNOME 3 application to access remote or virtual systems, without nonfree system logos" arch=('i686' 'x86_64' 'mips64el') @@ -20,7 +20,7 @@ makedepends=('gobject-introspection' 'intltool' 'itstool' 'spice-protocol' 'vala install=$pkgname.install source=(http://ftp.gnome.org/pub/GNOME/sources/$pkgname/${pkgver::4}/$pkgname-$pkgver.tar.xz libre.patch) -sha256sums=('41efae4e6906c9f4b687d996cb07316e71dbdae6f619a497801ab26557e8480d' +sha256sums=('f5fecb1ba0769e2a3dbec31e6149fffbcbd59946e4dbab31fb3ec28a16e41995' '73ea08076d1e2608e27969fbf3127b5f45a659b2a8a89b04e349b519ce1d07ba') prepare() { -- cgit v1.2.3 From c515bf05d8cd2daa1a44487167ae1402115cc9af Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 04:04:47 -0300 Subject: kdelibs-4.14.8-1.parabola1: updating version --- libre/kdelibs/PKGBUILD | 15 ++--- libre/kdelibs/dolphin-places.patch | 119 ------------------------------------- 2 files changed, 6 insertions(+), 128 deletions(-) delete mode 100644 libre/kdelibs/dolphin-places.patch (limited to 'libre') diff --git a/libre/kdelibs/PKGBUILD b/libre/kdelibs/PKGBUILD index 75ed14522..9c11da583 100644 --- a/libre/kdelibs/PKGBUILD +++ b/libre/kdelibs/PKGBUILD @@ -5,9 +5,9 @@ # Maintainer: André Silva pkgname=kdelibs -pkgver=4.14.7 -_kdeappver=15.04.0 -pkgrel=3.parabola1 +pkgver=4.14.8 +_kdeappver=15.04.1 +pkgrel=1.parabola1 pkgdesc="KDE Core Libraries, without nonfree plugins recommendation support" arch=('i686' 'x86_64' 'mips64el') url='https://projects.kde.org/projects/kde/kdelibs' @@ -21,12 +21,11 @@ depends=('attica-qt4' 'libxss' 'krb5' 'qca' 'libdbusmenu-qt' 'polkit-qt4' makedepends=('cmake' 'automoc4' 'avahi' 'libgl' 'hspell' 'mesa' 'grantlee-qt4') install=${pkgname}.install source=("http://download.kde.org/stable/applications/${_kdeappver}/src/${pkgname}-${pkgver}.tar.xz" - 'kde-applications-menu.patch' 'khtml-fsdg.diff' 'qt4.patch' 'dolphin-places.patch') -sha1sums=('6de82328f692717b97ad6833109a564a7b6a0a9a' + 'kde-applications-menu.patch' 'khtml-fsdg.diff' 'qt4.patch') +sha1sums=('98b174dbbbef340bcfc11b819405d8e838cac34c' '86ee8c8660f19de8141ac99cd6943964d97a1ed7' 'a1502a964081ad583a00cf90c56e74bf60121830' - 'ed1f57ee661e5c7440efcaba7e51d2554709701c' - 'a53959b740b66054f981139430f91885657d5e94') + 'ed1f57ee661e5c7440efcaba7e51d2554709701c') prepare() { mkdir build @@ -37,8 +36,6 @@ prepare() { patch -p1 -i "${srcdir}"/khtml-fsdg.diff # qmake refers to Qt5 patch -p1 -i "${srcdir}"/qt4.patch - # fix disappearing bookmarks in Dolphin https://bugs.kde.org/show_bug.cgi?id=345174 - patch -p1 -i "$srcdir"/dolphin-places.patch } build() { diff --git a/libre/kdelibs/dolphin-places.patch b/libre/kdelibs/dolphin-places.patch deleted file mode 100644 index a43812eff..000000000 --- a/libre/kdelibs/dolphin-places.patch +++ /dev/null @@ -1,119 +0,0 @@ -From: Emmanuel Pescosta -Date: Wed, 29 Apr 2015 14:02:02 +0000 -Subject: Remove bookmarks syncing from KFilePlacesModel and use user-places.xbel only. -X-Git-Url: http://quickgit.kde.org/?p=kdelibs.git&a=commitdiff&h=5c0a31a2f2a46aa44b8c34baae67b6951b2abcaf ---- -Remove bookmarks syncing from KFilePlacesModel and use user-places.xbel only. - -FIXED-IN: 4.14.8 -BUG: 345174 -REVIEW: 123568 ---- - - ---- a/kfile/CMakeLists.txt -+++ b/kfile/CMakeLists.txt -@@ -22,7 +22,6 @@ - kfilewidget.cpp - kfileplacesitem.cpp - kfileplacesmodel.cpp -- kfileplacessharedbookmarks.cpp - kfileplacesview.cpp - kfileplaceeditdialog.cpp - kfilepreviewgenerator.cpp - ---- a/kfile/kfileplacesmodel.cpp -+++ b/kfile/kfileplacesmodel.cpp -@@ -19,7 +19,6 @@ - */ - #include "kfileplacesmodel.h" - #include "kfileplacesitem_p.h" --#include "kfileplacessharedbookmarks_p.h" - - #ifdef _WIN32_WCE - #include "Windows.h" -@@ -61,10 +60,9 @@ - class KFilePlacesModel::Private - { - public: -- Private(KFilePlacesModel *self) : q(self), bookmarkManager(0), sharedBookmarks(0) {} -+ Private(KFilePlacesModel *self) : q(self), bookmarkManager(0) {} - ~Private() - { -- delete sharedBookmarks; - qDeleteAll(items); - } - -@@ -76,7 +74,6 @@ - - Solid::Predicate predicate; - KBookmarkManager *bookmarkManager; -- KFilePlacesSharedBookmarks * sharedBookmarks; - - void reloadAndSignal(); - QList loadBookmarkList(); -@@ -93,8 +90,8 @@ - KFilePlacesModel::KFilePlacesModel(QObject *parent) - : QAbstractItemModel(parent), d(new Private(this)) - { -- const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml"); -- d->bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces"); -+ const QString file = KStandardDirs().localxdgdatadir() + "user-places.xbel"; -+ d->bookmarkManager = KBookmarkManager::managerForExternalFile(file); - - // Let's put some places in there if it's empty. We have a corner case here: - // Given you have bookmarked some folders (which have been saved on -@@ -145,9 +142,6 @@ - // user-places.xbel will be filled later). (ereslibre) - d->bookmarkManager->saveAs(file); - } -- -- // create after, so if we have own places, they are added afterwards, in case of equal priorities -- d->sharedBookmarks = new KFilePlacesSharedBookmarks(d->bookmarkManager); - - QString predicate("[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]" - " OR " -@@ -632,8 +626,6 @@ - return false; - } - -- d->sharedBookmarks->updateSharedBookmarks(); -- - d->reloadAndSignal(); - - return true; -@@ -660,8 +652,6 @@ - KFilePlacesItem *item = static_cast(after.internalPointer()); - d->bookmarkManager->root().moveBookmark(bookmark, item->bookmark()); - } -- -- d->sharedBookmarks->updateSharedBookmarks(); - - d->reloadAndSignal(); - } -@@ -684,8 +674,6 @@ - bookmark.setIcon(iconName); - bookmark.setMetaDataItem("OnlyInApp", appName); - -- d->sharedBookmarks->updateSharedBookmarks(); -- - d->reloadAndSignal(); - emit dataChanged(index, index); - } -@@ -703,7 +691,6 @@ - if (bookmark.isNull()) return; - - d->bookmarkManager->root().deleteBookmark(bookmark); -- d->sharedBookmarks->updateSharedBookmarks(); - d->reloadAndSignal(); - } - -@@ -718,8 +705,6 @@ - if (bookmark.isNull()) return; - - bookmark.setMetaDataItem("IsHidden", (hidden ? "true" : "false")); -- -- d->sharedBookmarks->updateSharedBookmarks(); - - d->reloadAndSignal(); - emit dataChanged(index, index); -- cgit v1.2.3 From aa3be8bdfd896e69b3b33c3dfa8ed3e9450452e4 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 04:16:11 -0300 Subject: kdebase-runtime-15.04.1-1.parabola1: updating version --- libre/kdebase-runtime/PKGBUILD | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libre') diff --git a/libre/kdebase-runtime/PKGBUILD b/libre/kdebase-runtime/PKGBUILD index 7d17fd5f3..14c7a85a9 100644 --- a/libre/kdebase-runtime/PKGBUILD +++ b/libre/kdebase-runtime/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 237798 2015-04-20 18:54:26Z arojas $ +# $Id: PKGBUILD 238946 2015-05-10 20:32:14Z arojas $ # Maintainer (Arch): Felix Yan # Contributor (Arch): Andrea Scarpino # Contributor (Arch): Pierre Schmitz @@ -6,8 +6,8 @@ pkgbase=kdebase-runtime pkgname=kdebase-runtime -pkgver=15.04.0 -pkgrel=4.parabola1 +pkgver=15.04.1 +pkgrel=1.parabola1 pkgdesc="Plugins and applications necessary for the running of KDE applications, without non-privacy search providers" arch=('i686' 'x86_64' 'mips64el') url='https://projects.kde.org/projects/kde/kde-runtime' @@ -17,7 +17,7 @@ makedepends=('kdelibs' 'libkactivities4' 'smbclient' 'libssh' 'libcanberra' 'lib source=("http://download.kde.org/stable/applications/${pkgver}/src/kde-runtime-${pkgver}.tar.xz" 'duckduckgo_html.desktop' 'duckduckgo_lite.desktop') -sha1sums=('5cbfec48ead85a1cd3dab675b98623dd4a831d91' +sha1sums=('73ac23a97bc81b3e988a214ee1342743e516c74c' 'aa6f39f4b0ad3c110fd05cd6c41190afae9773dd' 'ac3bac94a2c4b1444642524bc5fb539c4c5dcc5b') -- cgit v1.2.3 From 38136f61464f0d1a198f690a248d3ba8f863d810 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 04:44:50 -0300 Subject: kdebase-konqueror-15.04.1-1.parabola1: updating version --- libre/kdebase-konqueror/PKGBUILD | 15 ++++++--------- libre/kdebase-konqueror/dolphin-places.patch | 26 -------------------------- 2 files changed, 6 insertions(+), 35 deletions(-) delete mode 100644 libre/kdebase-konqueror/dolphin-places.patch (limited to 'libre') diff --git a/libre/kdebase-konqueror/PKGBUILD b/libre/kdebase-konqueror/PKGBUILD index 0b8c3fb2b..617b33bf4 100644 --- a/libre/kdebase-konqueror/PKGBUILD +++ b/libre/kdebase-konqueror/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 238288 2015-04-30 08:34:07Z arojas $ +# $Id: PKGBUILD 238946 2015-05-10 20:32:14Z arojas $ # Maintainer (Arch): Felix Yan # Contributor (Arch): Andrea Scarpino # Contributor (Arch): Pierre Schmitz @@ -6,8 +6,8 @@ # Maintainer: André Silva pkgname='kdebase-konqueror' -pkgver=15.04.0 -pkgrel=3.parabola1 +pkgver=15.04.1 +pkgrel=1.parabola1 arch=('i686' 'x86_64' 'mips64el') url="http://kde.org/applications/internet/konqueror/" license=('GPL' 'LGPL' 'FDL') @@ -16,10 +16,9 @@ conflicts=('kdebase-nsplugins' 'kdebase-konqueror-libre') replaces=('kdebase-nsplugins' 'kdebase-konqueror-libre') makedepends=('kdelibs' 'cmake' 'automoc4' 'tidyhtml' 'baloo4-widgets') source=("http://download.kde.org/stable/applications/${pkgver}/src/kde-baseapps-${pkgver}.tar.xz" - 'konq-about-fsdg.diff' 'dolphin-places.patch') -sha1sums=('18ec78a547ca68b110d3b82a12a0001bf62d0b66' - 'd6cbb53c04179b8180f9439eca156b7ff2e76b3a' - 'a3c0536eece94ac288184ceaed3b6bde9241f2dc') + 'konq-about-fsdg.diff') +sha1sums=('099c2d63bd3482936966445950fa290a6dc43550' + 'd6cbb53c04179b8180f9439eca156b7ff2e76b3a') pkgdesc='KDE File Manager & Web Browser, without Google and nonfree software recommendation' depends=('kdebase-dolphin' 'kdebase-keditbookmarks') optdepends=('kwebkitpart: to enable webkit engine') @@ -31,8 +30,6 @@ prepare() { cd kde-baseapps-${pkgver} # Don't recommend nonfree software or Google. patch -Np1 -i "${srcdir}/konq-about-fsdg.diff" - # Fix disappearing bookmarks in Dolphin https://bugs.kde.org/show_bug.cgi?id=345174 - patch -p1 -i "$srcdir"/dolphin-places.patch } build() { diff --git a/libre/kdebase-konqueror/dolphin-places.patch b/libre/kdebase-konqueror/dolphin-places.patch deleted file mode 100644 index 2a2bfcba1..000000000 --- a/libre/kdebase-konqueror/dolphin-places.patch +++ /dev/null @@ -1,26 +0,0 @@ -From: Emmanuel Pescosta -Date: Thu, 30 Apr 2015 08:12:24 +0000 -Subject: Use user-places.xbel instead of bookmarks.xml in places model. -X-Git-Url: http://quickgit.kde.org/?p=kde-baseapps.git&a=commitdiff&h=270d2affaafcc9e87ba14f82bfe579e22607e2d2 ---- -Use user-places.xbel instead of bookmarks.xml in places model. - -FIXED-IN: 15.04.1 -CCBUG: 345174 ---- - - ---- a/dolphin/src/panels/places/placesitemmodel.cpp -+++ b/dolphin/src/panels/places/placesitemmodel.cpp -@@ -85,8 +85,8 @@ - Baloo::IndexerConfig config; - m_fileIndexingEnabled = config.fileIndexingEnabled(); - #endif -- const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml"); -- m_bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces"); -+ const QString file = KStandardDirs().localxdgdatadir() + "user-places.xbel"; -+ m_bookmarkManager = KBookmarkManager::managerForExternalFile(file); - - createSystemBookmarks(); - initializeAvailableDevices(); - -- cgit v1.2.3 From 30e64aa0bdb9a93d4d44c91651ac84e0d671cdb5 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 05:09:02 -0300 Subject: kdenetwork-kopete-15.04.1-1.parabola1{,.nonprism1}: updating version --- libre/kdenetwork-kopete/PKGBUILD | 6 +++--- nonprism/kdenetwork-kopete/PKGBUILD | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'libre') diff --git a/libre/kdenetwork-kopete/PKGBUILD b/libre/kdenetwork-kopete/PKGBUILD index fb715f7e1..87290ac9a 100644 --- a/libre/kdenetwork-kopete/PKGBUILD +++ b/libre/kdenetwork-kopete/PKGBUILD @@ -1,9 +1,9 @@ -# $Id: PKGBUILD 236016 2015-04-10 06:56:26Z arojas $ +# $Id: PKGBUILD 238946 2015-05-10 20:32:14Z arojas $ # Maintainer (Arch): Andrea Scarpino # Maintainer: André Silva pkgname=kdenetwork-kopete -pkgver=15.04.0 +pkgver=15.04.1 pkgrel=1.parabola1 pkgdesc='Instant Messenger, without nonfree Skype support' url='http://kde.org/applications/internet/kopete/' @@ -17,7 +17,7 @@ makedepends=('cmake' 'automoc4' 'boost' 'kdepim-libkdepim' 'mediastreamer' 'libg optdepends=('mediastreamer: jingle support' 'libgadu: Gadu-Gadu protocol') install=${pkgname}.install source=("http://download.kde.org/stable/applications/${pkgver}/src/kopete-${pkgver}.tar.xz") -sha1sums=('c287f0fdfc179d97a634320dd54aebcba08561d9') +sha1sums=('18d3061ecfc7e287408d3842ed690e128520fd40') prepare() { cd kopete-${pkgver} diff --git a/nonprism/kdenetwork-kopete/PKGBUILD b/nonprism/kdenetwork-kopete/PKGBUILD index ec29bffa9..fc41adc01 100644 --- a/nonprism/kdenetwork-kopete/PKGBUILD +++ b/nonprism/kdenetwork-kopete/PKGBUILD @@ -1,9 +1,9 @@ -# $Id: PKGBUILD 236016 2015-04-10 06:56:26Z arojas $ +# $Id: PKGBUILD 238946 2015-05-10 20:32:14Z arojas $ # Maintainer (Arch): Andrea Scarpino # Maintainer: André Silva pkgname=kdenetwork-kopete -pkgver=15.04.0 +pkgver=15.04.1 pkgrel=1.parabola1.nonprism1 pkgdesc='Instant Messenger, without nonfree Skype support and support for unsafe and dangerous for privacy protocols' url='http://kde.org/applications/internet/kopete/' @@ -18,7 +18,7 @@ optdepends=('mediastreamer: jingle support') install=${pkgname}.install source=("http://download.kde.org/stable/applications/${pkgver}/src/kopete-${pkgver}.tar.xz" 'libre-nonprism.patch') -sha1sums=('c287f0fdfc179d97a634320dd54aebcba08561d9' +sha1sums=('18d3061ecfc7e287408d3842ed690e128520fd40' 'f0d7b727da1b5160f05952eec4df1bfbefab99cf') prepare() { -- cgit v1.2.3 From fdeec642a378b1aab3b20fa5be58cc533054df97 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 14 May 2015 05:20:30 -0300 Subject: kdeutils-ark-15.04.1-1.parabola1: updating version --- libre/kdeutils-ark/PKGBUILD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libre') diff --git a/libre/kdeutils-ark/PKGBUILD b/libre/kdeutils-ark/PKGBUILD index 50b8c2b7c..0d73786c4 100644 --- a/libre/kdeutils-ark/PKGBUILD +++ b/libre/kdeutils-ark/PKGBUILD @@ -1,10 +1,10 @@ -# $Id: PKGBUILD 236016 2015-04-10 06:56:26Z arojas $ +# $Id: PKGBUILD 238946 2015-05-10 20:32:14Z arojas $ # Maintainer (Arch): Felix Yan # Contributor (Arch): Andrea Scarpino # Maintainer: André Silva pkgname=kdeutils-ark -pkgver=15.04.0 +pkgver=15.04.1 pkgrel=1.parabola1 pkgdesc='Archiving Tool, with unar support' url='http://kde.org/applications/utilities/ark/' @@ -19,7 +19,7 @@ optdepends=('p7zip' 'zip' 'unzip' 'unar') install=${pkgname}.install source=("http://download.kde.org/stable/applications/${pkgver}/src/ark-${pkgver}.tar.xz" 'ark-unar-06.patch') -sha1sums=('7f5d5bd32ab472e2c17f51d9ee19d16cdb9c9fbe' +sha1sums=('dcfe0c465c9c51b402d2192058126caee206ad8c' 'a0a836950f185d9b2245204579f969203036fdec') prepare() { -- cgit v1.2.3 From e97e4049f633c66ce53c45b1fc76763a2f9e23be Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Fri, 15 May 2015 05:50:19 -0300 Subject: mesa-libcl-10.5.5-1: updating version --- libre/mesa-libcl/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libre') diff --git a/libre/mesa-libcl/PKGBUILD b/libre/mesa-libcl/PKGBUILD index 85e5ff969..23697e90a 100644 --- a/libre/mesa-libcl/PKGBUILD +++ b/libre/mesa-libcl/PKGBUILD @@ -4,7 +4,7 @@ pkgbase=mesa _pkgname=libcl pkgname=$pkgbase-$_pkgname -pkgver=10.5.4 +pkgver=10.5.5 pkgrel=1 pkgdesc='Mesa 3-D OpenCL library and ICD loader' arch=('i686' 'x86_64' 'mips64el') @@ -18,7 +18,7 @@ provides=("$_pkgname") conflicts=("$_pkgname" "$_pkgname-libre" 'opencl-nvidia' 'opencl-nvidia-304xx') replaces=("$_pkgname" "$_pkgname-libre" 'opencl-nvidia' 'opencl-nvidia-304xx') source=(ftp://ftp.freedesktop.org/pub/$pkgbase/$pkgver/$pkgbase-$pkgver.tar.xz{,.sig}) -sha512sums=('e8268b5a28eeafe03d8d8e4a1b3865e5b4a05501507d5b623f7d4c542ade3d8fa6fef2a2b6c05d6aaefa81de26365ab6bb895a0ba2a1d9c05dd1fd701bdab5f5' +sha512sums=('d339f598bfdbe14388d3213b166bed5f89e67535b0ccc09d47f434e2669ed3c5d4c23a1c86f3e180d90e8ba1175f9de24f62b16364f072ac6bb695b57e519b61' 'SKIP') validpgpkeys=('8703B6700E7EE06D7A39B8D6EDAE37B02CEB490D') # Emil Velikov -- cgit v1.2.3 From 73d0d912d77be4264098ed2d622bf20a3b3a2000 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Fri, 15 May 2015 17:25:15 -0300 Subject: calibre-2.28.0-1.parabola1: updating version --- libre/calibre/PKGBUILD | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libre') diff --git a/libre/calibre/PKGBUILD b/libre/calibre/PKGBUILD index 83b760053..d4939e203 100644 --- a/libre/calibre/PKGBUILD +++ b/libre/calibre/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 132635 2015-05-02 09:40:48Z jelle $ +# $Id: PKGBUILD 133492 2015-05-15 10:21:09Z jelle $ # Maintainer (Arch): Jelle van der Waa # Maintainer (Arch): Daniel Wallace # Contributor (Arch): Giovanni Scafora @@ -9,7 +9,7 @@ pkgname=calibre _pkgname=$pkgname-libre -pkgver=2.27.0 +pkgver=2.28.0 pkgrel=1.parabola1 pkgdesc="Ebook management application, without nonfree decompression engine for RAR archives" arch=('i686' 'x86_64' 'mips64el') @@ -32,8 +32,8 @@ install=$pkgname.install mksource=("http://download.$pkgname-ebook.com/${pkgver}/$pkgname-${pkgver}.tar.xz") source=("https://repo.parabola.nu/other/${_pkgname}/${_pkgname}-${pkgver}.tar.xz" 'libre.patch') -mkmd5sums=('a41aa53d514b095fc269cefa69bf88e5') -md5sums=('4bcef173cc7775bc82c0d5e17c78f5eb' +mkmd5sums=('1837c57d4c115049c3749e03ca3378ba') +md5sums=('36639a9ebd87beab162135130bbfa628' '466d44b66e40a94ede272093ccd9ade4') mksource(){ -- cgit v1.2.3 From fbfa247389003694464f4df34982fe076f86f722 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 16 May 2015 09:16:45 -0300 Subject: linux-libre-4.0.3_gnu-1: updating version --- libre/linux-libre/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libre') diff --git a/libre/linux-libre/PKGBUILD b/libre/linux-libre/PKGBUILD index b4c00da84..6a205f495 100644 --- a/libre/linux-libre/PKGBUILD +++ b/libre/linux-libre/PKGBUILD @@ -9,7 +9,7 @@ pkgbase=linux-libre # Build stock "" kernel _pkgbasever=4.0-gnu -_pkgver=4.0.2-gnu +_pkgver=4.0.3-gnu _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -38,7 +38,7 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li '4.0-rc7-37af2c8aae-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - '6b559c4393922896752822a63d22fb51f4aad0d8feb123a9c7a518d25ca7b378' + '73e5adbee83c5d5898f03b4f7525876cc0db6eab0e569a4229ee8d8cf9e3ef2e' 'SKIP' 'a9a0590e45ec7b3913f0da294c52bbd6f4c0034a1ef1fedb83f3c6347003f499' '69f73083d02e937e4c47a88c559da55a45efa17a6740459d0a002aa8ccfd89c2' -- cgit v1.2.3 From 496206d18afc54ff00475501b22f6b265c7369b3 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 16 May 2015 09:17:02 -0300 Subject: linux-libre-lts-3.14.42_gnu-1: updating version --- libre/linux-libre-lts/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libre') diff --git a/libre/linux-libre-lts/PKGBUILD b/libre/linux-libre-lts/PKGBUILD index 8c7aa4b08..b18238083 100644 --- a/libre/linux-libre-lts/PKGBUILD +++ b/libre/linux-libre-lts/PKGBUILD @@ -9,7 +9,7 @@ pkgbase=linux-libre-lts # Build kernel with -lts localname _pkgbasever=3.14-gnu -_pkgver=3.14.41-gnu +_pkgver=3.14.42-gnu _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -43,7 +43,7 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li '3.14.26-8475f027b4-loongson-community.patch') sha256sums=('477555c709b9407fe37dbd70d3331ff9dde1f9d874aba2741f138d07ae6f281b' 'SKIP' - '120e97db433d48fb6d099497baa0da5b335eeb5ec48882a5c6911e93b6b08781' + 'b3b2b73aab358b0371fb02cbb112e90daf341db661300262f2a835ea29d9161c' 'SKIP' 'b4cc9c49948fc1d571c27ddeddd93b5b499ccc17fb06fa75bfe41ecddfbc12e4' '3fa8ce26aea9b5e596ccfc842baa3f2a8be8ef4a62bc13d75e8da2bafd89141c' -- cgit v1.2.3 From 7a745e89d8042557066123b99a013378cf3bacb0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 16 May 2015 09:20:35 -0300 Subject: linux-libre-grsec{,-knock}-4.0.3_gnu.201505141746-1: updating version --- kernels/linux-libre-grsec-knock/PKGBUILD | 8 ++++---- libre/linux-libre-grsec/PKGBUILD | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'libre') diff --git a/kernels/linux-libre-grsec-knock/PKGBUILD b/kernels/linux-libre-grsec-knock/PKGBUILD index ac586b99f..24a513aa3 100644 --- a/kernels/linux-libre-grsec-knock/PKGBUILD +++ b/kernels/linux-libre-grsec-knock/PKGBUILD @@ -12,9 +12,9 @@ pkgbase=linux-libre-grsec-knock # Build kernel with -grsec-knock localname _pkgbasever=4.0-gnu -_pkgver=4.0.2-gnu +_pkgver=4.0.3-gnu _grsecver=3.1 -_timestamp=201505072057 +_timestamp=201505141746 _knockpatchver=3.18_1 _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname @@ -49,9 +49,9 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li '4.0-rc7-37af2c8aae-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - '6b559c4393922896752822a63d22fb51f4aad0d8feb123a9c7a518d25ca7b378' + '73e5adbee83c5d5898f03b4f7525876cc0db6eab0e569a4229ee8d8cf9e3ef2e' 'SKIP' - '62b75881f2bc760c585f77b73c335fbf439db042eb456abb8765fc644d7b5b5a' + 'e10e9292b02728a3e2d4157b385298095c29634d00e7ae5f9f2847576d69c570' 'SKIP' '93a1610c203ea4c187ac5b50dce105fac86df914b1406e1d85df5857d36201c9' 'SKIP' diff --git a/libre/linux-libre-grsec/PKGBUILD b/libre/linux-libre-grsec/PKGBUILD index 084b10b17..97c34f539 100644 --- a/libre/linux-libre-grsec/PKGBUILD +++ b/libre/linux-libre-grsec/PKGBUILD @@ -12,9 +12,9 @@ pkgbase=linux-libre-grsec # Build kernel with -grsec localname _pkgbasever=4.0-gnu -_pkgver=4.0.2-gnu +_pkgver=4.0.3-gnu _grsecver=3.1 -_timestamp=201505072057 +_timestamp=201505141746 _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -46,9 +46,9 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li '4.0-rc7-37af2c8aae-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - '6b559c4393922896752822a63d22fb51f4aad0d8feb123a9c7a518d25ca7b378' + '73e5adbee83c5d5898f03b4f7525876cc0db6eab0e569a4229ee8d8cf9e3ef2e' 'SKIP' - '62b75881f2bc760c585f77b73c335fbf439db042eb456abb8765fc644d7b5b5a' + 'e10e9292b02728a3e2d4157b385298095c29634d00e7ae5f9f2847576d69c570' 'SKIP' 'd1b2bfc86563d522562850556a2dd39f41b91b992cb4d839551e44e8d9df0ae3' '92580d3bd2f8c66ccc9467e9a4bfbc012e90a3d32953503750309313755a3ea2' -- cgit v1.2.3 From e6db179fe23d4d4c9746aa0857fa398a0603499b Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 16 May 2015 10:07:30 -0300 Subject: rebuild module packages against linux-libre-lts-3.14.42_gnu-1 --- libre/acpi_call/PKGBUILD | 2 +- libre/bbswitch/PKGBUILD | 2 +- libre/tp_smapi/PKGBUILD | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'libre') diff --git a/libre/acpi_call/PKGBUILD b/libre/acpi_call/PKGBUILD index 5cd88cb4c..fb7990f3d 100644 --- a/libre/acpi_call/PKGBUILD +++ b/libre/acpi_call/PKGBUILD @@ -13,7 +13,7 @@ if [[ ${_kernelname} == "" ]]; then _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 - _archrel=17 + _archrel=21 _parabolarel=1 elif [[ ${_kernelname} == -grsec ]]; then _basekernel=3.19 diff --git a/libre/bbswitch/PKGBUILD b/libre/bbswitch/PKGBUILD index 6caa4ce93..76cd2c59a 100644 --- a/libre/bbswitch/PKGBUILD +++ b/libre/bbswitch/PKGBUILD @@ -13,7 +13,7 @@ if [[ ${_kernelname} == "" ]]; then _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 - _archrel=8 + _archrel=10 _parabolarel=1 elif [[ ${_kernelname} == -grsec ]]; then _basekernel=3.19 diff --git a/libre/tp_smapi/PKGBUILD b/libre/tp_smapi/PKGBUILD index a4dbeda24..1a987a03c 100644 --- a/libre/tp_smapi/PKGBUILD +++ b/libre/tp_smapi/PKGBUILD @@ -18,7 +18,7 @@ if [[ ${_kernelname} == "" ]]; then _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 - _archrel=39 + _archrel=41 _parabolarel=1 elif [[ ${_kernelname} == -grsec ]]; then _basekernel=3.19 -- cgit v1.2.3 From d63973b33f2a03a80317e4c79ce3f231ec207690 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sun, 17 May 2015 05:19:39 -0300 Subject: rebuild module packages against linux-libre-4.0.3_gnu-1 --- libre/acpi_call/PKGBUILD | 2 +- libre/bbswitch/PKGBUILD | 2 +- libre/tp_smapi/PKGBUILD | 2 +- libre/vhba-module/PKGBUILD | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'libre') diff --git a/libre/acpi_call/PKGBUILD b/libre/acpi_call/PKGBUILD index fb7990f3d..3ad505a61 100644 --- a/libre/acpi_call/PKGBUILD +++ b/libre/acpi_call/PKGBUILD @@ -9,7 +9,7 @@ _kernelname= if [[ ${_kernelname} == "" ]]; then _basekernel=4.0 - _archrel=29 + _archrel=30 _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 diff --git a/libre/bbswitch/PKGBUILD b/libre/bbswitch/PKGBUILD index 76cd2c59a..42b18c2a1 100644 --- a/libre/bbswitch/PKGBUILD +++ b/libre/bbswitch/PKGBUILD @@ -9,7 +9,7 @@ _kernelname= if [[ ${_kernelname} == "" ]]; then _basekernel=4.0 - _archrel=31 + _archrel=32 _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 diff --git a/libre/tp_smapi/PKGBUILD b/libre/tp_smapi/PKGBUILD index 1a987a03c..7aeb2ccf5 100644 --- a/libre/tp_smapi/PKGBUILD +++ b/libre/tp_smapi/PKGBUILD @@ -14,7 +14,7 @@ _kernelname= if [[ ${_kernelname} == "" ]]; then _basekernel=4.0 - _archrel=68 + _archrel=69 _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 diff --git a/libre/vhba-module/PKGBUILD b/libre/vhba-module/PKGBUILD index 5017d64d5..3f2b5f13a 100644 --- a/libre/vhba-module/PKGBUILD +++ b/libre/vhba-module/PKGBUILD @@ -9,7 +9,7 @@ _kernelname= if [[ ${_kernelname} == "" ]]; then _basekernel=4.0 - _archrel=12 + _archrel=13 _parabolarel=1 elif [[ ${_kernelname} == -lts ]]; then _basekernel=3.14 -- cgit v1.2.3 From 3ea90c6a5ae18786cef12d6a28cdeba50d3d6478 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sun, 17 May 2015 14:03:14 -0300 Subject: vim-7.4.723-1.parabola1: updating version --- libre/vim/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libre') diff --git a/libre/vim/PKGBUILD b/libre/vim/PKGBUILD index 5937dbdcf..ec7deac59 100644 --- a/libre/vim/PKGBUILD +++ b/libre/vim/PKGBUILD @@ -9,7 +9,7 @@ pkgbase=vim pkgname=('vim-minimal' 'vim' 'vim-python3' 'gvim' 'gvim-python3' 'vim-runtime') # list of tags can be found at https://code.google.com/p/vim/source/list _topver=7.4 -_patchlevel=712 +_patchlevel=723 _tag=v${_topver/./-}-${_patchlevel} _versiondir="vim${_topver//./}" pkgver=${_topver}.${_patchlevel} -- cgit v1.2.3 From e5013c4a19f8393a42afb5d0275fb3c6f13b9e47 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sun, 17 May 2015 14:15:33 -0300 Subject: file-roller-3.16.2-2.parabola1: improve optdeps, zip support and give priority to libarchive that supports RAR files better --- libre/file-roller/PKGBUILD | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'libre') diff --git a/libre/file-roller/PKGBUILD b/libre/file-roller/PKGBUILD index bf7ae1100..6429a5434 100644 --- a/libre/file-roller/PKGBUILD +++ b/libre/file-roller/PKGBUILD @@ -1,16 +1,19 @@ -# $Id: PKGBUILD 239229 2015-05-12 20:24:47Z heftig $ +# $Id: PKGBUILD 239484 2015-05-17 10:06:23Z heftig $ # Maintainer (Arch): Jan Alexander Steffens (heftig) # Contributor (Arch): Jan de Groot pkgname=file-roller pkgver=3.16.2 -pkgrel=1.parabola1 +pkgrel=2.parabola1 pkgdesc="Create and modify archives, with unar support included and nonfree unace recommendation removed" arch=('i686' 'x86_64' 'mips64el') license=('GPL') -depends=('desktop-file-utils' 'gtk3' 'hicolor-icon-theme' 'dconf' 'libarchive' 'file' 'json-glib' 'libnotify' 'p7zip' 'unar') +depends=('desktop-file-utils' 'gtk3' 'hicolor-icon-theme' 'dconf' 'libarchive' 'file' 'json-glib' 'libnotify' 'p7zip' + 'zip' 'unzip') makedepends=('intltool' 'pkg-config' 'libnautilus-extension' 'itstool' 'docbook-xsl') -optdepends=('lrzip: lrzip archive support') +optdepends=('libarchive: better RAR archive support' + 'lrzip: lrzip archive support' + 'cdrkit: ISO image support') groups=('gnome-extra') replaces=("${pkgname}-libre" "${pkgname}-parabola") conflicts=("${pkgname}-libre" "${pkgname}-parabola") -- cgit v1.2.3 From 297f065f91c0527252f854c60ca667a70de0a356 Mon Sep 17 00:00:00 2001 From: "coadde [Márcio Alexandre Silva Delgado]" Date: Mon, 18 May 2015 22:18:45 -0300 Subject: update your-freedom --- libre/your-freedom/PKGBUILD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libre') diff --git a/libre/your-freedom/PKGBUILD b/libre/your-freedom/PKGBUILD index ba6915ab8..c9e95ae44 100644 --- a/libre/your-freedom/PKGBUILD +++ b/libre/your-freedom/PKGBUILD @@ -5,8 +5,8 @@ pkgdesc="This package conflicts with every nonfree package known to date to ensu license=('GPL3') url="https://projects.parabola.nu/blacklist.git" #url="https://lukeshu.com/git/mirror/parabola/blacklist.git" -pkgver=20150429 -_gitver=148d6b8701309816f80da9a5e9231dad728115eb +pkgver=20150519 +_gitver=e4a9618a4aa1da1421a7dca500081d695a93f114 pkgrel=1 arch=('any') @@ -16,7 +16,7 @@ install=${pkgname}.install makedepends=(librelib) source=(blacklist-${_gitver}.txt::https://projects.parabola.nu/blacklist.git/plain/blacklist.txt?id=${_gitver}) #source=(blacklist-${_gitver}.txt::https://lukeshu.com/git/mirror/parabola/blacklist.git/plain/blacklist.txt?id=${_gitver}) -md5sums=('fc52ca4c19ac5df3c2983bdde6f9e22c') +md5sums=('f41ff6df9922def50127d8cee288f8b9') package() { cd "$srcdir" -- cgit v1.2.3 From a553980e8f718e422fbcd583fa437235516abd30 Mon Sep 17 00:00:00 2001 From: "coadde [Márcio Alexandre Silva Delgado]" Date: Mon, 18 May 2015 22:24:26 -0300 Subject: update your-freedom_emu --- libre/your-freedom_emu/PKGBUILD | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'libre') diff --git a/libre/your-freedom_emu/PKGBUILD b/libre/your-freedom_emu/PKGBUILD index 8b289cd94..379f0b2bc 100644 --- a/libre/your-freedom_emu/PKGBUILD +++ b/libre/your-freedom_emu/PKGBUILD @@ -3,19 +3,19 @@ pkgname=your-freedom_emu pkgdesc="This package removes hardware emulators that emulate technically free games and/or OS (but only there are nonfree games and/or OS)." license=('GPL3') -#url="https://projects.parabolagnulinux.org/blacklist.git" -url="https://lukeshu.com/git/mirror/parabola/blacklist.git" -pkgver=20140827.1 -_gitver=e2410d7936cac105a8af764a2bf771fdcffed4c7 +url="https://projects.parabolagnulinux.org/blacklist.git" +#url="https://lukeshu.com/git/mirror/parabola/blacklist.git" +pkgver=20150519 +_gitver=e4a9618a4aa1da1421a7dca500081d695a93f114 pkgrel=1 arch=('any') install=${pkgname}.install makedepends=(librelib) -#source=(blacklist-${_gitver}.txt::https://projects.parabolagnulinux.org/blacklist.git/plain/${pkgname}-blacklist.txt?id=${_gitver}) -source=(blacklist-${_gitver}.txt::https://lukeshu.com/git/mirror/parabola/blacklist.git/plain/${pkgname}-blacklist.txt?id=${_gitver}) -md5sums=('cf6c392395891ada2fa08970fc5430ef') +source=(blacklist-${_gitver}.txt::https://projects.parabolagnulinux.org/blacklist.git/plain/${pkgname}-blacklist.txt?id=${_gitver}) +#source=(blacklist-${_gitver}.txt::https://lukeshu.com/git/mirror/parabola/blacklist.git/plain/${pkgname}-blacklist.txt?id=${_gitver}) +md5sums=('731850976f34a609ba86ddd4d99e7467') package() { cd "$srcdir" -- cgit v1.2.3 From 868da4da691a9aee89d16793c58e6cd91ebfd99e Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Mon, 18 May 2015 23:43:08 -0300 Subject: asciidoc: add new package to [libre] -> https://labs.parabola.nu/issues/717 --- libre/asciidoc/PKGBUILD | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 libre/asciidoc/PKGBUILD (limited to 'libre') diff --git a/libre/asciidoc/PKGBUILD b/libre/asciidoc/PKGBUILD new file mode 100644 index 000000000..8ef3debd3 --- /dev/null +++ b/libre/asciidoc/PKGBUILD @@ -0,0 +1,64 @@ +# $Id: PKGBUILD 118968 2014-09-14 16:00:30Z bluewind $ +# Contributor (Arch): Chris Brannon +# Contributor (Arch): Geoffroy Carrier +# Contributor (Arch): Dan McGee +# Contributor (Arch): Jaroslaw Rosiek +# Contributor (Arch): Darwin Bautista +# Contributor (Arch): Daniel J Griffiths +# Maintainer (Arch): Florian Pritz +# Maintainer: André Silva + +pkgname=asciidoc +pkgver=8.6.9 +pkgrel=2.parabola1 +pkgdesc='Text document format for short documents, articles, books and UNIX man pages, without nonfree fop recommendation' +arch=('any') +url='http://www.methods.co.nz/asciidoc/' +license=('GPL') +depends=('python2' 'libxslt' 'docbook-xsl') +optdepends=('lilypond: music-filter' + 'imagemagick: music-filter (used in conjunction with lilypond)' + 'source-highlight: source-highlight-filter' + 'dblatex: pdf generation' + 'lynx: text generation' + 'w3m: text generation (alternative to lynx)') +source=("http://downloads.sourceforge.net/${pkgname}/${pkgname}-${pkgver}.tar.gz") +md5sums=('c59018f105be8d022714b826b0be130a') + +prepare() { + cd ${pkgname}-${pkgver} + + # python2 fix + for file in asciidocapi.py a2x.py asciidoc.py filters/music/music2png.py filters/latex/latex2png.py \ + filters/code/code-filter.py filters/graphviz/graphviz2png.py; do + sed -i 's_#!/usr/bin/env python_#!/usr/bin/env python2_' $file + done + #sed -i -e 's_sys:python_sys:python2_g' -e 's_sys3:python_sys3:python2_g' xhtml11.conf + #sed -i 's_sys:python_sys:python2_g' xhtml11-quirks.conf + #sed -i -e 's/{python}/{python2}/g' \ + #-e 's#{language@python:py:#{language@python2:py:#' \ + #filters/source/source-highlight-filter.conf \ + #html5.conf xhtml11.conf xhtml11-quirks.conf + #sed -i -e "s#'python'#'python2'#g" filters/code/code-filter.py +} + +build() { + cd ${pkgname}-${pkgver} + + ./configure \ + --prefix=/usr \ + --sysconfdir=/etc +} + +package() { + cd ${pkgname}-${pkgver} + + make install DESTDIR=${pkgdir} + + install -Dm644 asciidocapi.py \ + ${pkgdir}/usr/lib/python2.7/site-packages/asciidocapi.py + + # fix FS#21579 - [asciidoc] 8.6.2-2 "asciidoc" table style doesn't work (mismatched python version) + #sed -i 's/python/python2/' \ + #${pkgdir}/etc/asciidoc/asciidoc.conf +} -- cgit v1.2.3 From 002cc042e7423a1212fb5086a2a487f315ef7fad Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 19 May 2015 03:09:33 -0300 Subject: mapnik: add new package to [libre] -> https://labs.parabola.nu/issues/718 --- libre/mapnik/PKGBUILD | 53 +++++++++++++++++++++++++++++++++++++++++++++ libre/mapnik/mapnik.install | 11 ++++++++++ 2 files changed, 64 insertions(+) create mode 100644 libre/mapnik/PKGBUILD create mode 100644 libre/mapnik/mapnik.install (limited to 'libre') diff --git a/libre/mapnik/PKGBUILD b/libre/mapnik/PKGBUILD new file mode 100644 index 000000000..6e6676ecd --- /dev/null +++ b/libre/mapnik/PKGBUILD @@ -0,0 +1,53 @@ +# $Id: PKGBUILD 132059 2015-04-23 16:30:52Z spupykin $ +# Maintainer (Arch): Sergej Pupykin +# Contributor (Arch): David Dent +# Contributor (Arch): orbisvicis +# Maintainer: André Silva + +pkgname=mapnik +pkgver=2.2.0.654.g718a8b3 +pkgrel=5.parabola1 +pkgdesc="Free Toolkit for developing mapping applications. Above all Mapnik is about rendering beautiful maps, without nonfree mod_fastcgi recommendation" +arch=('i686' 'x86_64') +url="http://mapnik.org/" +license=('LGPL') +depends=('boost-libs' 'icu' 'libpng' 'libjpeg' 'libtiff' 'freetype2' + 'libxml2' 'python2' 'proj' 'cairo' 'cairomm' 'pycairo' + 'postgresql-libs' 'postgis' 'gdal' 'curl' 'libltdl') +optdepends=('libxslt: Web Map Service' + 'python2-lxml: Web Map Service' + 'python2-pillow: Web Map Service' + 'python-nose: Web Map Service' + 'apache: Web Map Service' + 'mod_fcgid: Web Map Service - or:' + 'mod_wsgi2: Web Map Service') +makedepends=('scons' 'boost' 'git') +install="mapnik.install" +#source=("$pkgname-$pkgver.tar.gz::https://github.com/mapnik/mapnik/archive/v$pkgver.tar.gz") +source=("git://github.com/mapnik/mapnik.git#branch=2.3.x") +md5sums=('SKIP') + +pkgver() { + cd "$srcdir/$pkgname" + + git describe --long | cut -c2- | sed 's/-/./g' +} + +build() { + cd "$srcdir/$pkgname" + + sed -i 's|lib64|lib|g' SConstruct + sed -i 's|python|python2|' \ + utils/performance/mapnik-speed-check \ + utils/upgrade_map_xml/*.py + scons configure \ + PREFIX="/usr" \ + INPUT_PLUGINS=all \ + DESTDIR="$pkgdir" + scons $MAKEFLAGS +} + +package(){ + cd "$srcdir/$pkgname" + scons install +} diff --git a/libre/mapnik/mapnik.install b/libre/mapnik/mapnik.install new file mode 100644 index 000000000..46f265d5b --- /dev/null +++ b/libre/mapnik/mapnik.install @@ -0,0 +1,11 @@ +post_install() { + /sbin/ldconfig +} + +post_upgrade() { + post_install +} + +post_remove() { + post_install +} -- cgit v1.2.3 From c63176dc33a16c7f0dbccf1f3e03da25de508f09 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 19 May 2015 03:12:23 -0300 Subject: openttd: add new package to [libre] -> https://labs.parabola.nu/issues/716 --- libre/openttd/PKGBUILD | 38 ++++++++++++++++++++++++++++++++++++++ libre/openttd/openttd.install | 17 +++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 libre/openttd/PKGBUILD create mode 100644 libre/openttd/openttd.install (limited to 'libre') diff --git a/libre/openttd/PKGBUILD b/libre/openttd/PKGBUILD new file mode 100644 index 000000000..ed984afa9 --- /dev/null +++ b/libre/openttd/PKGBUILD @@ -0,0 +1,38 @@ +# $Id: PKGBUILD 130965 2015-04-08 20:31:16Z lcarlier $ +# Maintainer (Arch): Vesa Kaihlavirta +# Maintainer: André Silva + +pkgname=openttd +pkgver=1.5.0 +pkgrel=1.parabola1 +pkgdesc='An engine for running Transport Tycoon Deluxe, without nonfree openttd-opensfx recommendation' +arch=('i686' 'x86_64') +url='http://www.openttd.org' +license=('GPL') +depends=('libpng' 'sdl' 'icu' 'fontconfig' 'lzo' 'hicolor-icon-theme' 'desktop-file-utils' 'xz') +install=openttd.install +optdepends=('openttd-opengfx: free graphics') +source=("http://binaries.openttd.org/releases/${pkgver}/${pkgname}-${pkgver}-source.tar.xz") +sha256sums=('cb2735c3c94709430c58eb4e8820cd5d26b1a17447c34ca8792bb3432a3f7c2d') + +build() { + cd ${pkgname}-${pkgver} + + ./configure \ + --prefix-dir=/usr \ + --binary-name=${pkgname} \ + --binary-dir=bin \ + --data-dir=share/${pkgname} \ + --install-dir=${pkgdir} \ + --doc-dir=share/doc/${pkgname} \ + --menu-name="OpenTTD" \ + --personal-dir=.${pkgname} + + make +} + +package() { + cd ${pkgname}-${pkgver} + + make install +} diff --git a/libre/openttd/openttd.install b/libre/openttd/openttd.install new file mode 100644 index 000000000..85b22a1c5 --- /dev/null +++ b/libre/openttd/openttd.install @@ -0,0 +1,17 @@ +post_install() { + gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor > /dev/null 2>&1 + update-desktop-database > /dev/null 2>&1 +} + +post_upgrade() { + post_install $1 +} + +pre_remove() { + update-desktop-database > /dev/null 2>&1 +} + +post_remove() { + gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor > /dev/null 2>&1 + update-desktop-database > /dev/null 2>&1 +} -- cgit v1.2.3 From a41018125d32a20b644ff10836d1e737cd0dfa67 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 19 May 2015 04:22:21 -0300 Subject: unp: add new package to [libre] -> https://labs.parabola.nu/issues/715 --- libre/unp/PKGBUILD | 50 ++++++++++++++++++++++++++++++++++++++++++ libre/unp/libre.patch | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 libre/unp/PKGBUILD create mode 100644 libre/unp/libre.patch (limited to 'libre') diff --git a/libre/unp/PKGBUILD b/libre/unp/PKGBUILD new file mode 100644 index 000000000..fe4b53c47 --- /dev/null +++ b/libre/unp/PKGBUILD @@ -0,0 +1,50 @@ +# $Id: PKGBUILD 116352 2014-07-25 17:05:00Z anatolik $ +# Maintainer (Arch): Anatol Pomozov +# Contributor (Arch): Michael Düll PGP-Key: AAAEE882 +# Contributor (Arch): TDY +# Contributor (Arch): Sergio Rubio +# Contributor (Arch): Hannes Rist +# Maintainer: André Silva + +pkgname=unp +pkgver=2.0~pre7+nmu1 +pkgrel=2.parabola1 +pkgdesc='A script for unpacking a wide variety of archive formats, without nonfree unace, unarj and unrar recommendation' +arch=(any) +url='http://packages.qa.debian.org/u/unp.html' +license=(GPL) +depends=(perl) +optdepends=( + 'unzip: zip support' + 'bzip2: bzip2 support' + 'p7zip: p7zip support' + 'cpio: cpio support' + 'sharutils: sharutils' + 'cabextract: cab support' + 'rpmextract: rpm support' +) +source=(http://ftp.debian.org/debian/pool/main/u/unp/unp_$pkgver.tar.bz2 + libre.patch) +sha1sums=('b91f4cbc4720b3aace147652ac2043cf74668244' + '202375dd1c013c798d0d61ab5c273be8ebe1c546') + +prepare() { + cd unp-$pkgver + patch -Np1 -i "$srcdir"/libre.patch +} + +build() { + cd unp-$pkgver/po + make +} + +package() { + cd unp-$pkgver + install -Dm755 unp "$pkgdir"/usr/bin/unp + install -Dm755 ucat "$pkgdir"/usr/bin/ucat + install -Dm644 debian/unp.1 "$pkgdir"/usr/share/man/man1/unp.1 + install -Dm755 bash_completion.d/unp "$pkgdir"/etc/bash_completion.d/unp.sh + + cd po + make DESTDIR="$pkgdir" install +} diff --git a/libre/unp/libre.patch b/libre/unp/libre.patch new file mode 100644 index 000000000..e459ce209 --- /dev/null +++ b/libre/unp/libre.patch @@ -0,0 +1,60 @@ +diff -Nur unp-2.0~pre7+nmu1.orig/unp unp-2.0~pre7+nmu1/unp +--- unp-2.0~pre7+nmu1.orig/unp 2011-03-23 17:07:18.000000000 -0300 ++++ unp-2.0~pre7+nmu1/unp 2015-05-19 04:13:37.929971649 -0300 +@@ -214,11 +214,6 @@ + [ 'archmage'] + ], + +- [ gettext("rar or unrar or unrar-free"), "rar", "RAR.*archive", 0, +- [ "rar", "x" ], +- [ "unrar", "x" ] +- ] +- , + [ "binutils", "ar|deb", "(Debian binary package|\ ar.*archive)", 0, + [ "ar", "-x", "-v" ] + ] +@@ -231,11 +226,6 @@ + [ "lha", "x" ] + ] + , +- [ "arj", "arj", "ARJ.*archive", 0, +- [ "arj", "x" ], +- [ "unarj", "x" ], +- ] +- , + [ "ppmd", "pmd", "PPmd.*archive", 0, + [ "PPMd", "x" ] + ] +@@ -264,18 +254,10 @@ + [ "cabextract" ] + ] + , +- [ "unace", "ace", "ACE.*archive", 0, +- [ "unace", "e" ] +- ] +- , + [ "xdms", "dms", "DMS.*archive", 0, + [ "xdms", "x" ] + ] + , +- [ "unlzx", "lzx", "LZX.*archive", 0, +- [ "unace", "e" ] +- ] +- , + [ "macutils", "sea|sea\.bin", "SEA.*archive", 0, + [ "macutils", "-v" ] + ] +@@ -284,12 +266,9 @@ + [ "hexbin", "-v" ] + ] + , +- [ "maybe orange or unzip or unrar or unarj or lha ", "exe", "executable", 3, ++ [ "maybe orange or unzip or lha ", "exe", "executable", 3, + [ "orange" ], + [ "unzip" ], +- [ "unrar", "x" ], +- [ "rar", "x" ], +- [ "arj", "x" ], + [ "lha", "x" ] + ] + -- cgit v1.2.3 From df4e30709269c5117e7d5cdfe61098eab40b1fbb Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 19 May 2015 22:40:35 -0300 Subject: vim-7.4.729-1.parabola1: updating version --- libre/vim/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libre') diff --git a/libre/vim/PKGBUILD b/libre/vim/PKGBUILD index ec7deac59..58a845b48 100644 --- a/libre/vim/PKGBUILD +++ b/libre/vim/PKGBUILD @@ -9,7 +9,7 @@ pkgbase=vim pkgname=('vim-minimal' 'vim' 'vim-python3' 'gvim' 'gvim-python3' 'vim-runtime') # list of tags can be found at https://code.google.com/p/vim/source/list _topver=7.4 -_patchlevel=723 +_patchlevel=729 _tag=v${_topver/./-}-${_patchlevel} _versiondir="vim${_topver//./}" pkgver=${_topver}.${_patchlevel} -- cgit v1.2.3 From ceaa47051de0cd353ce7524bd0e9f76e249b4b53 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 20 May 2015 04:04:55 -0300 Subject: iceweasel-1:38.0.1.deb1-1: updating version --- libre/iceweasel/PKGBUILD | 13 +++++-------- libre/iceweasel/libre.patch | 40 +++++++++++++++++++++------------------- libre/iceweasel/mozconfig | 1 + 3 files changed, 27 insertions(+), 27 deletions(-) (limited to 'libre') diff --git a/libre/iceweasel/PKGBUILD b/libre/iceweasel/PKGBUILD index 073ac707e..8afcd744b 100644 --- a/libre/iceweasel/PKGBUILD +++ b/libre/iceweasel/PKGBUILD @@ -16,7 +16,7 @@ _pgo=true # We're getting this from Debian Experimental _debname=iceweasel -_debver=37.0.2 +_debver=38.0.1 _debrel=deb1 _debrepo=http://ftp.debian.org/debian/pool/main/ debfile() { echo $@|sed -r 's@(.).*@\1/&/&@'; } @@ -52,10 +52,10 @@ source=("$_debrepo/`debfile $_debname`_$_debver.orig.tar.bz2" $pkgname-install-dir.patch vendor.js $pkgname-fixed-loading-icon.png) -sha256sums=('a9af34b1e1a0851c9e65d2908104b4baab8162080b345c568ecc519c375d5728' - '6ec89b187f2a7ed3a092f0f727b6f0e729c3d36d0d0511080253b2c4222949f9' - '831720c1efd6e67d54e70cf4e2b02f9554aa6c914315be6dd2ca837adbbdcabd' - 'fcb11b3e6bef5afb2f41b631c98d05d10f30bae3afda28ad8d29b98db5187909' +sha256sums=('a0011a4e9078cc2e50a48f76fef3506360d3ab32507b0eef47404dc6d3bd022c' + '490daa2deafd0db5a1193b236cf9f595e7330f2edf61b19950d3e52cf0ad6481' + 'aa354e7d4ebe6bc7618dd4bee86c17a55911df27684a7e47b2f4189bb1fc5832' + '659d7740dd7ace5cc4b806a414245e52322492f0b19b45084b2957839c677255' '93e3001ce152e1d142619e215a9ef07dd429943b99d21726c25da9ceb31e31cd' '2257dc69886bd0b72c48675a27c3a88b9cf6b598252c9e9f1c99763180684fc3' '3aea6676f1e53a09673b6ae219d281fc28054beb6002b09973611c02f827651d' @@ -140,9 +140,6 @@ prepare() { # WebRTC build tries to execute "python" and expects Python 2 ln -s /usr/bin/python2 "$srcdir/path/python" - # Use gold, as Mozilla can use some of its features, such as safe ICF - #ln -s /usr/bin/ld.gold "$srcdir/path/ld" - # configure script misdetects the preprocessor without an optimization level # https://bugs.archlinux.org/task/34644 sed -i '/ac_cpp=/s/$CPPFLAGS/& -O2/' configure diff --git a/libre/iceweasel/libre.patch b/libre/iceweasel/libre.patch index 5e1f7dad4..dea9cc18e 100644 --- a/libre/iceweasel/libre.patch +++ b/libre/iceweasel/libre.patch @@ -158,8 +158,8 @@ diff -Nur mozilla-release.orig/browser/base/content/abouthome/aboutHome.css mozi } diff -Nur mozilla-release.orig/browser/base/content/abouthome/aboutHome.js mozilla-release/browser/base/content/abouthome/aboutHome.js ---- mozilla-release.orig/browser/base/content/abouthome/aboutHome.js 2015-03-26 23:20:16.000000000 -0300 -+++ mozilla-release/browser/base/content/abouthome/aboutHome.js 2015-04-01 18:31:13.921464580 -0300 +--- mozilla-release.orig/browser/base/content/abouthome/aboutHome.js 2015-05-08 13:55:12.000000000 -0300 ++++ mozilla-release/browser/base/content/abouthome/aboutHome.js 2015-05-15 06:52:57.450189850 -0300 @@ -5,155 +5,44 @@ "use strict"; @@ -478,7 +478,7 @@ diff -Nur mozilla-release.orig/browser/base/content/abouthome/aboutHome.js mozil function onSearchSubmit(aEvent) { let searchText = document.getElementById("searchText"); -@@ -380,144 +156,6 @@ +@@ -381,144 +157,6 @@ document.dispatchEvent(event); } @@ -737,8 +737,8 @@ diff -Nur mozilla-release.orig/browser/locales/en-US/chrome/browser/devtools/too @@ -748,7 +748,7 @@ diff -Nur mozilla-release.orig/browser/locales/en-US/chrome/browser/devtools/web -@@ -56,7 +56,7 @@ +@@ -58,7 +58,7 @@ @@ -835,8 +835,8 @@ diff -Nur mozilla-release.orig/browser/locales/en-US/chrome/browser-region/regio +gecko.handlerService.schemes.ircs.0.name=Freenode Web IRC +gecko.handlerService.schemes.ircs.0.uriTemplate=https://webchat.freenode.net diff -Nur mozilla-release.orig/browser/locales/generic/profile/bookmarks.html.in mozilla-release/browser/locales/generic/profile/bookmarks.html.in ---- mozilla-release.orig/browser/locales/generic/profile/bookmarks.html.in 2015-01-09 02:38:16.000000000 -0200 -+++ mozilla-release/browser/locales/generic/profile/bookmarks.html.in 2015-01-16 15:03:01.408257268 -0200 +--- mozilla-release.orig/browser/locales/generic/profile/bookmarks.html.in 2015-05-08 13:55:16.000000000 -0300 ++++ mozilla-release/browser/locales/generic/profile/bookmarks.html.in 2015-05-15 07:20:33.941389259 -0300 @@ -15,13 +15,20 @@

@bookmarks_toolbarfolder@

@bookmarks_toolbarfolder_description@ @@ -847,10 +847,10 @@ diff -Nur mozilla-release.orig/browser/locales/generic/profile/bookmarks.html.in -

@firefox_heading@

+

Parabola GNU/Linux-libre

--

@firefox_help@ --
@firefox_customize@ --
@firefox_community@ --
@firefox_about@ +-
@firefox_help@ +-
@firefox_customize@ +-
@firefox_community@ +-
@firefox_about@ +
Parabola GNU/Linux-libre +
Parabola GNU/Linux-libre Packages +
Parabola GNU/Linux-libre Wiki @@ -858,10 +858,10 @@ diff -Nur mozilla-release.orig/browser/locales/generic/profile/bookmarks.html.in +

+

Free Software Foundation

+

-+

Free Software Foundation -+
LibrePlanet -+
Free addons -+
h-node ++
Free Software Foundation ++
The GNU Operating System and the Free Software Movement ++
LibrePlanet ++
h-node

diff -Nur mozilla-release.orig/browser/modules/AboutHome.jsm mozilla-release/browser/modules/AboutHome.jsm @@ -876,7 +876,7 @@ diff -Nur mozilla-release.orig/browser/modules/AboutHome.jsm mozilla-release/bro Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -@@ -20,66 +20,6 @@ +@@ -20,68 +20,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); @@ -887,7 +887,9 @@ diff -Nur mozilla-release.orig/browser/modules/AboutHome.jsm mozilla-release/bro -const STARTPAGE_VERSION = 4; - -this.AboutHomeUtils = { -- get snippetsVersion() STARTPAGE_VERSION, +- get snippetsVersion() { +- return STARTPAGE_VERSION; +- }, - - /* - * showKnowYourRights - Determines if the user should be shown the @@ -943,7 +945,7 @@ diff -Nur mozilla-release.orig/browser/modules/AboutHome.jsm mozilla-release/bro /** * This code provides services to the about:home page. Whenever * about:home needs to do something chrome-privileged, it sends a -@@ -242,18 +182,9 @@ +@@ -246,18 +184,9 @@ }).then(function(engineName) { let data = { showRestoreLastSession: ss.canRestoreLastSession, diff --git a/libre/iceweasel/mozconfig b/libre/iceweasel/mozconfig index ab1196522..4b6e783a9 100644 --- a/libre/iceweasel/mozconfig +++ b/libre/iceweasel/mozconfig @@ -35,6 +35,7 @@ ac_add_options --disable-debug-symbols # Parabola features ac_add_options --disable-safe-browsing +ac_add_options --disable-eme # Other mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/moz-objdir -- cgit v1.2.3 From ff62d44c80cec14342cc92919eba80ec53c2a760 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 20 May 2015 12:03:59 -0300 Subject: iceweasel-l10n-1:38.0.1.deb1-1: updating version --- libre/iceweasel-l10n/PKGBUILD | 178 +++++++++++++++++++++--------------------- 1 file changed, 89 insertions(+), 89 deletions(-) (limited to 'libre') diff --git a/libre/iceweasel-l10n/PKGBUILD b/libre/iceweasel-l10n/PKGBUILD index 92aaca15b..d1cf77654 100644 --- a/libre/iceweasel-l10n/PKGBUILD +++ b/libre/iceweasel-l10n/PKGBUILD @@ -4,7 +4,7 @@ # Contributor: fauno # Contributor: Figue -_debver=37.0.2 +_debver=38.0.1 _debrel=deb1 epoch=1 _pkgbase=iceweasel @@ -160,91 +160,91 @@ _package() { } sha256sums=('6ab481740fdd48790329217a1bbe1fc7d2438bbdc1f767e21ba3d66084f4afcf' - '46df91da1b1f3df067419a53f443f7f42bcd818dbd8f657c504870e9db663802' - '2590b8aa4a585a65804cc4807665e76ea017afd3d0b339d95936a7bc4a12a8bc' - '6394f641e50af7be6ec2e06cfae325e984f9733abb64d14e93053822a4806024' - 'f24db9ae64128546972b08461ed82c8e40e8ca80ec5bdc7fd48f248514b208e5' - 'c93596f85d5557b533d9fbf4a3785643885551609b79a3240bd38522b4ec4f35' - 'fc88e4f63b2ae3cae96c2c272c2c5fda4a6a29461eb37e5394fb4cc92827a21d' - '7888e43366080da53a429cc386e100fdaf88f50c13d0ee43a8abbef6c5a1cb21' - 'f2ed4b3a7ccfa994bf4715c43f235185d6a7812a34ca34a4be9a4a8c9de2cc87' - '26fec282a3c1466b918a1a443990d7c06160be5a9f29b5cca95442c40c7bdeea' - 'd0fdd728ba4115f44d894175f8fda6c0045a41d2013f83d4ec016eb3ba736d26' - 'e7628c1eda64f5b3ea1f1710472333c40290d0c9e3d21f1ec54b1a47059d926d' - '2314ab923d5ede048f2eb3b2e93a84f1acb895b40fb7491c37d9bc8a08b7b2bf' - 'cec666e55649cf193b887499bae2508702e9561d1983f66bab243a350b2413be' - '12a2905ff151bd5f210a2f2c3efa9815beb5db2c9ee3d11416845253a9167f1f' - 'a92af5e7a48f7d34fb8c68adbf1c9592637c7598cde4d6e6145b9a66b04f5578' - '4f2f68c37120863e23dc286ebacc13a49c03ed3d6d94cf2d82eef7829bc289b9' - 'c28437d8b449f8ba303e230b8eff098a562dd63e48bf17487327bb841fb88792' - 'c3aa43888b1ded108b787f313cf837915579f84aa7e3b00c48a9157241259716' - '96165ece3c25386a74acf16825404cd0cbb98396df5a51b2791d5cf2e1821614' - 'd23e4144f323fdd9629dbab91ae5b6eff1eb8b95358cea53c4cf43185533938b' - '72214132772ba4d12fb27fbe024ce9620595b596d234727e74bc543c2abfdd9c' - '20efde5f2a53aac94b082618d173b71731cdc5320bf5dac1d8e840851530a7e2' - '71c2601875e8354e5ba51c59d63988ff6cac178e5ab13ebc7426520461a22d29' - '30f1625e802a0dc9be7213483b258660b7cbae05ac50a7d323763d056e5e9fc2' - '3a7d65c752b009504800bd22d8cfab699681526e9fec24e67db6da31f5ff536d' - 'f2cd4d92f2b6088771108de25228b0ce5ea255e9ee35bbbf950a09c9ff95553b' - 'b0719b04dc9592f5efcaf7a8ca022f3291a45e898b9d881ce68e1e22e00c3efe' - '82944255040c681b71f31ffc686f706711d00d18f01b75a73d1b78f306e444be' - '6894b549aa3775c6d06d43232fcf461cb644db47e1c2b8639f49e19e602b6e4b' - '039dc23e10288be2f24e59438e8ae1aed82782018820f2062da171b83cf46b0e' - '1dae292f8366aa065c405a07707bfa03ed2bb359c5f1ee3a4da7bc4641b2eded' - 'c6addc7af1a16310bd164963f1b346136dd828a5da2918b65ca9f42653712e44' - 'acf5b304315b78b7d64c43816774202a2b657735e52891baba57801e4ce51d19' - 'aee124897df46eefd2f34020f8356e478dd808b2c2454115a2fe89672982f6e9' - '202b66f9ba36e5aa21a53fbcdbda41daf7cc5b811dd21588895e8246472e99f4' - 'baaec2219b2fcc7b22f771ed2db825488d3a8220712f257cab3fa0546fb088a3' - '8f8c97cacf7df7b0bbfa145d643e684dd5ce33baa4ae451e4b7b778e748ea83a' - '7fca605daf0525a43d9ec5de9bc931ba4d758177e9c2bac249230270739be2ca' - '8c742add184120ccf6fa5298a1ffd503af07a9522a2c0fa9041a9ecf7486c042' - '221b0deb134ed158b7634d0622f0f1bb3cb42b3f082d306d629041a8e1f8be7a' - '0c636f0975dfb8f476f4f8eb14533de9b380eccecca7cfe7eeffdaaaedd9628c' - '49eea65ca9c6bab4d1b487b21f1393d9fa1a8f41b04380f466509fc51b590e41' - '18563024ef2d44f24d28160a3e64cd55c17e77e146bc78e58bc6bd683582e334' - 'df2f8b7055096ddcd7d4f1664416e8676eaae81fd0c14786a3887a2215d11488' - '220233daf918d1d21f7eb4168183df55545f5701a9ad7c335bc19410d0078592' - '2c358e388d019ab5617b4385204ae8423030fbfe78853d8da0485f9c798e8fd7' - '8ba54a5d6346fc4e2905ce9c492a2c52b43872741f87d0be416628479a5fe1d5' - '6fa794685b60b14d61d066509e87c9178af68bf7f34c08891f071002dc78241d' - '2155e7780d829952f12c590a49927cf008e28de789e5faa3d364a2144f9dbf77' - 'b2db3f40e7cd0f7a24ddeab5edd2902299a8c9e247d98b408c2df1d97c174925' - 'aef01c5c7f9e14fafa4dca6547d670067eb0f7cdf7dd5281bb224d0d21967e1d' - 'fbbc6db0f8d48f1c7bdd4a471c73c9cc82fbcfd7bd0b8d79a9b1a8719b49e4af' - '1f245ca7e43e5f88f86d978891ee4c89e28f2352973afa9befbe35691d164e29' - '0efa33921795ede12c4e01f595e442226f715183b146c899f50def9ad6a9b0bc' - '621df89a873179d47765b2c2fb79fca4f0b4fe9eb3471d9d760a1ba15eddebf1' - 'e0890fe61843a1942e4e95c0c923d2945bb90a4a39171f780a0ddd2fe94e470a' - '6a3d778cdfc1eef899a14177609ba2a930a1559992652e833c294d7f02e36eb5' - 'b10f4108a12becfcd672a2bf136258bbc42d09d6c06a24bedd83d45069ea56ed' - '02c0fbdb20b1cd2c464a49598febfcf9bd419732080b5a4b57311577dacb1c8a' - '2ecd6df50258eae99ab7bf7608df8cd98030902943192f2de7fc981231f9d245' - '6ada08c6af7c26a1882073b5b024f90fda8b8b2582ec38448c3e163dfed581cb' - '4b695792624e41699218e4030f6ceb0a0870cc2938f892ee463475afb29f6692' - '42dd38b838f174af760aff8e8e3567c9d76e113d88de17da1347bcfe3454eb41' - 'da586ee0b3cf471fe549c728b8d206c374cfe9c63e21f835868a92b88aa017ed' - '2593444bd5cc24dbde3b1d3a4c01cfd117be2950c252a0f93f65c5f40959d74c' - '62c04d53d34449f6d3f53ad07ab315ed6d8e377d82bb80d80d923904f2907a23' - '13c3b617012140a685d3d9be8221f08128ca22ef61efc8c1113907555ed6f928' - '9a0304a8736634f69db6ee759fe094f872c007735a2f14223c34622e00741c47' - '1c21185e07a6a557b5ae8510cf30c63c95caa8e60c5322fd4b779bc4fabbdb0c' - '948b257ddda17c8f5f4b7b86f47a1a1bf998b634451cd00639e9353b27cdcd97' - 'cca61891ce1787f750ecb527e62dd7a128c83b01aa6adf617db8fecd44fe8fda' - '62d42387ecbcfe849003cbb66d519be0a05b28a44ca52162fef9dfc166fd8d96' - '6172487c0adce3d9233ab24484168dfd482d91bfc2d73eb26934642b01e7edc8' - '09ddd532bde2ceca72174e92b5853354f3d35bc58934d7d390e3e2f04ebb5a75' - 'bc0fe33659f7f81a584f3f3f2d2f31fc1a716b882c72d88479058fd18288086e' - '091a9e2e1caee9d95a6697a5e9c7618c9c538fbc2a6fa44f0b17ed992c56277b' - '905bdabfabf2fb3ee761be8d3cf8ef6f583f6a0918e283c5e4bffcabedf42708' - '4bbdb5efd6a2b5d0dc8125654bf5ac868cca5666092213d6083e894530d58f95' - 'efdd83dca77c3cc63aefab5ee8d9a28b4436fae1ed2cb1c503fe81423845abf6' - 'a00f9011c6c971c09918766ed072feee05e60668c4622849f234ec2ddcb84c61' - '7d501554b35afab436d400b10691a34f85c6e13ff9b01f7a4ba6f423e6029f5d' - '5eeafacdbd59e29a26899aef707363df83158bdbcc692bf65d826a71b53ee6db' - 'cdf01aa75b3ab9fa6aa880b1a4ea91e3cc086b233a5174674d9895a0e1dbdcc8' - 'a6c373b4bf80bd15fe15faf37c55ae69eb3552d35104c137d1a982bdd12d82b2' - 'e9280e553402a42436b7025253c3a686e1b6cd7d4718ccce743ef9c64b177a10' - 'f8bac7ecec29c7185b2c682cf7b48ead1f3610f9a6fe98f328d846d50bc1c77c' - '77a8555b964fa3baae54b88d8c329854ae2b04ff0825a88750aabbad9801a5c4' - '402338eb236ffc3d963da03cde1bf8e8d20f902042cd4a9bb84906da25335261') + 'fad6315dd1caae75e9fb05ae23baad58b375882eeec3daf32c2cdf37a83b6504' + 'b9abd689e8e6b7082745919a7939870782aa90d48c0e90aa6c1b82f16e85e782' + '476fc24dcd4da851e54220bfa123944fb162543118ede89c1be42a2a71ae61c2' + 'f8ef47446e1819e912211c5a60689f15bdc351d8eefdd2cc10b3f49f67eb17e7' + 'c5f54afd5c22b97acd960e21fa892da3319c5966a6538dd7139bf57e2a9eaa26' + 'dabf1bc4f5f9e6a5bf8274f053291449dbcb6625fbd40f23a6917e2c1556ac7f' + 'e78e5c6b4b3f2cf254a8cde4c09fb60e02b0ea9ec7dab92e44a0fdf1da84e0ae' + '2492c2612d80c9e2a6ba0cd8901fad155b83e37ff5c29bc6a192d5dd1034360c' + '395032e27b55d8dc9ef6d60f0eecc2e82bf7097e96465b3d4f09efa94306c287' + 'c0b9b2ea96fba3bafb0aa5c6d1385c466897000ed1803727d3ed41a5486a01de' + '9d1b1d6e35e09c19c16dfaf8cddc196385a4890778d63c3b3b548adf57e780fe' + '3a764b4ad540ebaaa0a341f68dd365d1352b8e7d6f9f25f2cad94192296a102e' + '02861e0e2e395baa18e315891c48da5e519ce2f4b8f7706ae6845897609e359c' + '8c0c4d94cfd079ba755f1e0381baec3f06b517cf81b92fef933eac91f47a6da5' + '84cf492e816d7d54d9fbd6efa7d2e731a7a7335f913fc438f6e6c011d8b530a4' + 'b6965520beb1e080103ca28d6bcf66d9a892ea5cd204d4c301e03971138f1e67' + '371253c9e7c7e451d39f7a0f4de2c933723e10832e43fdd2cb70931544639258' + '2b3e44d0a232a65b3ec81fd4d872cf125c0d7f4a96bf8e5f1bfb6b666a97e953' + '4159cec4572feeabb8d84ddff4ccc1e11152a9c4a96a86492073eaf6c85cbae6' + '6432745599c7ebc5c4b3cb5b92d0974530c39af13d0388a5ea00fffae6259a99' + '1deb1aeed20e63ee908aa14e3777768c80d2798f78a94779133efeb9fab51319' + 'eabcb35500514a1f788586368225938be825e78f8f45a113ac8ea57858e54f60' + 'ccb56a546181ff63052e0fd1672e3a54233d9a90a34a5579eaaeb8bb8d9bc515' + '4accd730bb991b6321225c994a5307c9093515519339627b2b71ba93ddd54095' + '46a48f053b3e65fc39bf2ec06f693b0f3b5b691c1b3d5205e023561cbccfabb2' + '0008140022d1457fb0390ace4398cd14bb4e4196186545c571081e625e06997e' + '300322e4a72de37fa11a1ef92abe30083efa1df6510420bcbad54b9b144eb6af' + 'a646a99d31d54f2d0aca6b518c1c4d1059adab95493e20256531348dd984c650' + 'a6a4ca57e11c938aebda1c8954e14d23e40eec08d1635f04a22108907e3393ff' + '5764a8012586616b4bbd039c3b0ba463c5509c5ffbbcbd6404a1e0b1fd4cf2c3' + 'ff5bc97dab31f3b8ff8061ca28e5e5ac8b10bf41e878ae5ef8bf3bf3db6f570e' + '8b8c2aff5ea3322c107c2455f7fc8238101e04f131a246088d12570e709531b1' + '5fcab669d2ef961a0f8c9aa8cd45533ff57443e215c698bb4d5a66e08f2ad2ef' + 'f5c7d5032ce766faae306e033fddba9b55bfda01abcc826947eea71f420f2ce9' + 'b7cb4bb9083f468e632f271b438251bdbce93200a085983f74088b73e7fed8c8' + '921058ee68b5939d49a67f1ed282601611e8fafb1b5539fca02a3fb0a34820c7' + '8c5ba2521e4f8961bc2b843294a0bda0769a43ef7108e95025dd256c87e0319f' + '5eb664ebba8f5aae10035918dabb36a0a74c7f0dff44b4e318ded7f06c228b79' + '8417c5f90c5cd265320792d6ee0e39f7d5aad2ab0cfd1fa74f7ff43d5ab3f4c8' + '7847ae29fb0e2523967d39e7f35b5360ec7eb4d9c381ee9dc433ab9ab4ecff19' + '082c067984e823d15699df95af87a19e4402eb744fa32458c3b4d4a76b8fbc6c' + '9b44cb8d6b505cfbb639cad5a6960a4635d6154df3653c6a68ff75e0fc46aa92' + 'ed1836874b38d5ea81a2ab6e43be00205008932bab57204d33ccf6841d473457' + 'cccfd8af1986973c05b08312530a2368863a60416808bfe3c79cb517cecf3bde' + 'f00584939eadf71608d21ebfe1be6d955bed91ea5c92c7c2b62611ffaa8e1faa' + '79a3b41f3b5ad2c77ca3da5076aa3d26c2e02ece91e617f4c9552f8b873c240c' + '2fddb5d2d196a78a10097011b545a75b79dfc39c4a7b0ce86588111d04ae3a60' + '47a83cdb97cded6f53d740786968cc89f44901fc3dad44be44bd041a483955ab' + 'ac782b93a980504afeb1e9647a9c27bc6ea433873acf70d1faf7307a0f826bdd' + '1d1e39d4f4af2ad8bc0a4551a7e4ccd94e58fe1500fed720c67d3fce026c17ac' + '7a95b4f9b0569f61d5e9db865eeb17d77d3a7d1e0d34a2a79386642ffaeecd40' + '715ad1ac863b8c0f785af3615f63cbc233e14bcca4a95281d0fcf317354fb5e8' + '37c872eabf16c325f8e238c1a28deb3e389223756f9b6e7ef7036fb9a6f3b795' + '51e3647a861b854620f2d7834db5f393d87ba9fea8181648a97f7b5a1ca099ea' + '8f1ffa69dd901cd34ddd5e5803b266a2c4de9035a26245809920f43150ca50f8' + '075752bb779b8dd95fde734e08695abea6a7a397061422f2f3dde067fa5769a8' + '11d640b6fc807406e2f48f83cd4aae063404d03ca3472e2f2c1fdd986dd2564e' + '53e5de731266e0dbae9304d0c08103146bfa18a9bf8cb41793b0a9c266b8b68e' + '11829251bcb1284027117b7acfebf5b3254de7aa741b01d5424aa5c261117b87' + 'c1e5ccbb27c8297a2d1e2058a04056b55a2cd30e09337c5a37c3593483445e47' + 'c99c8e6a035d03b2c66aaccedf84ec5c45283d77ecf353fa6df96826a097101b' + '43ee7a7cf0eef6ade8c362d7648e77d65a39933d28e8334c546da2295682c657' + '8b6183bd587b0d7debe0c249bd2f90892e7d3928aaaa77f8d2d74ba550016881' + '7fbd81d54900d39bbd3941f55f971dfba711f229de8a95c46b3d5e259abd8b47' + 'e7f18dd60b15df485a5e1cb7ff0f77de337d492242192411481df6f7c3998d8b' + 'ef2bb8083468723fd30c34975e05e19ed5990b9e4cc084f30a00755b046be730' + 'cde2befb40649ba789abe323b17743e98d59f159397f0a15278894b05da977e6' + '356754c904a158f145c0982c95b072f827df756160c221f2a6d058f12ab7bca7' + '048849ec5ef9b7370253b311fc06e3c393f350bcb2d213a3343fd84b88297f7e' + '092a4688117d825353c145f59304948afefae0c41e7292b2bb0aab71c1954e3e' + '5c3d34afaef1264b13913bb8effa9065218f246777d3c65e5f163301ce05fb9a' + '509681ca7287445a555a12b20b861945473d91b3a8f4620378366aea34c996a5' + '8fd03ff8d698723cbf5de90efeff30e421997133c103dd04f2efe0d4922ac707' + 'cf27afe1ec0dfa56952829fa1cccfbfaafbd3ad266f9184342d4a69e0182d0b7' + 'c4aa602c53d14c88f3dd29409771c4ce5789dde7c9a372ca86056aeffed0dcd1' + '6a9003bcbe6a4a6d4b1e79b43b1de31e6158d0938a010aaf919880ee9fccf5a6' + '6c41d02ae765d9faf5c46f1ea0f006e68b99b2fa2def8434c0c07df973505860' + 'ddb0b69cabbb5cf05652a3eaf717d02f9044c42e1ca7f8579f504adf2e8771ee' + 'ce3ecc80f22979f68e9e322141bdf63f146655d2732dea95e7ed8b600c936a88' + '465c55d25945ec29f2b699b0a7868473b79bbbad4a4ee37c8e3503fd0a8d2e10' + 'c2ff6b33985422c90594e70f7929d48c5455ac679a6f607770726cab836c8211' + 'a146ba43195b37ac045f432268d874ebf70ac7045e9d596a3a06fa31e56ae21b' + '574bea26c62bae18a904df48d454da2eab06a41d004ed982956b63af78adaf67' + 'c05f2515d7fdd7c3e47f57e8b98554266116a49d58efeb933d6641d44fe21613' + 'ea29f07460c4ce0a6112a083d8c0df877b868eb5ef9558b4aa74b67dcd3f23bb' + 'b1be098710db8d1d6fffca2a1a34b8a0193abd98641ebd70bb60f70a493351c5' + '7958a4277974e4c2ded813ba6423575a1aa390a663ff99ea154909c80296431c' + 'e3f921f80afe8ecc14e2dcb5adb692be2c4e1964ce17b431d3ed6d2fcc577455') -- cgit v1.2.3 From 09a6345a5404a66c4fa25401a18dac1c23e65bbc Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 20 May 2015 23:01:15 -0300 Subject: linux-libre-4.0.4_gnu-1: updating version --- .../4.0-rc7-37af2c8aae-loongson-community.patch | 12167 ------------------ .../4.0.2-ae91f13af5-loongson-community.patch | 12168 +++++++++++++++++++ libre/linux-libre/PKGBUILD | 16 +- libre/linux-libre/config.i686 | 122 +- libre/linux-libre/config.mips64el | 99 +- libre/linux-libre/config.x86_64 | 120 +- 6 files changed, 12496 insertions(+), 12196 deletions(-) delete mode 100644 libre/linux-libre/4.0-rc7-37af2c8aae-loongson-community.patch create mode 100644 libre/linux-libre/4.0.2-ae91f13af5-loongson-community.patch (limited to 'libre') diff --git a/libre/linux-libre/4.0-rc7-37af2c8aae-loongson-community.patch b/libre/linux-libre/4.0-rc7-37af2c8aae-loongson-community.patch deleted file mode 100644 index 36edc2945..000000000 --- a/libre/linux-libre/4.0-rc7-37af2c8aae-loongson-community.patch +++ /dev/null @@ -1,12167 +0,0 @@ -diff --git a/Makefile b/Makefile -index 54430f9..09d9a42 100644 ---- a/Makefile -+++ b/Makefile -@@ -297,8 +297,8 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ - - HOSTCC = gcc - HOSTCXX = g++ --HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 --HOSTCXXFLAGS = -O2 -+HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O3 -fomit-frame-pointer -std=gnu89 -+HOSTCXXFLAGS = -O3 - - ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1) - HOSTCFLAGS += -Wno-unused-value -Wno-unused-parameter \ -@@ -616,7 +616,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) - ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE - KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) - else --KBUILD_CFLAGS += -O2 -+KBUILD_CFLAGS += -O3 - endif - - # Tell gcc to never replace conditional load with a non-conditional one -diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig -index c7a1690..0f854f0 100644 ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -333,7 +333,7 @@ config LASAT - - config MACH_LOONGSON - bool "Loongson family of machines" -- select SYS_SUPPORTS_ZBOOT -+ select SYS_SUPPORTS_ZBOOT_UART16550 - help - This enables the support of Loongson family of machines. - -@@ -1640,6 +1640,15 @@ config CPU_LOONGSON2 - bool - select CPU_SUPPORTS_32BIT_KERNEL - select CPU_SUPPORTS_64BIT_KERNEL -+ select CPU_SUPPORTS_HIGHMEM if ! EMBEDDED -+ select ARCH_WANT_OPTIONAL_GPIOLIB -+ -+config CPU_LOONGSON1 -+ bool -+ select CPU_MIPS32 -+ select CPU_MIPSR2 -+ select CPU_HAS_PREFETCH -+ select CPU_SUPPORTS_32BIT_KERNEL - select CPU_SUPPORTS_HIGHMEM - select CPU_SUPPORTS_HUGEPAGES - -@@ -2313,7 +2322,7 @@ config CPU_SUPPORTS_MSA - - config ARCH_FLATMEM_ENABLE - def_bool y -- depends on !NUMA && !CPU_LOONGSON2 -+ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION) - - config ARCH_DISCONTIGMEM_ENABLE - bool -diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile -index 61af6b6..8598044 100644 ---- a/arch/mips/boot/compressed/Makefile -+++ b/arch/mips/boot/compressed/Makefile -@@ -30,9 +30,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ - targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o - - # decompressor objects (linked with vmlinuz) --vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o -+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o - - ifdef CONFIG_DEBUG_ZBOOT -+vmlinuzobjs-y += $(obj)/dbg.o - vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o - vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o - endif -@@ -79,9 +80,18 @@ quiet_cmd_zld = LD $@ - cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ - quiet_cmd_strip = STRIP $@ - cmd_strip = $(STRIP) -s $@ -+ifdef CONFIG_EMBEDDED -+quiet_cmd_sstrip = SSTRIP $@ -+ cmd_sstrip = $(srctree)/scripts/sstrip.sh $@ -+endif - vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr - $(call cmd,zld) - $(call cmd,strip) -+ $(call cmd,sstrip) -+ -+vmlinuz.unsstrip: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr -+ $(call cmd,zld) -+ $(call cmd,strip) - - # - # Some DECstations need all possible sections of an ECOFF executable -@@ -94,14 +104,14 @@ endif - hostprogs-y += ../elf2ecoff - - ifdef CONFIG_32BIT -- VMLINUZ = vmlinuz -+ VMLINUZ = vmlinuz.unsstrip - else - VMLINUZ = vmlinuz.32 - endif - - quiet_cmd_32 = OBJCOPY $@ - cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ --vmlinuz.32: vmlinuz -+vmlinuz.32: vmlinuz.unsstrip - $(call cmd,32) - - quiet_cmd_ecoff = ECOFF $@ -@@ -110,11 +120,11 @@ vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ) - $(call cmd,ecoff) - - OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary --vmlinuz.bin: vmlinuz -+vmlinuz.bin: vmlinuz.unsstrip - $(call cmd,objcopy) - - OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec --vmlinuz.srec: vmlinuz -+vmlinuz.srec: vmlinuz.unsstrip - $(call cmd,objcopy) - --clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} -+clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec,unsstrip} -diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c -index 31903cf..14da73c 100644 ---- a/arch/mips/boot/compressed/decompress.c -+++ b/arch/mips/boot/compressed/decompress.c -@@ -28,8 +28,13 @@ unsigned long free_mem_end_ptr; - extern unsigned char __image_begin, __image_end; - - /* debug interfaces */ -+#ifdef CONFIG_DEBUG_ZBOOT - extern void puts(const char *s); - extern void puthex(unsigned long long val); -+#else -+#define puts(s) -+#define puthex(val) -+#endif - - void error(char *x) - { -diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script -index 5a33409..de04ac9 100644 ---- a/arch/mips/boot/compressed/ld.script -+++ b/arch/mips/boot/compressed/ld.script -@@ -49,5 +49,6 @@ SECTIONS - *(.reginfo) - *(.comment) - *(.note) -+ *(.gnu.attributes) - } - } -diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -index a0ee0cb..4e18add 100644 ---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo); - /* GPIO : I/O SPACE; REG : 32BITS */ - #define GPIOL_OUT_VAL 0x00 - #define GPIOL_OUT_EN 0x04 -+#define GPIOL_OUT_AUX1_SEL 0x10 -+/* SMB : I/O SPACE, REG : 8BITS WIDTH */ -+#define SMB_SDA 0x00 -+#define SMB_STS 0x01 -+#define SMB_STS_SLVSTP (1 << 7) -+#define SMB_STS_SDAST (1 << 6) -+#define SMB_STS_BER (1 << 5) -+#define SMB_STS_NEGACK (1 << 4) -+#define SMB_STS_STASTR (1 << 3) -+#define SMB_STS_NMATCH (1 << 2) -+#define SMB_STS_MASTER (1 << 1) -+#define SMB_STS_XMIT (1 << 0) -+#define SMB_CTRL_STS 0x02 -+#define SMB_CSTS_TGSTL (1 << 5) -+#define SMB_CSTS_TSDA (1 << 4) -+#define SMB_CSTS_GCMTCH (1 << 3) -+#define SMB_CSTS_MATCH (1 << 2) -+#define SMB_CSTS_BB (1 << 1) -+#define SMB_CSTS_BUSY (1 << 0) -+#define SMB_CTRL1 0x03 -+#define SMB_CTRL1_STASTRE (1 << 7) -+#define SMB_CTRL1_NMINTE (1 << 6) -+#define SMB_CTRL1_GCMEN (1 << 5) -+#define SMB_CTRL1_ACK (1 << 4) -+#define SMB_CTRL1_RSVD (1 << 3) -+#define SMB_CTRL1_INTEN (1 << 2) -+#define SMB_CTRL1_STOP (1 << 1) -+#define SMB_CTRL1_START (1 << 0) -+#define SMB_ADDR 0x04 -+#define SMB_ADDR_SAEN (1 << 7) -+#define SMB_CONTROLLER_ADDR (0xef << 0) -+#define SMB_CTRL2 0x05 -+#define SMB_FREQ (0x20 << 1) -+#define SMB_ENABLE (0x01 << 0) -+#define SMB_CTRL3 0x06 - - #endif /* _CS5536_H */ -diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -index 021d017..50aafca 100644 ---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -@@ -28,8 +28,19 @@ static inline void __maybe_unused enable_mfgpt0_counter(void) - #define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ) - - #define MFGPT_BASE mfgpt_base -+#define MFGPT0_CMP1 (MFGPT_BASE + 0) - #define MFGPT0_CMP2 (MFGPT_BASE + 2) - #define MFGPT0_CNT (MFGPT_BASE + 4) - #define MFGPT0_SETUP (MFGPT_BASE + 6) - -+#define MFGPT1_CMP1 (MFGPT_BASE + 0x08) -+#define MFGPT1_CMP2 (MFGPT_BASE + 0x0A) -+#define MFGPT1_CNT (MFGPT_BASE + 0x0C) -+#define MFGPT1_SETUP (MFGPT_BASE + 0x0E) -+ -+#define MFGPT2_CMP1 (MFGPT_BASE + 0x10) -+#define MFGPT2_CMP2 (MFGPT_BASE + 0x12) -+#define MFGPT2_CNT (MFGPT_BASE + 0x14) -+#define MFGPT2_SETUP (MFGPT_BASE + 0x16) -+ - #endif /*!_CS5536_MFGPT_H */ -diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h -index 5459ac0..14e82d9 100644 ---- a/arch/mips/include/asm/mach-loongson/loongson.h -+++ b/arch/mips/include/asm/mach-loongson/loongson.h -@@ -46,6 +46,12 @@ static inline void prom_init_uart_base(void) - #endif - } - -+/* -+ * Copy kernel command line from arcs_cmdline -+ */ -+#include -+extern char loongson_cmdline[COMMAND_LINE_SIZE]; -+ - /* irq operation functions */ - extern void bonito_irqdispatch(void); - extern void __init bonito_irq_init(void); -diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h -index cb2b602..78fcd38 100644 ---- a/arch/mips/include/asm/mach-loongson/machine.h -+++ b/arch/mips/include/asm/mach-loongson/machine.h -@@ -24,6 +24,12 @@ - - #endif - -+#ifdef CONFIG_DEXXON_GDIUM -+ -+#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10 -+ -+#endif -+ - #ifdef CONFIG_LOONGSON_MACH3X - - #define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC -diff --git a/arch/mips/include/asm/mach-loongson1/clock.h b/arch/mips/include/asm/mach-loongson1/clock.h -new file mode 100644 -index 0000000..dd1afdb ---- /dev/null -+++ b/arch/mips/include/asm/mach-loongson1/clock.h -@@ -0,0 +1,53 @@ -+#ifndef __ASM_MACH_LOONGSON1_CLOCK_H -+#define __ASM_MACH_LOONGSON1_CLOCK_H -+ -+#include -+#include -+#include -+#include -+ -+extern void (*cpu_wait) (void); -+ -+struct clk; -+ -+struct clk_ops { -+ void (*init) (struct clk *clk); -+ void (*enable) (struct clk *clk); -+ void (*disable) (struct clk *clk); -+ void (*recalc) (struct clk *clk); -+ int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id); -+ long (*round_rate) (struct clk *clk, unsigned long rate); -+}; -+ -+struct clk { -+ struct list_head node; -+ const char *name; -+ int id; -+ struct module *owner; -+ -+ struct clk *parent; -+ struct clk_ops *ops; -+ -+ struct kref kref; -+ -+ unsigned long rate; -+ unsigned long flags; -+}; -+ -+#define CLK_ALWAYS_ENABLED (1 << 0) -+#define CLK_RATE_PROPAGATES (1 << 1) -+ -+/* Should be defined by processor-specific code */ -+void arch_init_clk_ops(struct clk_ops **, int type); -+ -+int clk_init(void); -+ -+int __clk_enable(struct clk *); -+void __clk_disable(struct clk *); -+ -+void clk_recalc_rate(struct clk *); -+ -+int clk_register(struct clk *); -+void clk_unregister(struct clk *); -+ -+#endif /* __ASM_MIPS_CLOCK_H */ -diff --git a/arch/mips/include/asm/mach-loongson1/regs-intc.h b/arch/mips/include/asm/mach-loongson1/regs-intc.h -new file mode 100644 -index 0000000..6d5db23 ---- /dev/null -+++ b/arch/mips/include/asm/mach-loongson1/regs-intc.h -@@ -0,0 +1,25 @@ -+/* -+ * Copyright (c) 2011 Zhang, Keguang -+ * -+ * Loongson1 Interrupt register definitions. -+ * -+ * 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. -+ */ -+ -+#ifndef __ASM_MACH_LOONGSON1_REGS_INTC_H -+#define __ASM_MACH_LOONGSON1_REGS_INTC_H -+ -+#define LS1X_INTC_REG(n, x) \ -+ (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4)) -+ -+#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) -+#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) -+#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) -+#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) -+#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) -+#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) -+ -+#endif /* __ASM_MACH_LOONGSON1_REGS_INTC_H */ -diff --git a/arch/mips/include/asm/sparsemem.h b/arch/mips/include/asm/sparsemem.h -index b1071c1..8b8e551 100644 ---- a/arch/mips/include/asm/sparsemem.h -+++ b/arch/mips/include/asm/sparsemem.h -@@ -11,7 +11,11 @@ - #else - # define SECTION_SIZE_BITS 28 - #endif --#define MAX_PHYSMEM_BITS 48 -+#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit c461731836 broke Loongson2. */ -+# define MAX_PHYSMEM_BITS 48 -+#else -+# define MAX_PHYSMEM_BITS 35 -+#endif - - #endif /* CONFIG_SPARSEMEM */ - #endif /* _MIPS_SPARSEMEM_H */ -diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h -index b05bb70..44c9a69 100644 ---- a/arch/mips/include/asm/timex.h -+++ b/arch/mips/include/asm/timex.h -@@ -11,6 +11,10 @@ - - #ifdef __KERNEL__ - -+#ifdef CONFIG_CSRC_R4K -+#define ARCH_HAS_PREPARED_LPJ -+#endif -+ - #include - - #include -diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h -index fc0cf5a..99e6430 100644 ---- a/arch/mips/include/uapi/asm/inst.h -+++ b/arch/mips/include/uapi/asm/inst.h -@@ -65,6 +65,8 @@ enum spec_op { - enum spec2_op { - madd_op, maddu_op, mul_op, spec2_3_unused_op, - msub_op, msubu_op, /* more unused ops */ -+ loongson_madd_op = 0x18, loongson_msub_op, -+ loongson_nmadd_op, loongson_nmsub_op, - clz_op = 0x20, clo_op, - dclz_op = 0x24, dclo_op, - sdbpp_op = 0x3f -@@ -151,7 +153,7 @@ enum cop0_com_func { - */ - enum cop1_fmt { - s_fmt, d_fmt, e_fmt, q_fmt, -- w_fmt, l_fmt -+ w_fmt, l_fmt, ps_fmt - }; - - /* -@@ -180,7 +182,8 @@ enum cop1_sdw_func { - enum cop1x_func { - lwxc1_op = 0x00, ldxc1_op = 0x01, - swxc1_op = 0x08, sdxc1_op = 0x09, -- pfetch_op = 0x0f, madd_s_op = 0x20, -+ pfetch_op = 0x0f, -+ prefx_op = 0x17, madd_s_op = 0x20, - madd_d_op = 0x21, madd_e_op = 0x22, - msub_s_op = 0x28, msub_d_op = 0x29, - msub_e_op = 0x2a, nmadd_s_op = 0x30, -diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S -index d07b210..69996f2 100644 ---- a/arch/mips/kernel/scall64-o32.S -+++ b/arch/mips/kernel/scall64-o32.S -@@ -26,6 +26,18 @@ - - .align 5 - NESTED(handle_sys, PT_SIZE, sp) -+#ifdef CONFIG_MIPS_USER_RDTSC -+ MFC0 k0, CP0_EPC -+ lw k1, 0(k0) -+ sltiu k1, k1, 0x1c -+ bne k1, zero, 1f # Normal syscall code: 0x0c < 0x1c -+ nop -+ mfc0 v0, CP0_COUNT # Get TSC -+ PTR_ADDIU k0, 4 # ret from syscall -+ MTC0 k0, CP0_EPC -+ eret -+1: -+#endif /* CONFIG_MIPS_USER_RDTSC */ - .set noat - SAVE_SOME - TRACE_IRQS_ON_RELOAD -diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c -index 8d01709..9cd25da 100644 ---- a/arch/mips/kernel/time.c -+++ b/arch/mips/kernel/time.c -@@ -119,6 +119,11 @@ static __init int cpu_has_mfc0_count_bug(void) - - void __init time_init(void) - { -+#ifdef CONFIG_HR_SCHED_CLOCK -+ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) -+ write_c0_count(0); -+#endif -+ - plat_time_init(); - - /* -diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile -index 1e9e900..36fcccc 100644 ---- a/arch/mips/lib/Makefile -+++ b/arch/mips/lib/Makefile -@@ -2,10 +2,14 @@ - # Makefile for MIPS-specific library files.. - # - --lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ -+lib-y += bitops.o csum_partial.o memcpy.o memset.o \ - mips-atomic.o strlen_user.o strncpy_user.o \ - strnlen_user.o uncached.o - -+ifndef CONFIG_CSRC_R4K -+lib-y += delay.o -+endif -+ - obj-y += iomap.o - obj-$(CONFIG_PCI) += iomap-pci.o - lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y)) -diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig -index 156de85..0a433e6 100644 ---- a/arch/mips/loongson/Kconfig -+++ b/arch/mips/loongson/Kconfig -@@ -32,12 +32,12 @@ config LEMOTE_FULOONG2E - - config LEMOTE_MACH2F - bool "Lemote Loongson 2F family machines" -- select ARCH_SPARSEMEM_ENABLE -+ select ARCH_SPARSEMEM_ENABLE if HIBERNATION - select BOARD_SCACHE - select BOOT_ELF32 - select CEVT_R4K if ! MIPS_EXTERNAL_TIMER - select CPU_HAS_WB -- select CS5536 -+ select CS5536 if PCI - select CSRC_R4K if ! MIPS_EXTERNAL_TIMER - select DMA_NONCOHERENT - select GENERIC_ISA_DMA_SUPPORT_BROKEN -@@ -45,14 +45,13 @@ config LEMOTE_MACH2F - select HW_HAS_PCI - select I8259 - select IRQ_CPU -- select ISA - select SYS_HAS_CPU_LOONGSON2F - select SYS_HAS_EARLY_PRINTK - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL -- select SYS_SUPPORTS_HIGHMEM -+ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED - select SYS_SUPPORTS_LITTLE_ENDIAN -- select LOONGSON_MC146818 -+ select LOONGSON_MC146818 if RTC_DRV_CMOS - help - Lemote Loongson 2F family machines utilize the 2F revision of - Loongson processor and the AMD CS5536 south bridge. -@@ -60,6 +59,31 @@ config LEMOTE_MACH2F - These family machines include fuloong2f mini PC, yeeloong2f notebook, - LingLoong allinone PC and so forth. - -+config DEXXON_GDIUM -+ bool "Dexxon Gdium Netbook" -+ select ARCH_SPARSEMEM_ENABLE -+ select BOARD_SCACHE -+ select BOOT_ELF32 -+ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER -+ select CPU_HAS_WB -+ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER -+ select DMA_NONCOHERENT -+ select GENERIC_ISA_DMA_SUPPORT_BROKEN -+ select HW_HAS_PCI -+ select I8259 -+ select IRQ_CPU -+ select ISA -+ select SYS_HAS_CPU_LOONGSON2F -+ select SYS_HAS_EARLY_PRINTK -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_64BIT_KERNEL -+ select SYS_SUPPORTS_HIGHMEM -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select ARCH_REQUIRE_GPIOLIB -+ select HAVE_PWM if MFD_SM501 -+ help -+ Dexxon gdium netbook based on Loongson 2F and SM502. -+ - config LOONGSON_MACH3X - bool "Generic Loongson 3 family machines" - select ARCH_SPARSEMEM_ENABLE -@@ -152,6 +176,24 @@ config LOONGSON_MC146818 - bool - default n - -+config GDIUM_PWM_CLOCK -+ tristate "Gdium PWM Timer" -+ default n -+ depends on HAVE_PWM && EXPERIMENTAL && BROKEN -+ select MIPS_EXTERNAL_TIMER -+ help -+ This options enables the experimental sm501-pwm based clock. With it, -+ you may be possible to use the loongson2f cpufreq driver. -+ -+config GDIUM_VERSION -+ int "Configure Gdium Version" -+ depends on DEXXON_GDIUM -+ default "3" -+ help -+ I have no information about how to determine which version your board -+ is, If the default config doesn't work for it, please change it to -+ smaller ones. -+ - config LEFI_FIRMWARE_INTERFACE - bool - -diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile -index 7429994..63214c8 100644 ---- a/arch/mips/loongson/Makefile -+++ b/arch/mips/loongson/Makefile -@@ -17,6 +17,12 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ - obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ - - # -+# Dexxon gdium netbook, based on loongson 2F and SM502 -+# -+ -+obj-$(CONFIG_DEXXON_GDIUM) += gdium/ -+ -+# - # All Loongson-3 family machines - # - -diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform -index 0ac20eb..cd957dd 100644 ---- a/arch/mips/loongson/Platform -+++ b/arch/mips/loongson/Platform -@@ -30,4 +30,5 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/ - cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely - load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 - load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 -+load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000 - load-$(CONFIG_LOONGSON_MACH3X) += 0xffffffff80200000 -diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c -index 72fed00..96d5919 100644 ---- a/arch/mips/loongson/common/cmdline.c -+++ b/arch/mips/loongson/common/cmdline.c -@@ -17,10 +17,15 @@ - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -+#include - #include - - #include - -+/* the kernel command line copied from arcs_cmdline */ -+char loongson_cmdline[COMMAND_LINE_SIZE]; -+EXPORT_SYMBOL(loongson_cmdline); -+ - void __init prom_init_cmdline(void) - { - int prom_argc; -@@ -45,4 +50,31 @@ void __init prom_init_cmdline(void) - } - - prom_init_machtype(); -+ -+ /* append machine specific command line */ -+ switch (mips_machtype) { -+ case MACH_LEMOTE_LL2F: -+ if ((strstr(arcs_cmdline, "video=")) == NULL) -+ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60"); -+ break; -+ case MACH_LEMOTE_FL2F: -+ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL) -+ strcat(arcs_cmdline, " ide_core.ignore_cable=0"); -+ break; -+ case MACH_LEMOTE_ML2F7: -+ /* Mengloong-2F has a 800x480 screen */ -+ if ((strstr(arcs_cmdline, "vga=")) == NULL) -+ strcat(arcs_cmdline, " vga=0x313"); -+ break; -+ case MACH_DEXXON_GDIUM2F10: -+ /* gdium has a 1024x600 screen */ -+ if ((strstr(arcs_cmdline, "video=")) == NULL) -+ strcat(arcs_cmdline, " video=sm501fb:1024x600@60"); -+ break; -+ default: -+ break; -+ } -+ -+ /* copy arcs_cmdline into loongson_cmdline */ -+ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE); - } -diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c -index 045ea3d..1d1db80 100644 ---- a/arch/mips/loongson/common/env.c -+++ b/arch/mips/loongson/common/env.c -@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap; - struct loongson_system_configuration loongson_sysconf; - - u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; -+EXPORT_SYMBOL_GPL(loongson_chipcfg); - u64 loongson_freqctrl[MAX_PACKAGES]; - - unsigned long long smp_group[4]; -diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile -new file mode 100644 -index 0000000..f3f4f51 ---- /dev/null -+++ b/arch/mips/loongson/gdium/Makefile -@@ -0,0 +1,6 @@ -+# Makefile for gdium -+ -+obj-y += irq.o reset.o platform.o -+ -+obj-$(CONFIG_MFD_SM501) += sm501-pwm.o -+obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o -diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c -new file mode 100644 -index 0000000..fdbf42a ---- /dev/null -+++ b/arch/mips/loongson/gdium/gdium-clock.c -@@ -0,0 +1,234 @@ -+/* -+ * Doesn't work really well. When used, the clocksource is producing -+ * bad timings and the clockevent can't be used (don't have one shot feature -+ * thus can't switch on the fly and the pwm is initialised too late to be able -+ * to use it at boot time). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define CLOCK_PWM 1 -+#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */ -+#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ) -+#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */ -+#define CLOCK_PWM_DUTY 50 -+#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4) -+ -+static const char drv_name[] = "gdium-clock"; -+ -+static struct pwm_device *clock_pwm; -+ -+static DEFINE_SPINLOCK(clock_pwm_lock); -+static uint64_t clock_tick; -+ -+static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id) -+{ -+ struct clock_event_device *cd = dev_id; -+ unsigned long flag; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ clock_tick++; -+ /* wait intn2 to finish */ -+ do { -+ LOONGSON_INTENCLR = (1 << 13); -+ } while (LOONGSON_INTISR & (1 << 13)); -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ -+ if (cd && cd->event_handler) -+ cd->event_handler(cd); -+ -+ return IRQ_HANDLED; -+} -+ -+static cycle_t gdium_pwm_clock_read(struct clocksource *cs) -+{ -+ unsigned long flag; -+ uint32_t jifs; -+ uint64_t ticks; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ jifs = jiffies; -+ ticks = clock_tick; -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ /* return (cycle_t)ticks; */ -+ return (cycle_t)(CLOCK_LATCH * jifs); -+} -+ -+static struct clocksource gdium_pwm_clock_clocksource = { -+ .name = "gdium_csrc", -+ .read = gdium_pwm_clock_read, -+ .mask = CLOCKSOURCE_MASK(64), -+ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, -+ .shift = 20, -+}; -+ -+/* Debug fs */ -+static int gdium_pwm_clock_show(struct seq_file *s, void *p) -+{ -+ unsigned long flag; -+ uint64_t ticks; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ ticks = clock_tick; -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ seq_printf(s, "%lld\n", ticks); -+ return 0; -+} -+ -+static int gdium_pwm_clock_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, gdium_pwm_clock_show, inode->i_private); -+} -+ -+static const struct file_operations gdium_pwm_clock_fops = { -+ .open = gdium_pwm_clock_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+static struct dentry *debugfs_file; -+ -+static void gdium_pwm_clock_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *evt) -+{ -+ /* Nothing to do ... */ -+} -+ -+static struct clock_event_device gdium_pwm_clock_cevt = { -+ .name = "gdium_cevt", -+ .features = CLOCK_EVT_FEAT_PERIODIC, -+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ -+ .rating = 299, -+ .irq = CLOCK_PWM_IRQ, -+ .set_mode = gdium_pwm_clock_set_mode, -+}; -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "gdium-pwmclk", -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver gdium_pwm_clock_driver = { -+ .driver = { -+ .name = drv_name, -+ .owner = THIS_MODULE, -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int gdium_pwm_clock_drvinit(void) -+{ -+ int ret; -+ struct clocksource *cs = &gdium_pwm_clock_clocksource; -+ struct clock_event_device *cd = &gdium_pwm_clock_cevt; -+ unsigned int cpu = smp_processor_id(); -+ -+ clock_tick = 0; -+ -+ clock_pwm = pwm_request(CLOCK_PWM, drv_name); -+ if (clock_pwm == NULL) { -+ pr_err("unable to request PWM for Gdium clock\n"); -+ return -EBUSY; -+ } -+ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD); -+ if (ret) { -+ pr_err("unable to configure PWM for Gdium clock\n"); -+ goto err_pwm_request; -+ } -+ ret = pwm_enable(clock_pwm); -+ if (ret) { -+ pr_err("unable to enable PWM for Gdium clock\n"); -+ goto err_pwm_request; -+ } -+ -+ cd->cpumask = cpumask_of(cpu); -+ -+ cd->shift = 22; -+ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift); -+ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd); -+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd); -+ clockevents_register_device(&gdium_pwm_clock_cevt); -+ -+ /* SM501 PWM1 connected to intn2 <->ip4 */ -+ LOONGSON_INTPOL = (1 << 13); -+ LOONGSON_INTEDGE &= ~(1 << 13); -+ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt); -+ if (ret) { -+ pr_err("Can't claim irq\n"); -+ goto err_pwm_disable; -+ } -+ -+ cs->rating = 200; -+ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift); -+ ret = clocksource_register(&gdium_pwm_clock_clocksource); -+ if (ret) { -+ pr_err("Can't register clocksource\n"); -+ goto err_irq; -+ } -+ pr_info("Clocksource registered with shift %d and mult %d\n", -+ cs->shift, cs->mult); -+ -+ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO, -+ NULL, NULL, &gdium_pwm_clock_fops); -+ -+ return 0; -+ -+err_irq: -+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); -+err_pwm_disable: -+ pwm_disable(clock_pwm); -+err_pwm_request: -+ pwm_free(clock_pwm); -+ return ret; -+} -+ -+static void gdium_pwm_clock_drvexit(void) -+{ -+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); -+ pwm_disable(clock_pwm); -+ pwm_free(clock_pwm); -+} -+ -+ -+static int __devinit gdium_pwm_clock_init(void) -+{ -+ int ret = gdium_pwm_clock_drvinit(); -+ -+ if (ret) { -+ pr_err("Fail to register gdium clock driver\n"); -+ return ret; -+ } -+ -+ return platform_driver_register(&gdium_pwm_clock_driver); -+} -+ -+static void __exit gdium_pwm_clock_cleanup(void) -+{ -+ gdium_pwm_clock_drvexit(); -+ platform_driver_unregister(&gdium_pwm_clock_driver); -+} -+ -+module_init(gdium_pwm_clock_init); -+module_exit(gdium_pwm_clock_cleanup); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("Gdium PWM clock driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:gdium-pwmclk"); -diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c -new file mode 100644 -index 0000000..2415d20 ---- /dev/null -+++ b/arch/mips/loongson/gdium/irq.c -@@ -0,0 +1,55 @@ -+/* -+ * Copyright (C) 2007 Lemote Inc. -+ * Author: Fuxin Zhang, zhangfx@lemote.com -+ * -+ * Copyright (c) 2010 yajin -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+ -+#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */ -+#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */ -+#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */ -+ -+void mach_irq_dispatch(unsigned int pending) -+{ -+ if (pending & CAUSEF_IP7) -+ do_IRQ(LOONGSON_TIMER_IRQ); -+ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ -+ do_perfcnt_IRQ(); -+ bonito_irqdispatch(); -+ } else if (pending & CAUSEF_IP3) /* CPU UART */ -+ do_IRQ(LOONGSON_UART_IRQ); -+#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE) -+ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */ -+ do_IRQ(MIPS_CPU_IRQ_BASE + 4); -+#endif -+ else -+ spurious_interrupt(); -+} -+ -+static irqreturn_t ip6_action(int cpl, void *dev_id) -+{ -+ return IRQ_HANDLED; -+} -+ -+struct irqaction ip6_irqaction = { -+ .handler = ip6_action, -+ .name = "cascade", -+ .flags = IRQF_SHARED, -+}; -+ -+void __init mach_init_irq(void) -+{ -+ /* setup north bridge irq (bonito) */ -+ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction); -+} -diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c -new file mode 100644 -index 0000000..ffafba4 ---- /dev/null -+++ b/arch/mips/loongson/gdium/platform.c -@@ -0,0 +1,135 @@ -+/* -+ * Copyright (c) 2009 Philippe Vachon -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define GDIUM_GPIO_BASE 224 -+ -+static struct i2c_board_info __initdata sm502dev_i2c_devices[] = { -+ { -+ I2C_BOARD_INFO("lm75", 0x48), -+ }, -+ { -+ I2C_BOARD_INFO("m41t83", 0x68), -+ }, -+ { -+ I2C_BOARD_INFO("gdium-laptop", 0x40), -+ }, -+}; -+ -+static int sm502dev_backlight_init(struct device *dev) -+{ -+ /* Add gpio request stuff here */ -+ return 0; -+} -+ -+static void sm502dev_backlight_exit(struct device *dev) -+{ -+ /* Add gpio free stuff here */ -+} -+ -+static struct platform_pwm_backlight_data backlight_data = { -+ .pwm_id = 0, -+ .max_brightness = 15, -+ .dft_brightness = 8, -+ .pwm_period_ns = 50000, /* 20 kHz */ -+ .init = sm502dev_backlight_init, -+ .exit = sm502dev_backlight_exit, -+}; -+ -+static struct platform_device backlight = { -+ .name = "pwm-backlight", -+ .dev = { -+ .platform_data = &backlight_data, -+ }, -+ .id = -1, -+}; -+ -+/* -+ * Warning this stunt is very dangerous -+ * as the sm501 gpio have dynamic numbers... -+ */ -+/* bus 0 is the one for the ST7, DS75 etc... */ -+static struct i2c_gpio_platform_data i2c_gpio0_data = { -+#if CONFIG_GDIUM_VERSION > 2 -+ .sda_pin = GDIUM_GPIO_BASE + 13, -+ .scl_pin = GDIUM_GPIO_BASE + 6, -+#else -+ .sda_pin = 192+15, -+ .scl_pin = 192+14, -+#endif -+ .udelay = 5, -+ .timeout = HZ / 10, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+}; -+ -+static struct platform_device i2c_gpio0_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { .platform_data = &i2c_gpio0_data, }, -+}; -+ -+/* bus 1 is for the CRT/VGA external screen */ -+static struct i2c_gpio_platform_data i2c_gpio1_data = { -+ .sda_pin = GDIUM_GPIO_BASE + 10, -+ .scl_pin = GDIUM_GPIO_BASE + 9, -+ .udelay = 5, -+ .timeout = HZ / 10, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+}; -+ -+static struct platform_device i2c_gpio1_device = { -+ .name = "i2c-gpio", -+ .id = 1, -+ .dev = { .platform_data = &i2c_gpio1_data, }, -+}; -+ -+static struct platform_device gdium_clock = { -+ .name = "gdium-pwmclk", -+ .id = -1, -+}; -+ -+static struct platform_device *devices[] __initdata = { -+ &i2c_gpio0_device, -+ &i2c_gpio1_device, -+ &backlight, -+ &gdium_clock, -+}; -+ -+static int __init gdium_platform_devices_setup(void) -+{ -+ int ret; -+ -+ pr_info("Registering gdium platform devices\n"); -+ -+ ret = i2c_register_board_info(0, sm502dev_i2c_devices, -+ ARRAY_SIZE(sm502dev_i2c_devices)); -+ -+ if (ret != 0) { -+ pr_info("Error while registering platform devices: %d\n", ret); -+ return ret; -+ } -+ -+ platform_add_devices(devices, ARRAY_SIZE(devices)); -+ -+ return 0; -+} -+ -+/* -+ * some devices are on the pwm stuff which is behind the mfd which is -+ * behind the pci bus so arch_initcall can't work because too early -+ */ -+late_initcall(gdium_platform_devices_setup); -diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c -new file mode 100644 -index 0000000..8289f95 ---- /dev/null -+++ b/arch/mips/loongson/gdium/reset.c -@@ -0,0 +1,22 @@ -+/* Board-specific reboot/shutdown routines -+ * -+ * Copyright (C) 2010 yajin -+ * -+ * 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. -+ */ -+#include -+ -+void mach_prepare_shutdown(void) -+{ -+ LOONGSON_GPIOIE &= ~(1<<1); -+ LOONGSON_GPIODATA |= (1<<1); -+} -+ -+void mach_prepare_reboot(void) -+{ -+ LOONGSON_GPIOIE &= ~(1<<2); -+ LOONGSON_GPIODATA &= ~(1<<2); -+} -diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c -new file mode 100644 -index 0000000..5af3b23 ---- /dev/null -+++ b/arch/mips/loongson/gdium/sm501-pwm.c -@@ -0,0 +1,465 @@ -+/* -+ * SM501 PWM clock -+ * Copyright (C) 2009-2010 Arnaud Patard -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static const char drv_name[] = "sm501-pwm"; -+ -+#define INPUT_CLOCK 96 /* MHz */ -+#define PWM_COUNT 3 -+ -+#define SM501PWM_HIGH_COUNTER (1<<20) -+#define SM501PWM_LOW_COUNTER (1<<8) -+#define SM501PWM_CLOCK_DIVIDE (1>>4) -+#define SM501PWM_IP (1<<3) -+#define SM501PWM_I (1<<2) -+#define SM501PWM_E (1<<0) -+ -+struct pwm_device { -+ struct list_head node; -+ struct device *dev; -+ void __iomem *regs; -+ int duty_ns; -+ int period_ns; -+ char enabled; -+ void (*handler)(struct pwm_device *pwm); -+ -+ const char *label; -+ unsigned int use_count; -+ unsigned int pwm_id; -+}; -+ -+struct sm501pwm_info { -+ void __iomem *regs; -+ int irq; -+ struct resource *res; -+ struct device *dev; -+ struct dentry *debugfs; -+ -+ struct pwm_device pwm[3]; -+}; -+ -+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -+{ -+ unsigned int high, low, divider; -+ int divider1, divider2; -+ unsigned long long delay; -+ -+ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns) -+ return -EINVAL; -+ -+ /* Get delay -+ * We're loosing some precision but multiplying then dividing -+ * will overflow -+ */ -+ if (period_ns > 1000) { -+ delay = period_ns / 1000; -+ delay *= INPUT_CLOCK; -+ } else { -+ delay = period_ns * 96; -+ delay /= 1000; -+ } -+ -+ /* Get the number of clock low and high */ -+ high = delay * duty_ns / period_ns; -+ low = delay - high; -+ -+ /* Get divider to make 'low' and 'high' fit into 12 bits */ -+ /* No need to say that the divider must be >= 0 */ -+ divider1 = fls(low)-12; -+ divider2 = fls(high)-12; -+ -+ if (divider1 < 0) -+ divider1 = 0; -+ if (divider2 < 0) -+ divider2 = 0; -+ -+ divider = max(divider1, divider2); -+ -+ low >>= divider; -+ high >>= divider; -+ -+ pwm->duty_ns = duty_ns; -+ pwm->period_ns = period_ns; -+ -+ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_config); -+ -+int pwm_enable(struct pwm_device *pwm) -+{ -+ u32 reg; -+ -+ if (!pwm) -+ return -EINVAL; -+ -+ switch (pwm->pwm_id) { -+ case 0: -+ sm501_configure_gpio(pwm->dev->parent, 29, 1); -+ break; -+ case 1: -+ sm501_configure_gpio(pwm->dev->parent, 30, 1); -+ break; -+ case 2: -+ sm501_configure_gpio(pwm->dev->parent, 31, 1); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ reg = readl(pwm->regs); -+ reg |= (SM501PWM_IP | SM501PWM_E); -+ writel(reg, pwm->regs); -+ pwm->enabled = 1; -+ -+ return 0; -+} -+EXPORT_SYMBOL(pwm_enable); -+ -+void pwm_disable(struct pwm_device *pwm) -+{ -+ u32 reg; -+ -+ if (!pwm) -+ return; -+ -+ reg = readl(pwm->regs); -+ reg &= ~(SM501PWM_IP | SM501PWM_E); -+ writel(reg, pwm->regs); -+ -+ switch (pwm->pwm_id) { -+ case 0: -+ sm501_configure_gpio(pwm->dev->parent, 29, 0); -+ break; -+ case 1: -+ sm501_configure_gpio(pwm->dev->parent, 30, 0); -+ break; -+ case 2: -+ sm501_configure_gpio(pwm->dev->parent, 31, 0); -+ break; -+ default: -+ break; -+ } -+ pwm->enabled = 0; -+} -+EXPORT_SYMBOL(pwm_disable); -+ -+static DEFINE_MUTEX(pwm_lock); -+static LIST_HEAD(pwm_list); -+ -+struct pwm_device *pwm_request(int pwm_id, const char *label) -+{ -+ struct pwm_device *pwm; -+ int found = 0; -+ -+ mutex_lock(&pwm_lock); -+ -+ list_for_each_entry(pwm, &pwm_list, node) { -+ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) { -+ pwm->use_count++; -+ pwm->label = label; -+ found = 1; -+ break; -+ } -+ } -+ -+ mutex_unlock(&pwm_lock); -+ -+ return (found) ? pwm : NULL; -+} -+EXPORT_SYMBOL(pwm_request); -+ -+void pwm_free(struct pwm_device *pwm) -+{ -+ mutex_lock(&pwm_lock); -+ -+ if (pwm->use_count) { -+ pwm->use_count--; -+ pwm->label = NULL; -+ } else -+ dev_warn(pwm->dev, "PWM device already freed\n"); -+ -+ mutex_unlock(&pwm_lock); -+} -+EXPORT_SYMBOL(pwm_free); -+ -+int pwm_int_enable(struct pwm_device *pwm) -+{ -+ unsigned long conf; -+ -+ if (!pwm || !pwm->regs || !pwm->handler) -+ return -EINVAL; -+ -+ conf = readl(pwm->regs); -+ conf |= SM501PWM_I; -+ writel(conf, pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_int_enable); -+ -+int pwm_int_disable(struct pwm_device *pwm) -+{ -+ unsigned long conf; -+ -+ if (!pwm || !pwm->regs || !pwm->handler) -+ return -EINVAL; -+ -+ conf = readl(pwm->regs); -+ conf &= ~SM501PWM_I; -+ writel(conf, pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_int_disable); -+ -+int pwm_set_handler(struct pwm_device *pwm, -+ void (*handler)(struct pwm_device *pwm)) -+{ -+ if (!pwm || !handler) -+ return -EINVAL; -+ pwm->handler = handler; -+ return 0; -+} -+EXPORT_SYMBOL(pwm_set_handler); -+ -+static irqreturn_t sm501pwm_irq(int irq, void *dev_id) -+{ -+ unsigned long value; -+ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id; -+ struct pwm_device *pwm; -+ int i; -+ -+ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0); -+ -+ /* Check is the interrupt is for us */ -+ if (value & (1<<22)) { -+ for (i = 0 ; i < PWM_COUNT ; i++) { -+ /* -+ * Find which pwm triggered the interrupt -+ * and ack -+ */ -+ value = readl(info->regs + i*4); -+ if (value & SM501PWM_IP) -+ writel(value | SM501PWM_IP, info->regs + i*4); -+ -+ pwm = &info->pwm[i]; -+ if (pwm->handler) -+ pwm->handler(pwm); -+ } -+ return IRQ_HANDLED; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static void add_pwm(int id, struct sm501pwm_info *info) -+{ -+ struct pwm_device *pwm = &info->pwm[id]; -+ -+ pwm->use_count = 0; -+ pwm->pwm_id = id; -+ pwm->dev = info->dev; -+ pwm->regs = info->regs + id * 4; -+ -+ mutex_lock(&pwm_lock); -+ list_add_tail(&pwm->node, &pwm_list); -+ mutex_unlock(&pwm_lock); -+} -+ -+static void del_pwm(int id, struct sm501pwm_info *info) -+{ -+ struct pwm_device *pwm = &info->pwm[id]; -+ -+ pwm->use_count = 0; -+ pwm->pwm_id = -1; -+ mutex_lock(&pwm_lock); -+ list_del(&pwm->node); -+ mutex_unlock(&pwm_lock); -+} -+ -+/* Debug fs */ -+static int sm501pwm_show(struct seq_file *s, void *p) -+{ -+ struct pwm_device *pwm; -+ -+ mutex_lock(&pwm_lock); -+ list_for_each_entry(pwm, &pwm_list, node) { -+ if (pwm->use_count) { -+ seq_printf(s, "pwm-%d (%12s) %d %d %s\n", -+ pwm->pwm_id, pwm->label, -+ pwm->duty_ns, pwm->period_ns, -+ pwm->enabled ? "on" : "off"); -+ seq_printf(s, " %08x\n", readl(pwm->regs)); -+ } -+ } -+ mutex_unlock(&pwm_lock); -+ -+ return 0; -+} -+ -+static int sm501pwm_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, sm501pwm_show, inode->i_private); -+} -+ -+static const struct file_operations sm501pwm_fops = { -+ .open = sm501pwm_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init sm501pwm_probe(struct platform_device *pdev) -+{ -+ struct sm501pwm_info *info; -+ struct device *dev = &pdev->dev; -+ struct resource *res; -+ int ret = 0; -+ int res_len; -+ int i; -+ -+ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL); -+ if (!info) { -+ dev_err(dev, "Allocation failure\n"); -+ ret = -ENOMEM; -+ goto err; -+ } -+ info->dev = dev; -+ platform_set_drvdata(pdev, info); -+ -+ /* Get irq number */ -+ info->irq = platform_get_irq(pdev, 0); -+ if (!info->irq) { -+ dev_err(dev, "no irq found\n"); -+ ret = -ENODEV; -+ goto err_alloc; -+ } -+ -+ /* Get regs address */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res == NULL) { -+ dev_err(dev, "No memory resource found\n"); -+ ret = -ENODEV; -+ goto err_alloc; -+ } -+ info->res = res; -+ res_len = (res->end - res->start)+1; -+ -+ if (!request_mem_region(res->start, res_len, drv_name)) { -+ dev_err(dev, "Can't request iomem resource\n"); -+ ret = -EBUSY; -+ goto err_alloc; -+ } -+ -+ info->regs = ioremap(res->start, res_len); -+ if (!info->regs) { -+ dev_err(dev, "ioremap failed\n"); -+ ret = -ENOMEM; -+ goto err_mem; -+ } -+ -+ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info); -+ if (ret != 0) { -+ dev_err(dev, "can't get irq\n"); -+ goto err_map; -+ } -+ -+ -+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1); -+ -+ for (i = 0; i < 3; i++) -+ add_pwm(i, info); -+ -+ dev_info(dev, "SM501 PWM Found at %lx irq %d\n", -+ (unsigned long)info->res->start, info->irq); -+ -+ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO, -+ NULL, info, &sm501pwm_fops); -+ -+ -+ return 0; -+ -+err_map: -+ iounmap(info->regs); -+ -+err_mem: -+ release_mem_region(res->start, res_len); -+ -+err_alloc: -+ kfree(info); -+ platform_set_drvdata(pdev, NULL); -+err: -+ return ret; -+} -+ -+static int sm501pwm_remove(struct platform_device *pdev) -+{ -+ struct sm501pwm_info *info = platform_get_drvdata(pdev); -+ int i; -+ -+ if (info->debugfs) -+ debugfs_remove(info->debugfs); -+ -+ for (i = 0; i < 3; i++) { -+ pwm_disable(&info->pwm[i]); -+ del_pwm(i, info); -+ } -+ -+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0); -+ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22); -+ -+ free_irq(info->irq, info); -+ iounmap(info->regs); -+ release_mem_region(info->res->start, -+ (info->res->end - info->res->start)+1); -+ kfree(info); -+ platform_set_drvdata(pdev, NULL); -+ -+ return 0; -+} -+ -+static struct platform_driver sm501pwm_driver = { -+ .probe = sm501pwm_probe, -+ .remove = sm501pwm_remove, -+ .driver = { -+ .name = drv_name, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __devinit sm501pwm_init(void) -+{ -+ return platform_driver_register(&sm501pwm_driver); -+} -+ -+static void __exit sm501pwm_cleanup(void) -+{ -+ platform_driver_unregister(&sm501pwm_driver); -+} -+ -+module_init(sm501pwm_init); -+module_exit(sm501pwm_cleanup); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("SM501 PWM driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:sm501-pwm"); -diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile -index 4f9eaa3..f945bd7a 100644 ---- a/arch/mips/loongson/lemote-2f/Makefile -+++ b/arch/mips/loongson/lemote-2f/Makefile -@@ -2,7 +2,7 @@ - # Makefile for lemote loongson2f family machines - # - --obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o -+obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o platform.o - - # - # Suspend Support -diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c -new file mode 100644 -index 0000000..5316360 ---- /dev/null -+++ b/arch/mips/loongson/lemote-2f/platform.c -@@ -0,0 +1,48 @@ -+/* -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+ -+static struct platform_device yeeloong_pdev = { -+ .name = "yeeloong_laptop", -+ .id = -1, -+}; -+ -+static struct platform_device lynloong_pdev = { -+ .name = "lynloong_pc", -+ .id = -1, -+}; -+ -+static int __init lemote2f_platform_init(void) -+{ -+ struct platform_device *pdev = NULL; -+ -+ switch (mips_machtype) { -+ case MACH_LEMOTE_YL2F89: -+ pdev = &yeeloong_pdev; -+ break; -+ case MACH_LEMOTE_LL2F: -+ pdev = &lynloong_pdev; -+ break; -+ default: -+ break; -+ -+ } -+ -+ if (pdev != NULL) -+ return platform_device_register(pdev); -+ -+ return -ENODEV; -+} -+ -+arch_initcall(lemote2f_platform_init); -diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c -index b30bf65..c0177cb 100644 ---- a/arch/mips/math-emu/cp1emu.c -+++ b/arch/mips/math-emu/cp1emu.c -@@ -7,6 +7,9 @@ - * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. - * -+ * Loongson instruction support -+ * Copyright (C) 2011 Mark H Weaver -+ * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. -@@ -60,6 +63,11 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, - static int fpux_emu(struct pt_regs *, - struct mips_fpu_struct *, mips_instruction, void *__user *); - -+#ifdef CONFIG_MACH_LOONGSON -+static int loongson_spec2_emu(struct pt_regs *, -+ struct mips_fpu_struct *, mips_instruction, void *__user *); -+#endif -+ - /* Control registers */ - - #define FPCREG_RID 0 /* $0 = revision id */ -@@ -842,6 +850,14 @@ do { \ - #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) - #define DPTOREG(dp, x) DITOREG((dp).bits, x) - -+/* Support for Loongson paired single floating-point format */ -+#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \ -+ (si1) = (u32)di; (si2) = (u32)(di >> 32); }) -+#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x) -+ -+#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x) -+#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x) -+ - /* - * Emulate the single floating point instruction pointed at by EPC. - * Two instructions if the instruction is in a branch delay slot. -@@ -1235,6 +1251,16 @@ emul: - xcp->regs[MIPSInst_RD(ir)] = - xcp->regs[MIPSInst_RS(ir)]; - break; -+ -+#ifdef CONFIG_MACH_LOONGSON -+ case spec2_op:{ -+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr); -+ if (sig) -+ return sig; -+ break; -+ } -+#endif -+ - default: - sigill: - return SIGILL; -@@ -1312,6 +1338,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); - DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); - DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); - -+#ifdef CONFIG_MACH_LOONGSON -+static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, -+ mips_instruction ir, void *__user *fault_addr) -+{ -+ int rfmt; /* resulting format */ -+ unsigned rcsr = 0; /* resulting csr */ -+ union { -+ union ieee754dp d; -+ struct { -+ union ieee754sp s; -+ union ieee754sp s2; -+ }; -+ } rv; /* resulting value */ -+ -+ /* XXX maybe add a counter for loongson spec2 fp instructions? */ -+ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */ -+ -+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { -+ case s_fmt:{ -+ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); -+ union ieee754sp fd, fs, ft; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_sp_madd; -+ goto scoptop; -+ case loongson_msub_op: -+ handler = fpemu_sp_msub; -+ goto scoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_sp_nmadd; -+ goto scoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_sp_nmsub; -+ goto scoptop; -+ -+ scoptop: -+ SPFROMREG(fd, MIPSInst_FD(ir)); -+ SPFROMREG(fs, MIPSInst_FS(ir)); -+ SPFROMREG(ft, MIPSInst_FT(ir)); -+ rv.s = (*handler) (fd, fs, ft); -+ -+ copcsr: -+ if (ieee754_cxtest(IEEE754_INEXACT)) -+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; -+ if (ieee754_cxtest(IEEE754_UNDERFLOW)) -+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; -+ if (ieee754_cxtest(IEEE754_OVERFLOW)) -+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; -+ if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) -+ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; -+ -+ break; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ case d_fmt:{ -+ union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); -+ union ieee754dp fd, fs, ft; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_dp_madd; -+ goto dcoptop; -+ case loongson_msub_op: -+ handler = fpemu_dp_msub; -+ goto dcoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_dp_nmadd; -+ goto dcoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_dp_nmsub; -+ goto dcoptop; -+ -+ dcoptop: -+ DPFROMREG(fd, MIPSInst_FD(ir)); -+ DPFROMREG(fs, MIPSInst_FS(ir)); -+ DPFROMREG(ft, MIPSInst_FT(ir)); -+ rv.d = (*handler) (fd, fs, ft); -+ goto copcsr; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ case ps_fmt:{ -+ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fd1, fs1, ft1; -+ union ieee754sp fd2, fs2, ft2; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_sp_madd; -+ goto pscoptop; -+ case loongson_msub_op: -+ handler = fpemu_sp_msub; -+ goto pscoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_sp_nmadd; -+ goto pscoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_sp_nmsub; -+ goto pscoptop; -+ -+ pscoptop: -+ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir)); -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); -+ rv.s = (*handler) (fd1, fs1, ft1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler) (fd2, fs2, ft2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ default: -+ return SIGILL; -+ } -+ -+ /* -+ * Update the fpu CSR register for this operation. -+ * If an exception is required, generate a tidy SIGFPE exception, -+ * without updating the result register. -+ * Note: cause exception bits do not accumulate, they are rewritten -+ * for each op; only the flag/sticky bits accumulate. -+ */ -+ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; -+ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { -+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ -+ return SIGFPE; -+ } -+ -+ /* -+ * Now we can safely write the result back to the register file. -+ */ -+ switch (rfmt) { -+ case d_fmt: -+ DPTOREG(rv.d, MIPSInst_FD(ir)); -+ break; -+ case s_fmt: -+ SPTOREG(rv.s, MIPSInst_FD(ir)); -+ break; -+ case ps_fmt: -+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); -+ break; -+ default: -+ return SIGILL; -+ } -+ -+ return 0; -+} -+#endif -+ - static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - mips_instruction ir, void *__user *fault_addr) - { -@@ -1413,7 +1605,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - break; - - default: -- return SIGILL; -+ goto SIGILL_unless_prefx_op; - } - break; - } -@@ -1483,7 +1675,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - goto copcsr; - - default: -- return SIGILL; -+ goto SIGILL_unless_prefx_op; - } - break; - } -@@ -1496,6 +1688,11 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - break; - - default: -+ SIGILL_unless_prefx_op: -+ if (MIPSInst_FUNC(ir) == prefx_op) { -+ /* ignore prefx operation */ -+ break; -+ } - return SIGILL; - } - -@@ -1517,7 +1714,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - unsigned cond; - union { - union ieee754dp d; -- union ieee754sp s; -+ struct { -+ union ieee754sp s; -+#ifdef CONFIG_MACH_LOONGSON -+ union ieee754sp s2; /* for Loongson paired singles */ -+#endif -+ }; - int w; - s64 l; - } rv; /* resulting value */ -@@ -1614,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - case fmov_op: - /* an easy one */ - SPFROMREG(rv.s, MIPSInst_FS(ir)); -- goto copcsr; -+ break; - - /* binary op on handler */ - scopbop: -@@ -1811,7 +2013,7 @@ copcsr: - case fmov_op: - /* an easy one */ - DPFROMREG(rv.d, MIPSInst_FS(ir)); -- goto copcsr; -+ break; - - /* binary op on handler */ - dcopbop: -@@ -1928,6 +2130,83 @@ dcopuop: - break; - } - -+#ifdef CONFIG_MACH_LOONGSON -+ case ps_fmt:{ /* 6 */ -+ /* Support for Loongson paired single fp instructions */ -+ union { -+ union ieee754sp(*b) (union ieee754sp, union ieee754sp); -+ union ieee754sp(*u) (union ieee754sp); -+ } handler; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ /* binary ops */ -+ case fadd_op: -+ handler.b = ieee754sp_add; -+ goto pscopbop; -+ case fsub_op: -+ handler.b = ieee754sp_sub; -+ goto pscopbop; -+ case fmul_op: -+ handler.b = ieee754sp_mul; -+ goto pscopbop; -+ -+ /* unary ops */ -+ case fabs_op: -+ handler.u = ieee754sp_abs; -+ goto pscopuop; -+ case fneg_op: -+ handler.u = ieee754sp_neg; -+ goto pscopuop; -+ case fmov_op: -+ /* an easy one */ -+ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir)); -+ break; -+ -+ pscopbop: /* paired binary op handler */ -+ { -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fs1, ft1; -+ union ieee754sp fs2, ft2; -+ -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); -+ rv.s = (*handler.b) (fs1, ft1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler.b) (fs2, ft2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ } -+ pscopuop: /* paired unary op handler */ -+ { -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fs1; -+ union ieee754sp fs2; -+ -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ rv.s = (*handler.u) (fs1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler.u) (fs2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ } -+ break; -+ -+ default: -+ if (MIPSInst_FUNC(ir) >= fcmp_op) { -+ /* Loongson fp hardware handles all -+ cases of fp compare insns, so we -+ shouldn't have to */ -+ printk ("Loongson paired-single fp compare" -+ " unimplemented in cp1emu.c\n"); -+ } -+ return SIGILL; -+ } -+ break; -+ } -+#endif -+ - case l_fmt: - - if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) -@@ -1999,6 +2278,11 @@ dcopuop: - - DITOREG(rv.l, MIPSInst_FD(ir)); - break; -+#ifdef CONFIG_MACH_LOONGSON -+ case ps_fmt: -+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); -+ break; -+#endif - default: - return SIGILL; - } -diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile -index 300591c..ed272e2 100644 ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -30,6 +30,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o - obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o - obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o - obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o -+obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o - obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3.o - obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o - obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o -diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c -new file mode 100644 -index 0000000..b296220 ---- /dev/null -+++ b/arch/mips/pci/fixup-gdium.c -@@ -0,0 +1,90 @@ -+/* -+ * Copyright (C) 2010 yajin -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+/* -+ * http://www.pcidatabase.com -+ * GDIUM has different PCI mapping -+ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI -+ * slog 14 (0x126f/0x0501) -> sm501 -+ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers -+ * plus Single EHCI controller -+ * slot 16 (0x10ec/0x8139) -> Realtek 8139c -+ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller -+ */ -+ -+#undef INT_IRQA -+#undef INT_IRQB -+#undef INT_IRQC -+#undef INT_IRQD -+#define INT_IRQA 36 -+#define INT_IRQB 37 -+#define INT_IRQC 38 -+#define INT_IRQD 39 -+ -+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ int irq = 0; -+ -+ switch (slot) { -+ case 13: -+ irq = INT_IRQC + ((pin - 1) & 3); -+ break; -+ case 14: -+ irq = INT_IRQA; -+ break; -+ case 15: -+#if CONFIG_GDIUM_VERSION > 2 -+ irq = INT_IRQB; -+#else -+ irq = INT_IRQA + ((pin - 1) & 3); -+#endif -+ break; -+ case 16: -+ irq = INT_IRQD; -+ break; -+#if CONFIG_GDIUM_VERSION > 2 -+ case 17: -+ irq = INT_IRQC; -+ break; -+#endif -+ default: -+ pr_info(" strange pci slot number %d on gdium.\n", slot); -+ break; -+ } -+ return irq; -+} -+ -+/* Do platform specific device initialization at pci_enable_device() time */ -+int pcibios_plat_dev_init(struct pci_dev *dev) -+{ -+ return 0; -+} -+ -+/* Fixups for the USB host controllers */ -+static void __init gdium_usb_host_fixup(struct pci_dev *dev) -+{ -+ unsigned int val; -+ pci_read_config_dword(dev, 0xe0, &val); -+#if CONFIG_GDIUM_VERSION > 2 -+ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3); -+#else -+ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5); -+ pci_write_config_dword(dev, 0xe4, 1<<5); -+#endif -+} -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, -+ gdium_usb_host_fixup); -+#if CONFIG_GDIUM_VERSION > 2 -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550, -+ gdium_usb_host_fixup); -+#endif -diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S -index 32a7c82..3a89502 100644 ---- a/arch/mips/power/hibernate.S -+++ b/arch/mips/power/hibernate.S -@@ -43,7 +43,9 @@ LEAF(swsusp_arch_resume) - bne t1, t3, 1b - PTR_L t0, PBE_NEXT(t0) - bnez t0, 0b -+#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit 771004298d broke Loongson2. */ - jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */ -+#endif - PTR_LA t0, saved_regs - PTR_L ra, PT_R31(t0) - PTR_L sp, PT_R29(t0) -diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c -index fc897ba..ac60f6b 100644 ---- a/drivers/cpufreq/loongson2_cpufreq.c -+++ b/drivers/cpufreq/loongson2_cpufreq.c -@@ -161,20 +161,32 @@ static int __init cpufreq_init(void) - /* Register platform stuff */ - ret = platform_driver_register(&platform_driver); - if (ret) -- return ret; -+ goto err_return; - - pr_info("cpufreq: Loongson-2F CPU frequency driver.\n"); - -- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, -- CPUFREQ_TRANSITION_NOTIFIER); -+ ret = cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, -+ CPUFREQ_TRANSITION_NOTIFIER); -+ if (ret) -+ goto err_platform_driver_unregister; - - ret = cpufreq_register_driver(&loongson2_cpufreq_driver); -+ if (ret) -+ goto err_cpufreq_unregister_notifier; - -- if (!ret && !nowait) { -+ if (!nowait) { - saved_cpu_wait = cpu_wait; - cpu_wait = loongson2_cpu_wait; - } - -+ return 0; -+ -+ err_cpufreq_unregister_notifier: -+ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block, -+ CPUFREQ_TRANSITION_NOTIFIER); -+ err_platform_driver_unregister: -+ platform_driver_unregister(&platform_driver); -+ err_return: - return ret; - } - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 152b006..767d8de 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -871,6 +871,13 @@ config HID_ZYDACRON - ---help--- - Support for Zydacron remote control. - -+config HID_GDIUM -+ bool "Gdium Fn keys support" if EMBEDDED -+ depends on USB_HID && DEXXON_GDIUM -+ default !EMBEDDED -+ ---help--- -+ Support for Functions keys available on Gdiums. -+ - config HID_SENSOR_HUB - tristate "HID Sensors framework support" - depends on HID && HAS_IOMEM -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 6f19958..2740ff0 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -99,6 +99,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o - wacom-objs := wacom_wac.o wacom_sys.o - obj-$(CONFIG_HID_WACOM) += wacom.o - obj-$(CONFIG_HID_WALTOP) += hid-waltop.o -+obj-$(CONFIG_HID_GDIUM) += hid-gdium.o - obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o - obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o - -diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c -new file mode 100644 -index 0000000..67cc095 ---- /dev/null -+++ b/drivers/hid/hid-gdium.c -@@ -0,0 +1,210 @@ -+/* -+ * hid-gdium -- Gdium laptop function keys -+ * -+ * Arnaud Patard -+ * -+ * Based on hid-apple.c -+ * -+ * 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. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+ -+#include "hid-ids.h" -+ -+#define GDIUM_FN_ON 1 -+ -+static int fnmode = GDIUM_FN_ON; -+module_param(fnmode, int, 0644); -+MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)"); -+ -+struct gdium_data { -+ unsigned int fn_on; -+}; -+ -+ -+struct gdium_key_translation { -+ u16 from; -+ u16 to; -+}; -+ -+static struct gdium_key_translation gdium_fn_keys[] = { -+ { KEY_F1, KEY_CAMERA }, -+ { KEY_F2, KEY_CONNECT }, -+ { KEY_F3, KEY_MUTE }, -+ { KEY_F4, KEY_VOLUMEUP}, -+ { KEY_F5, KEY_VOLUMEDOWN }, -+ { KEY_F6, KEY_SWITCHVIDEOMODE }, -+ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */ -+ { KEY_F8, KEY_BRIGHTNESSUP }, -+ { KEY_F9, KEY_BRIGHTNESSDOWN }, -+ { KEY_F10, KEY_SLEEP }, -+ { KEY_F11, KEY_PROG1 }, -+ { KEY_F12, KEY_PROG2 }, -+ { KEY_UP, KEY_PAGEUP }, -+ { KEY_DOWN, KEY_PAGEDOWN }, -+ { KEY_INSERT, KEY_NUMLOCK }, -+ { KEY_DELETE, KEY_SCROLLLOCK }, -+ { KEY_T, KEY_STOPCD }, -+ { KEY_F, KEY_PREVIOUSSONG }, -+ { KEY_H, KEY_NEXTSONG }, -+ { KEY_G, KEY_PLAYPAUSE }, -+ { } -+}; -+ -+static struct gdium_key_translation *gdium_find_translation( -+ struct gdium_key_translation *table, u16 from) -+{ -+ struct gdium_key_translation *trans; -+ -+ /* Look for the translation */ -+ for (trans = table; trans->from; trans++) -+ if (trans->from == from) -+ return trans; -+ return NULL; -+} -+ -+static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input, -+ struct hid_usage *usage, __s32 value) -+{ -+ struct gdium_data *data = hid_get_drvdata(hid); -+ struct gdium_key_translation *trans; -+ int do_translate; -+ -+ if (usage->type != EV_KEY) -+ return 0; -+ -+ if ((usage->code == KEY_FN)) { -+ data->fn_on = !!value; -+ input_event(input, usage->type, usage->code, value); -+ return 1; -+ } -+ -+ if (fnmode) { -+ trans = gdium_find_translation(gdium_fn_keys, usage->code); -+ if (trans) { -+ do_translate = data->fn_on; -+ if (do_translate) { -+ input_event(input, usage->type, trans->to, value); -+ return 1; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int gdium_input_event(struct hid_device *hdev, struct hid_field *field, -+ struct hid_usage *usage, __s32 value) -+{ -+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type) -+ return 0; -+ -+ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value)) -+ return 1; -+ -+ return 0; -+} -+ -+ -+static void gdium_input_setup(struct input_dev *input) -+{ -+ struct gdium_key_translation *trans; -+ -+ set_bit(KEY_NUMLOCK, input->keybit); -+ -+ /* Enable all needed keys */ -+ for (trans = gdium_fn_keys; trans->from; trans++) -+ set_bit(trans->to, input->keybit); -+} -+ -+static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi, -+ struct hid_field *field, struct hid_usage *usage, -+ unsigned long **bit, int *max) -+{ -+ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) -+ && ((usage->hid & HID_USAGE) == 0x82)) { -+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); -+ gdium_input_setup(hi->input); -+ return 1; -+ } -+ return 0; -+} -+ -+static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id) -+{ -+ struct gdium_data *data; -+ int ret; -+ -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) { -+ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n"); -+ return -ENOMEM; -+ } -+ -+ hid_set_drvdata(hdev, data); -+ -+ ret = hid_parse(hdev); -+ if (ret) { -+ dev_err(&hdev->dev, "parse failed\n"); -+ goto err_free; -+ } -+ -+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); -+ if (ret) { -+ dev_err(&hdev->dev, "hw start failed\n"); -+ goto err_free; -+ } -+ -+ return 0; -+err_free: -+ kfree(data); -+ return ret; -+} -+static void gdium_input_remove(struct hid_device *hdev) -+{ -+ hid_hw_stop(hdev); -+ kfree(hid_get_drvdata(hdev)); -+} -+ -+static const struct hid_device_id gdium_input_devices[] = { -+ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) }, -+ {} -+}; -+MODULE_DEVICE_TABLE(hid, gdium_input_devices); -+ -+static struct hid_driver gdium_input_driver = { -+ .name = "gdium-fnkeys", -+ .id_table = gdium_input_devices, -+ .probe = gdium_input_probe, -+ .remove = gdium_input_remove, -+ .event = gdium_input_event, -+ .input_mapping = gdium_input_mapping, -+}; -+ -+static int gdium_input_init(void) -+{ -+ int ret; -+ -+ ret = hid_register_driver(&gdium_input_driver); -+ if (ret) -+ pr_err("can't register gdium keyboard driver\n"); -+ -+ return ret; -+} -+static void gdium_input_exit(void) -+{ -+ hid_unregister_driver(&gdium_input_driver); -+} -+ -+module_init(gdium_input_init); -+module_exit(gdium_input_exit); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 9c47867..a3e1258 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -1021,6 +1021,9 @@ - #define USB_VENDOR_ID_ZYTRONIC 0x14c8 - #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 - -+#define USB_VENDOR_ID_GDIUM 0x04B4 -+#define USB_DEVICE_ID_GDIUM 0xe001 -+ - #define USB_VENDOR_ID_PRIMAX 0x0461 - #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 - -diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c -index 376f2dc..b576801 100644 ---- a/drivers/ide/ide-iops.c -+++ b/drivers/ide/ide-iops.c -@@ -27,6 +27,10 @@ - #include - #include - -+#ifdef CONFIG_LEMOTE_MACH2F -+#include -+#endif -+ - void SELECT_MASK(ide_drive_t *drive, int mask) - { - const struct ide_port_ops *port_ops = drive->hwif->port_ops; -@@ -300,6 +304,11 @@ void ide_check_nien_quirk_list(ide_drive_t *drive) - { - const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; - -+#ifdef CONFIG_LEMOTE_MACH2F -+ if (mips_machtype != MACH_LEMOTE_YL2F89) -+ return; -+#endif -+ - for (list = nien_quirk_list; *list != NULL; list++) - if (strstr(m, *list) != NULL) { - drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; -diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c -index 91077ef..2cfd9ff 100644 ---- a/drivers/mfd/sm501.c -+++ b/drivers/mfd/sm501.c -@@ -58,7 +58,7 @@ struct sm501_gpio { - struct sm501_gpio { - /* no gpio support, empty definition for sm501_devdata. */ - }; --#endif -+#endif /* CONFIG_MFD_SM501_GPIO */ - - struct sm501_devdata { - spinlock_t reg_lock; -@@ -1124,6 +1124,22 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) - { - return sm->gpio.registered; - } -+ -+void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned -+ char mode) -+{ -+ unsigned long set, reg, offset = gpio; -+ -+ if (offset >= 32) { -+ reg = SM501_GPIO63_32_CONTROL; -+ offset = gpio - 32; -+ } else -+ reg = SM501_GPIO31_0_CONTROL; -+ -+ set = mode ? 1 << offset : 0; -+ -+ sm501_modify_reg(dev, reg, set, 0); -+} - #else - static inline int sm501_register_gpio(struct sm501_devdata *sm) - { -@@ -1143,7 +1159,13 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) - { - return 0; - } --#endif -+ -+void sm501_configure_gpio(struct device *dev, unsigned int gpio, -+ unsigned char mode) -+{ -+} -+#endif /* CONFIG_MFD_SM501_GPIO */ -+EXPORT_SYMBOL_GPL(sm501_configure_gpio); - - static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, - struct sm501_platdata_gpio_i2c *iic) -@@ -1198,6 +1220,20 @@ static int sm501_register_gpio_i2c(struct sm501_devdata *sm, - return 0; - } - -+/* register sm501 PWM device */ -+static int sm501_register_pwm(struct sm501_devdata *sm) -+{ -+ struct platform_device *pdev; -+ -+ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0); -+ if (!pdev) -+ return -ENOMEM; -+ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC); -+ sm501_create_irq(sm, &pdev->resource[1]); -+ -+ return sm501_register_device(sm, pdev); -+} -+ - /* sm501_dbg_regs - * - * Debug attribute to attach to parent device to show core registers -@@ -1356,6 +1392,8 @@ static int sm501_init_dev(struct sm501_devdata *sm) - sm501_register_uart(sm, idata->devices); - if (idata->devices & SM501_USE_GPIO) - sm501_register_gpio(sm); -+ if (idata->devices & SM501_USE_PWM) -+ sm501_register_pwm(sm); - } - - if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { -@@ -1542,10 +1580,15 @@ static struct sm501_initdata sm501_pci_initdata = { - .devices = SM501_USE_ALL, - - /* Errata AB-3 says that 72MHz is the fastest available -- * for 33MHZ PCI with proper bus-mastering operation */ -- -+ * for 33MHZ PCI with proper bus-mastering operation -+ * For gdium, it works under 84&112M clock freq.*/ -+#ifdef CONFIG_DEXXON_GDIUM -+ .mclk = 84 * MHZ, -+ .m1xclk = 112 * MHZ, -+#else - .mclk = 72 * MHZ, - .m1xclk = 144 * MHZ, -+#endif - }; - - static struct sm501_platdata_fbsub sm501_pdata_fbsub = { -diff --git a/drivers/net/titan_ge.c b/drivers/net/titan_ge.c -new file mode 100644 -index 0000000..dc137bf8 ---- /dev/null -+++ b/drivers/net/titan_ge.c -@@ -0,0 +1,2069 @@ -+/* -+ * drivers/net/titan_ge.c - Driver for Titan ethernet ports -+ * -+ * Copyright (C) 2003 PMC-Sierra Inc. -+ * Author : Manish Lachwani (lachwani@pmc-sierra.com) -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+/* -+ * The MAC unit of the Titan consists of the following: -+ * -+ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO -+ * -> FIFO is where the incoming and outgoing data is placed -+ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes -+ * the data into the FIFO for Rx -+ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. -+ * -> AFX is the address filtering block -+ * -> GMII block to communicate with the PHY -+ * -+ * Rx will look like the following: -+ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory -+ * -+ * Tx will look like the following: -+ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII -+ * -+ * The Titan driver has support for the following performance features: -+ * -> Rx side checksumming -+ * -> Jumbo Frames -+ * -> Interrupt Coalscing -+ * -> Rx NAPI -+ * -> SKB Recycling -+ * -> Transmit/Receive descriptors in SRAM -+ * -> Fast routing for IP forwarding -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* For MII specifc registers, titan_mdio.h should be included */ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "titan_ge.h" -+#include "titan_mdio.h" -+ -+/* Static Function Declarations */ -+static int titan_ge_eth_open(struct net_device *); -+static void titan_ge_eth_stop(struct net_device *); -+static struct net_device_stats *titan_ge_get_stats(struct net_device *); -+static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int, -+ unsigned long, unsigned long, -+ unsigned long); -+static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int, -+ unsigned long, unsigned long); -+ -+static int titan_ge_open(struct net_device *); -+static int titan_ge_start_xmit(struct sk_buff *, struct net_device *); -+static int titan_ge_stop(struct net_device *); -+ -+static unsigned long titan_ge_tx_coal(unsigned long, int); -+ -+static void titan_ge_port_reset(unsigned int); -+static int titan_ge_free_tx_queue(titan_ge_port_info *); -+static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *); -+static int titan_ge_port_start(struct net_device *, titan_ge_port_info *); -+ -+static int titan_ge_return_tx_desc(titan_ge_port_info *, int); -+ -+/* -+ * Some configuration for the FIFO and the XDMA channel needs -+ * to be done only once for all the ports. This flag controls -+ * that -+ */ -+static unsigned long config_done; -+ -+/* -+ * One time out of memory flag -+ */ -+static unsigned int oom_flag; -+ -+static int titan_ge_poll(struct net_device *netdev, int *budget); -+ -+static int titan_ge_receive_queue(struct net_device *, unsigned int); -+ -+static struct platform_device *titan_ge_device[3]; -+ -+/* MAC Address */ -+extern unsigned char titan_ge_mac_addr_base[6]; -+ -+unsigned long titan_ge_base; -+static unsigned long titan_ge_sram; -+ -+static char titan_string[] = "titan"; -+ -+/* -+ * The Titan GE has two alignment requirements: -+ * -> skb->data to be cacheline aligned (32 byte) -+ * -> IP header alignment to 16 bytes -+ * -+ * The latter is not implemented. So, that results in an extra copy on -+ * the Rx. This is a big performance hog. For the former case, the -+ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size -+ * requested is calculated: -+ * -+ * Ethernet Frame Size : 1518 -+ * Ethernet Header : 14 -+ * Future Titan change for IP header alignment : 2 -+ * -+ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header -+ * alignment, we use skb_reserve(). -+ */ -+ -+#define ALIGNED_RX_SKB_ADDR(addr) \ -+ ((((unsigned long)(addr) + (64UL - 1UL)) \ -+ & ~(64UL - 1UL)) - (unsigned long)(addr)) -+ -+#define titan_ge_alloc_skb(__length, __gfp_flags) \ -+({ struct sk_buff *__skb; \ -+ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \ -+ if(__skb) { \ -+ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \ -+ if(__offset) \ -+ skb_reserve(__skb, __offset); \ -+ } \ -+ __skb; \ -+}) -+ -+/* -+ * Configure the GMII block of the Titan based on what the PHY tells us -+ */ -+static void titan_ge_gmii_config(int port_num) -+{ -+ unsigned int reg_data = 0, phy_reg; -+ int err; -+ -+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); -+ -+ if (err == TITAN_GE_MDIO_ERROR) { -+ printk(KERN_ERR -+ "Could not read PHY control register 0x11 \n"); -+ printk(KERN_ERR -+ "Setting speed to 1000 Mbps and Duplex to Full \n"); -+ -+ return; -+ } -+ -+ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0); -+ -+ if (phy_reg & 0x8000) { -+ if (phy_reg & 0x2000) { -+ /* Full Duplex and 1000 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x201); -+ } else { -+ /* Half Duplex and 1000 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x2201); -+ } -+ } -+ if (phy_reg & 0x4000) { -+ if (phy_reg & 0x2000) { -+ /* Full Duplex and 100 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x100); -+ } else { -+ /* Half Duplex and 100 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x2100); -+ } -+ } -+ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL + -+ (port_num << 12)); -+ reg_data |= 0x3; -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL + -+ (port_num << 12)), reg_data); -+} -+ -+/* -+ * Enable the TMAC if it is not -+ */ -+static void titan_ge_enable_tx(unsigned int port_num) -+{ -+ unsigned long reg_data; -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); -+ if (!(reg_data & 0x8000)) { -+ printk("TMAC disabled for port %d!! \n", port_num); -+ -+ reg_data |= 0x0001; /* Enable TMAC */ -+ reg_data |= 0x4000; /* CRC Check Enable */ -+ reg_data |= 0x2000; /* Padding enable */ -+ reg_data |= 0x0800; /* CRC Add enable */ -+ reg_data |= 0x0080; /* PAUSE frame */ -+ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ } -+} -+ -+/* -+ * Tx Timeout function -+ */ -+static void titan_ge_tx_timeout(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ printk(KERN_INFO "%s: TX timeout ", netdev->name); -+ printk(KERN_INFO "Resetting card \n"); -+ -+ /* Do the reset outside of interrupt context */ -+ schedule_work(&titan_ge_eth->tx_timeout_task); -+} -+ -+/* -+ * Update the AFX tables for UC and MC for slice 0 only -+ */ -+static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth) -+{ -+ int port = titan_ge_eth->port_num; -+ unsigned int i; -+ volatile unsigned long reg_data = 0; -+ u8 p_addr[6]; -+ -+ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6); -+ -+ /* Set the MAC address here for TMAC and RMAC */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1); -+ /* Configure the eight address filters */ -+ for (i = 0; i < 8; i++) { -+ /* Select each of the eight filters */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 + -+ (port << 12)), i); -+ -+ /* Configure the match */ -+ reg_data = 0x9; /* Forward Enable Bit */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 + -+ (port << 12)), reg_data); -+ -+ /* Finally, AFX Exact Match Address Registers */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ -+ /* VLAN id set to 0 */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + -+ (port << 12)), 0); -+ } -+} -+ -+/* -+ * Actual Routine to reset the adapter when the timeout occurred -+ */ -+static void titan_ge_tx_timeout_task(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ int port = titan_ge_eth->port_num; -+ -+ printk("Titan GE: Transmit timed out. Resetting ... \n"); -+ -+ /* Dump debug info */ -+ printk(KERN_ERR "TRTG cause : %x \n", -+ TITAN_GE_READ(0x100c + (port << 12))); -+ -+ /* Fix this for the other ports */ -+ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c)); -+ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040)); -+ printk(KERN_ERR "XDMA GDI ERROR : %x \n", -+ TITAN_GE_READ(0x5008 + (port << 8))); -+ printk(KERN_ERR "CHANNEL ERROR: %x \n", -+ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT -+ + (port << 8))); -+ -+ netif_device_detach(netdev); -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ titan_ge_port_start(netdev, titan_ge_eth); -+ netif_device_attach(netdev); -+} -+ -+/* -+ * Change the MTU of the Ethernet Device -+ */ -+static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned long flags; -+ -+ if ((new_mtu > 9500) || (new_mtu < 64)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ netdev->mtu = new_mtu; -+ -+ /* Now we have to reopen the interface so that SKBs with the new -+ * size will be allocated */ -+ -+ if (netif_running(netdev)) { -+ titan_ge_eth_stop(netdev); -+ -+ if (titan_ge_eth_open(netdev) != TITAN_OK) { -+ printk(KERN_ERR -+ "%s: Fatal error on opening device\n", -+ netdev->name); -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ return -1; -+ } -+ } -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ return 0; -+} -+ -+/* -+ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line -+ * only. Once an interrupt is triggered, figure out the port and then check -+ * the channel. -+ */ -+static irqreturn_t titan_ge_int_handler(int irq, void *dev_id) -+{ -+ struct net_device *netdev = (struct net_device *) dev_id; -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int reg_data; -+ unsigned int eth_int_cause_error = 0, is; -+ unsigned long eth_int_cause1; -+ int err = 0; -+#ifdef CONFIG_SMP -+ unsigned long eth_int_cause2; -+#endif -+ -+ /* Ack the CPU interrupt */ -+ switch (port_num) { -+ case 0: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is); -+#endif -+ break; -+ -+ case 1: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is); -+#endif -+ break; -+ -+ case 2: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is); -+#endif -+ } -+ -+ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); -+#ifdef CONFIG_SMP -+ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B); -+#endif -+ -+ /* Spurious interrupt */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) { -+#else -+ if (eth_int_cause1 == 0) { -+#endif -+ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT + -+ (port_num << 8)); -+ -+ if (eth_int_cause_error == 0) -+ return IRQ_NONE; -+ } -+ -+ /* Handle Tx first. No need to ack interrupts */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 & 0x20202) || -+ (eth_int_cause2 & 0x20202) ) -+#else -+ if (eth_int_cause1 & 0x20202) -+#endif -+ titan_ge_free_tx_queue(titan_ge_eth); -+ -+ /* Handle the Rx next */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 & 0x10101) || -+ (eth_int_cause2 & 0x10101)) { -+#else -+ if (eth_int_cause1 & 0x10101) { -+#endif -+ if (netif_rx_schedule_prep(netdev)) { -+ unsigned int ack; -+ -+ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ /* Disable Tx and Rx both */ -+ if (port_num == 0) -+ ack &= ~(0x3); -+ if (port_num == 1) -+ ack &= ~(0x300); -+ -+ if (port_num == 2) -+ ack &= ~(0x30000); -+ -+ /* Interrupts have been disabled */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack); -+ -+ __netif_rx_schedule(netdev); -+ } -+ } -+ -+ /* Handle error interrupts */ -+ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) { -+ printk(KERN_ERR -+ "XDMA Channel Error : %x on port %d\n", -+ eth_int_cause_error, port_num); -+ -+ printk(KERN_ERR -+ "XDMA GDI Hardware error : %x on port %d\n", -+ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num); -+ -+ printk(KERN_ERR -+ "XDMA currently has %d Rx descriptors \n", -+ TITAN_GE_READ(0x5048 + (port_num << 8))); -+ -+ printk(KERN_ERR -+ "XDMA currently has prefetcted %d Rx descriptors \n", -+ TITAN_GE_READ(0x505c + (port_num << 8))); -+ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + -+ (port_num << 8)), eth_int_cause_error); -+ } -+ -+ /* -+ * PHY interrupt to inform abt the changes. Reading the -+ * PHY Status register will clear the interrupt -+ */ -+ if ((!(eth_int_cause1 & 0x30303)) && -+ (eth_int_cause_error == 0)) { -+ err = -+ titan_ge_mdio_read(port_num, -+ TITAN_GE_MDIO_PHY_IS, ®_data); -+ -+ if (reg_data & 0x0400) { -+ /* Link status change */ -+ titan_ge_mdio_read(port_num, -+ TITAN_GE_MDIO_PHY_STATUS, ®_data); -+ if (!(reg_data & 0x0400)) { -+ /* Link is down */ -+ netif_carrier_off(netdev); -+ netif_stop_queue(netdev); -+ } else { -+ /* Link is up */ -+ netif_carrier_on(netdev); -+ netif_wake_queue(netdev); -+ -+ /* Enable the queue */ -+ titan_ge_enable_tx(port_num); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Multicast and Promiscuous mode set. The -+ * set_multi entry point is called whenever the -+ * multicast address list or the network interface -+ * flags are updated. -+ */ -+static void titan_ge_set_multi(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned long reg_data; -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + -+ (port_num << 12)); -+ -+ if (netdev->flags & IFF_PROMISC) { -+ reg_data |= 0x2; -+ } -+ else if (netdev->flags & IFF_ALLMULTI) { -+ reg_data |= 0x01; -+ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */ -+ } -+ else { -+ reg_data = 0x2; -+ } -+ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + -+ (port_num << 12)), reg_data); -+ if (reg_data & 0x01) { -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI + -+ (port_num << 12)), 0xffff); -+ } -+} -+ -+/* -+ * Open the network device -+ */ -+static int titan_ge_open(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num; -+ int retval; -+ -+ retval = request_irq(irq, titan_ge_int_handler, -+ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev); -+ -+ if (retval != 0) { -+ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n"); -+ return -1; -+ } -+ -+ netdev->irq = irq; -+ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num); -+ -+ spin_lock_irq(&(titan_ge_eth->lock)); -+ -+ if (titan_ge_eth_open(netdev) != TITAN_OK) { -+ spin_unlock_irq(&(titan_ge_eth->lock)); -+ printk("%s: Error opening interface \n", netdev->name); -+ free_irq(netdev->irq, netdev); -+ return -EBUSY; -+ } -+ -+ spin_unlock_irq(&(titan_ge_eth->lock)); -+ -+ return 0; -+} -+ -+/* -+ * Allocate the SKBs for the Rx ring. Also used -+ * for refilling the queue -+ */ -+static int titan_ge_rx_task(struct net_device *netdev, -+ titan_ge_port_info *titan_ge_port) -+{ -+ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev; -+ volatile titan_ge_rx_desc *rx_desc; -+ struct sk_buff *skb; -+ int rx_used_desc; -+ int count = 0; -+ -+ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) { -+ -+ /* First try to get the skb from the recycler */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC); -+#else -+ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC); -+#endif -+ if (unlikely(!skb)) { -+ /* OOM, set the flag */ -+ printk("OOM \n"); -+ oom_flag = 1; -+ break; -+ } -+ count++; -+ skb->dev = netdev; -+ -+ titan_ge_port->rx_ring_skbs++; -+ -+ rx_used_desc = titan_ge_port->rx_used_desc_q; -+ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]); -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ rx_desc->buffer_addr = dma_map_single(device, skb->data, -+ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE); -+#else -+ rx_desc->buffer_addr = dma_map_single(device, skb->data, -+ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE); -+#endif -+ -+ titan_ge_port->rx_skb[rx_used_desc] = skb; -+ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED; -+ -+ titan_ge_port->rx_used_desc_q = -+ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE; -+ } -+ -+ return count; -+} -+ -+/* -+ * Actual init of the Tital GE port. There is one register for -+ * the channel configuration -+ */ -+static void titan_port_init(struct net_device *netdev, -+ titan_ge_port_info * titan_ge_eth) -+{ -+ unsigned long reg_data; -+ -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ -+ /* First reset the TMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data |= 0x80000000; -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ udelay(30); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data &= ~(0xc0000000); -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ /* Now reset the RMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data |= 0x00080000; -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ udelay(30); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data &= ~(0x000c0000); -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+} -+ -+/* -+ * Start the port. All the hardware specific configuration -+ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX -+ * go here -+ */ -+static int titan_ge_port_start(struct net_device *netdev, -+ titan_ge_port_info * titan_port) -+{ -+ volatile unsigned long reg_data, reg_data1; -+ int port_num = titan_port->port_num; -+ int count = 0; -+ unsigned long reg_data_1; -+ -+ if (config_done == 0) { -+ reg_data = TITAN_GE_READ(0x0004); -+ reg_data |= 0x100; -+ TITAN_GE_WRITE(0x0004, reg_data); -+ -+ reg_data &= ~(0x100); -+ TITAN_GE_WRITE(0x0004, reg_data); -+ -+ /* Turn on GMII/MII mode and turn off TBI mode */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1); -+ reg_data |= 0x00000700; -+ reg_data &= ~(0x00800000); /* Fencing */ -+ -+ TITAN_GE_WRITE(0x000c, 0x00001100); -+ -+ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data); -+ -+ /* Set the CPU Resource Limit register */ -+ TITAN_GE_WRITE(0x00f8, 0x8); -+ -+ /* Be conservative when using the BIU buffers */ -+ TITAN_GE_WRITE(0x0068, 0x4); -+ } -+ -+ titan_port->tx_threshold = 0; -+ titan_port->rx_threshold = 0; -+ -+ /* We need to write the descriptors for Tx and Rx */ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)), -+ (unsigned long) titan_port->tx_dma); -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)), -+ (unsigned long) titan_port->rx_dma); -+ -+ if (config_done == 0) { -+ /* Step 1: XDMA config */ -+ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG); -+ reg_data &= ~(0x80000000); /* clear reset */ -+ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */ -+ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */ -+ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */ -+ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */ -+ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data); -+ } -+ -+ /* IR register for the XDMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)); -+ reg_data |= 0x80068000; /* No Rx_OOD */ -+ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data); -+ -+ /* Start the Tx and Rx XDMA controller */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)); -+ reg_data &= 0x4fffffff; /* Clear tx reset */ -+ reg_data &= 0xfff4ffff; /* Clear rx reset */ -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ reg_data |= 0xa0 | 0x30030000; -+#else -+ reg_data |= 0x40 | 0x20030000; -+#endif -+ -+#ifndef CONFIG_SMP -+ reg_data &= ~(0x10); -+ reg_data |= 0x0f; /* All of the packet */ -+#endif -+ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data); -+ -+ /* Rx desc count */ -+ count = titan_ge_rx_task(netdev, titan_port); -+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count); -+ count = TITAN_GE_READ(0x5048 + (port_num << 8)); -+ -+ udelay(30); -+ -+ /* -+ * Step 2: Configure the SDQPF, i.e. FIFO -+ */ -+ if (config_done == 0) { -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); -+ reg_data = 0x1; -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ reg_data &= ~(0x1); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); -+ reg_data = 0x1; -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ reg_data &= ~(0x1); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ } -+ /* -+ * Enable RX FIFO 0, 4 and 8 -+ */ -+ if (port_num == 0) { -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10); -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4844); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x4844, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ reg_data |= (0xff << 10); -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4944); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x4944, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ } -+ -+ if (port_num == 1) { -+ reg_data = TITAN_GE_READ(0x4870); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (0xff + 1); -+ -+ TITAN_GE_WRITE(0x4870, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4874); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x4874, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4870, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x494c); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x494c, reg_data); -+ reg_data |= (0xff << 10) | (0xff + 1); -+ TITAN_GE_WRITE(0x494c, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4950); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x4950, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x494c, reg_data); -+ } -+ -+ /* -+ * Titan 1.2 revision does support port #2 -+ */ -+ if (port_num == 2) { -+ /* -+ * Put the descriptors in the SRAM -+ */ -+ reg_data = TITAN_GE_READ(0x48a0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x48a4); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x48a4, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x4958); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ TITAN_GE_WRITE(0x4958, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x495c); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x495c, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ } -+ -+ if (port_num == 2) { -+ reg_data = TITAN_GE_READ(0x48a0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x48a4); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x48a4, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x4958); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ TITAN_GE_WRITE(0x4958, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x495c); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x495c, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ } -+ -+ /* -+ * Step 3: TRTG block enable -+ */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12)); -+ -+ /* -+ * This is the 1.2 revision of the chip. It has fix for the -+ * IP header alignment. Now, the IP header begins at an -+ * aligned address and this wont need an extra copy in the -+ * driver. This performance drawback existed in the previous -+ * versions of the silicon -+ */ -+ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12)); -+ reg_data_1 |= 0x40000000; -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ reg_data_1 |= 0x04000000; -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ mdelay(5); -+ -+ reg_data_1 &= ~(0x04000000); -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ mdelay(5); -+ -+ reg_data |= 0x0001; -+ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data); -+ -+ /* -+ * Step 4: Start the Tx activity -+ */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197); -+#ifdef TITAN_GE_JUMBO_FRAMES -+ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000); -+#endif -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); -+ reg_data |= 0x0001; /* Enable TMAC */ -+ reg_data |= 0x6c70; /* PAUSE also set */ -+ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ udelay(30); -+ -+ /* Destination Address drop bit */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)); -+ reg_data |= 0x218; /* DA_DROP bit and pause */ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data); -+ -+ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3); -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000); -+#endif -+ /* Start the Rx activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); -+ reg_data |= 0x0001; /* RMAC Enable */ -+ reg_data |= 0x0010; /* CRC Check enable */ -+ reg_data |= 0x0040; /* Min Frame check enable */ -+ reg_data |= 0x4400; /* Max Frame check enable */ -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ udelay(30); -+ -+ /* -+ * Enable the Interrupts for Tx and Rx -+ */ -+ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ -+ if (port_num == 0) { -+ reg_data1 |= 0x3; -+#ifdef CONFIG_SMP -+ TITAN_GE_WRITE(0x0038, 0x003); -+#else -+ TITAN_GE_WRITE(0x0038, 0x303); -+#endif -+ } -+ -+ if (port_num == 1) { -+ reg_data1 |= 0x300; -+ } -+ -+ if (port_num == 2) -+ reg_data1 |= 0x30000; -+ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1); -+ TITAN_GE_WRITE(0x003c, 0x300); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */ -+ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */ -+ } -+ -+ /* Priority */ -+ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12)); -+ reg_data &= ~(0x00f00000); -+ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data); -+ -+ /* Step 5: GMII config */ -+ titan_ge_gmii_config(port_num); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(0x1a80, 0); -+ config_done = 1; -+ } -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Function to queue the packet for the Ethernet device -+ */ -+static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth, -+ struct sk_buff * skb) -+{ -+ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev; -+ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q; -+ volatile titan_ge_tx_desc *tx_curr; -+ int port_num = titan_ge_eth->port_num; -+ -+ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]); -+ tx_curr->buffer_addr = -+ dma_map_single(device, skb->data, skb_headlen(skb), -+ DMA_TO_DEVICE); -+ -+ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb; -+ tx_curr->buffer_len = skb_headlen(skb); -+ -+ /* Last descriptor enables interrupt and changes ownership */ -+ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5); -+ -+ /* Kick the XDMA to start the transfer from memory to the FIFO */ -+ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1); -+ -+ /* Current descriptor updated */ -+ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE; -+ -+ /* Prefetch the next descriptor */ -+ prefetch((const void *) -+ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]); -+} -+ -+/* -+ * Actually does the open of the Ethernet device -+ */ -+static int titan_ge_eth_open(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ struct device *device = &titan_ge_device[port_num]->dev; -+ unsigned long reg_data; -+ unsigned int phy_reg; -+ int err = 0; -+ -+ /* Stop the Rx activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ /* Clear the port interrupts */ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0); -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0); -+ } -+ -+ /* Set the MAC Address */ -+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); -+ -+ if (config_done == 0) -+ titan_port_init(netdev, titan_ge_eth); -+ -+ titan_ge_update_afx(titan_ge_eth); -+ -+ /* Allocate the Tx ring now */ -+ titan_ge_eth->tx_ring_skbs = 0; -+ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE; -+ -+ /* Allocate space in the SRAM for the descriptors */ -+ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *) -+ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num); -+ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num; -+ -+ if (!titan_ge_eth->tx_desc_area) { -+ printk(KERN_ERR -+ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n", -+ netdev->name, TITAN_TX_RING_BYTES, port_num); -+ return -ENOMEM; -+ } -+ -+ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size); -+ -+ /* Now initialize the Tx descriptor ring */ -+ titan_ge_init_tx_desc_ring(titan_ge_eth, -+ titan_ge_eth->tx_ring_size, -+ (unsigned long) titan_ge_eth->tx_desc_area, -+ (unsigned long) titan_ge_eth->tx_dma); -+ -+ /* Allocate the Rx ring now */ -+ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE; -+ titan_ge_eth->rx_ring_skbs = 0; -+ -+ titan_ge_eth->rx_desc_area = -+ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num); -+ -+ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num; -+ -+ if (!titan_ge_eth->rx_desc_area) { -+ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", -+ netdev->name, TITAN_RX_RING_BYTES); -+ -+ printk(KERN_ERR "%s: Freeing previously allocated TX queues...", -+ netdev->name); -+ -+ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size, -+ (void *) titan_ge_eth->tx_desc_area, -+ titan_ge_eth->tx_dma); -+ -+ return -ENOMEM; -+ } -+ -+ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size); -+ -+ /* Now initialize the Rx ring */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ if ((titan_ge_init_rx_desc_ring -+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE, -+ (unsigned long) titan_ge_eth->rx_desc_area, 0, -+ (unsigned long) titan_ge_eth->rx_dma)) == 0) -+#else -+ if ((titan_ge_init_rx_desc_ring -+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE, -+ (unsigned long) titan_ge_eth->rx_desc_area, 0, -+ (unsigned long) titan_ge_eth->rx_dma)) == 0) -+#endif -+ panic("%s: Error initializing RX Ring\n", netdev->name); -+ -+ /* Fill the Rx ring with the SKBs */ -+ titan_ge_port_start(netdev, titan_ge_eth); -+ -+ /* -+ * Check if Interrupt Coalscing needs to be turned on. The -+ * values specified in the register is multiplied by -+ * (8 x 64 nanoseconds) to determine when an interrupt should -+ * be sent to the CPU. -+ */ -+ -+ if (TITAN_GE_TX_COAL) { -+ titan_ge_eth->tx_int_coal = -+ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num); -+ } -+ -+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); -+ if (err == TITAN_GE_MDIO_ERROR) { -+ printk(KERN_ERR -+ "Could not read PHY control register 0x11 \n"); -+ return TITAN_ERROR; -+ } -+ if (!(phy_reg & 0x0400)) { -+ netif_carrier_off(netdev); -+ netif_stop_queue(netdev); -+ return TITAN_ERROR; -+ } else { -+ netif_carrier_on(netdev); -+ netif_start_queue(netdev); -+ } -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Queue the packet for Tx. Currently no support for zero copy, -+ * checksum offload and Scatter Gather. The chip does support -+ * Scatter Gather only. But, that wont help here since zero copy -+ * requires support for Tx checksumming also. -+ */ -+int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned long flags; -+ struct net_device_stats *stats; -+//printk("titan_ge_start_xmit\n"); -+ -+ stats = &titan_ge_eth->stats; -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <= -+ (skb_shinfo(skb)->nr_frags + 1)) { -+ netif_stop_queue(netdev); -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ printk(KERN_ERR "Tx OOD \n"); -+ return 1; -+ } -+ -+ titan_ge_tx_queue(titan_ge_eth, skb); -+ titan_ge_eth->tx_ring_skbs++; -+ -+ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) { -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ titan_ge_free_tx_queue(titan_ge_eth); -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ } -+ -+ stats->tx_bytes += skb->len; -+ stats->tx_packets++; -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ netdev->trans_start = jiffies; -+ -+ return 0; -+} -+ -+/* -+ * Actually does the Rx. Rx side checksumming supported. -+ */ -+static int titan_ge_rx(struct net_device *netdev, int port_num, -+ titan_ge_port_info * titan_ge_port, -+ titan_ge_packet * packet) -+{ -+ int rx_curr_desc, rx_used_desc; -+ volatile titan_ge_rx_desc *rx_desc; -+ -+ rx_curr_desc = titan_ge_port->rx_curr_desc_q; -+ rx_used_desc = titan_ge_port->rx_used_desc_q; -+ -+ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) -+ return TITAN_ERROR; -+ -+ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]); -+ -+ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) -+ return TITAN_ERROR; -+ -+ packet->skb = titan_ge_port->rx_skb[rx_curr_desc]; -+ packet->len = (rx_desc->cmd_sts & 0x7fff); -+ -+ /* -+ * At this point, we dont know if the checksumming -+ * actually helps relieve CPU. So, keep it for -+ * port 0 only -+ */ -+ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16); -+ packet->cmd_sts = rx_desc->cmd_sts; -+ -+ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE; -+ -+ /* Prefetch the next descriptor */ -+ prefetch((const void *) -+ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Free the Tx queue of the used SKBs -+ */ -+static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth) -+{ -+ unsigned long flags; -+ -+ /* Take the lock */ -+ spin_lock_irqsave(&(titan_ge_eth->lock), flags); -+ -+ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) -+ if (titan_ge_eth->tx_ring_skbs != 1) -+ titan_ge_eth->tx_ring_skbs--; -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Threshold beyond which we do the cleaning of -+ * Tx queue and new allocation for the Rx -+ * queue -+ */ -+#define TX_THRESHOLD 4 -+#define RX_THRESHOLD 10 -+ -+/* -+ * Receive the packets and send it to the kernel. -+ */ -+static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ titan_ge_packet packet; -+ struct net_device_stats *stats; -+ struct sk_buff *skb; -+ unsigned long received_packets = 0; -+ unsigned int ack; -+ -+ stats = &titan_ge_eth->stats; -+ -+ while ((--max) -+ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) { -+ skb = (struct sk_buff *) packet.skb; -+ -+ titan_ge_eth->rx_ring_skbs--; -+ -+ if (--titan_ge_eth->rx_work_limit < 0) -+ break; -+ received_packets++; -+ -+ stats->rx_packets++; -+ stats->rx_bytes += packet.len; -+ -+ if ((packet.cmd_sts & TITAN_GE_RX_PERR) || -+ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) || -+ (packet.cmd_sts & TITAN_GE_RX_TRUNC) || -+ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) { -+ stats->rx_dropped++; -+ dev_kfree_skb_any(skb); -+ -+ continue; -+ } -+ /* -+ * Either support fast path or slow path. Decision -+ * making can really slow down the performance. The -+ * idea is to cut down the number of checks and improve -+ * the fastpath. -+ */ -+ -+ skb_put(skb, packet.len - 2); -+ -+ /* -+ * Increment data pointer by two since thats where -+ * the MAC starts -+ */ -+ skb_reserve(skb, 2); -+ skb->protocol = eth_type_trans(skb, netdev); -+ netif_receive_skb(skb); -+ -+ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) { -+ ack = titan_ge_rx_task(netdev, titan_ge_eth); -+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack); -+ titan_ge_eth->rx_threshold = 0; -+ } else -+ titan_ge_eth->rx_threshold++; -+ -+ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) { -+ titan_ge_eth->tx_threshold = 0; -+ titan_ge_free_tx_queue(titan_ge_eth); -+ } -+ else -+ titan_ge_eth->tx_threshold++; -+ -+ } -+ return received_packets; -+} -+ -+ -+/* -+ * Enable the Rx side interrupts -+ */ -+static void titan_ge_enable_int(unsigned int port_num, -+ titan_ge_port_info *titan_ge_eth, -+ struct net_device *netdev) -+{ -+ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ -+ if (port_num == 0) -+ reg_data |= 0x3; -+ if (port_num == 1) -+ reg_data |= 0x300; -+ if (port_num == 2) -+ reg_data |= 0x30000; -+ -+ /* Re-enable interrupts */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data); -+} -+ -+/* -+ * Main function to handle the polling for Rx side NAPI. -+ * Receive interrupts have been disabled at this point. -+ * The poll schedules the transmit followed by receive. -+ */ -+static int titan_ge_poll(struct net_device *netdev, int *budget) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ int port_num = titan_ge_eth->port_num; -+ int work_done = 0; -+ unsigned long flags, status; -+ -+ titan_ge_eth->rx_work_limit = *budget; -+ if (titan_ge_eth->rx_work_limit > netdev->quota) -+ titan_ge_eth->rx_work_limit = netdev->quota; -+ -+ do { -+ /* Do the transmit cleaning work here */ -+ titan_ge_free_tx_queue(titan_ge_eth); -+ -+ /* Ack the Rx interrupts */ -+ if (port_num == 0) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3); -+ if (port_num == 1) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300); -+ if (port_num == 2) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000); -+ -+ work_done += titan_ge_receive_queue(netdev, 0); -+ -+ /* Out of quota and there is work to be done */ -+ if (titan_ge_eth->rx_work_limit < 0) -+ goto not_done; -+ -+ /* Receive alloc_skb could lead to OOM */ -+ if (oom_flag == 1) { -+ oom_flag = 0; -+ goto oom; -+ } -+ -+ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); -+ } while (status & 0x30300); -+ -+ /* If we are here, then no more interrupts to process */ -+ goto done; -+ -+not_done: -+ *budget -= work_done; -+ netdev->quota -= work_done; -+ return 1; -+ -+oom: -+ printk(KERN_ERR "OOM \n"); -+ netif_rx_complete(netdev); -+ return 0; -+ -+done: -+ /* -+ * No more packets on the poll list. Turn the interrupts -+ * back on and we should be able to catch the new -+ * packets in the interrupt handler -+ */ -+ if (!work_done) -+ work_done = 1; -+ -+ *budget -= work_done; -+ netdev->quota -= work_done; -+ -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ /* Remove us from the poll list */ -+ netif_rx_complete(netdev); -+ -+ /* Re-enable interrupts */ -+ titan_ge_enable_int(port_num, titan_ge_eth, netdev); -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ return 0; -+} -+ -+/* -+ * Close the network device -+ */ -+int titan_ge_stop(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ spin_lock_irq(&(titan_ge_eth->lock)); -+ titan_ge_eth_stop(netdev); -+ free_irq(netdev->irq, netdev); -+ spin_unlock_irq(&titan_ge_eth->lock); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Free the Tx ring -+ */ -+static void titan_ge_free_tx_rings(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int curr; -+ unsigned long reg_data; -+ -+ /* Stop the Tx DMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)); -+ reg_data |= 0xc0000000; -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)), reg_data); -+ -+ /* Disable the TMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ for (curr = 0; -+ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE); -+ curr++) { -+ if (titan_ge_eth->tx_skb[curr]) { -+ dev_kfree_skb(titan_ge_eth->tx_skb[curr]); -+ titan_ge_eth->tx_ring_skbs--; -+ } -+ } -+ -+ if (titan_ge_eth->tx_ring_skbs != 0) -+ printk -+ ("%s: Error on Tx descriptor free - could not free %d" -+ " descriptors\n", netdev->name, -+ titan_ge_eth->tx_ring_skbs); -+ -+#ifndef TITAN_RX_RING_IN_SRAM -+ dma_free_coherent(&titan_ge_device[port_num]->dev, -+ titan_ge_eth->tx_desc_area_size, -+ (void *) titan_ge_eth->tx_desc_area, -+ titan_ge_eth->tx_dma); -+#endif -+} -+ -+/* -+ * Free the Rx ring -+ */ -+static void titan_ge_free_rx_rings(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int curr; -+ unsigned long reg_data; -+ -+ /* Stop the Rx DMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)); -+ reg_data |= 0x000c0000; -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)), reg_data); -+ -+ /* Disable the RMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ for (curr = 0; -+ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE); -+ curr++) { -+ if (titan_ge_eth->rx_skb[curr]) { -+ dev_kfree_skb(titan_ge_eth->rx_skb[curr]); -+ titan_ge_eth->rx_ring_skbs--; -+ } -+ } -+ -+ if (titan_ge_eth->rx_ring_skbs != 0) -+ printk(KERN_ERR -+ "%s: Error in freeing Rx Ring. %d skb's still" -+ " stuck in RX Ring - ignoring them\n", netdev->name, -+ titan_ge_eth->rx_ring_skbs); -+ -+#ifndef TITAN_RX_RING_IN_SRAM -+ dma_free_coherent(&titan_ge_device[port_num]->dev, -+ titan_ge_eth->rx_desc_area_size, -+ (void *) titan_ge_eth->rx_desc_area, -+ titan_ge_eth->rx_dma); -+#endif -+} -+ -+/* -+ * Actually does the stop of the Ethernet device -+ */ -+static void titan_ge_eth_stop(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ netif_stop_queue(netdev); -+ -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ -+ titan_ge_free_tx_rings(netdev); -+ titan_ge_free_rx_rings(netdev); -+ -+ /* Disable the Tx and Rx Interrupts for all channels */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0); -+} -+ -+/* -+ * Update the MAC address. Note that we have to write the -+ * address in three station registers, 16 bits each. And this -+ * has to be done for TMAC and RMAC -+ */ -+static void titan_ge_update_mac_address(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ u8 p_addr[6]; -+ -+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); -+ memcpy(p_addr, netdev->dev_addr, 6); -+ -+ /* Update the Address Filtering Match tables */ -+ titan_ge_update_afx(titan_ge_eth); -+ -+ printk("Station MAC : %d %d %d %d %d %d \n", -+ p_addr[5], p_addr[4], p_addr[3], -+ p_addr[2], p_addr[1], p_addr[0]); -+ -+ /* Set the MAC address here for TMAC and RMAC */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+} -+ -+/* -+ * Set the MAC address of the Ethernet device -+ */ -+static int titan_ge_set_mac_address(struct net_device *dev, void *addr) -+{ -+ titan_ge_port_info *tp = netdev_priv(dev); -+ struct sockaddr *sa = addr; -+ -+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); -+ -+ spin_lock_irq(&tp->lock); -+ titan_ge_update_mac_address(dev); -+ spin_unlock_irq(&tp->lock); -+ -+ return 0; -+} -+ -+/* -+ * Get the Ethernet device stats -+ */ -+static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ return &titan_ge_eth->stats; -+} -+ -+/* -+ * Initialize the Rx descriptor ring for the Titan Ge -+ */ -+static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port, -+ int rx_desc_num, -+ int rx_buff_size, -+ unsigned long rx_desc_base_addr, -+ unsigned long rx_buff_base_addr, -+ unsigned long rx_dma) -+{ -+ volatile titan_ge_rx_desc *rx_desc; -+ unsigned long buffer_addr; -+ int index; -+ unsigned long titan_ge_rx_desc_bus = rx_dma; -+ -+ buffer_addr = rx_buff_base_addr; -+ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr; -+ -+ /* Check alignment */ -+ if (rx_buff_base_addr & 0xF) -+ return 0; -+ -+ /* Check Rx buffer size */ -+ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER)) -+ return 0; -+ -+ /* 64-bit alignment -+ if ((rx_buff_base_addr + rx_buff_size) & 0x7) -+ return 0; */ -+ -+ /* Initialize the Rx desc ring */ -+ for (index = 0; index < rx_desc_num; index++) { -+ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc); -+ rx_desc[index].cmd_sts = 0; -+ rx_desc[index].buffer_addr = buffer_addr; -+ titan_eth_port->rx_skb[index] = NULL; -+ buffer_addr += rx_buff_size; -+ } -+ -+ titan_eth_port->rx_curr_desc_q = 0; -+ titan_eth_port->rx_used_desc_q = 0; -+ -+ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr; -+ titan_eth_port->rx_desc_area_size = -+ rx_desc_num * sizeof(titan_ge_rx_desc); -+ -+ titan_eth_port->rx_dma = rx_dma; -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Initialize the Tx descriptor ring. Descriptors in the SRAM -+ */ -+static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port, -+ int tx_desc_num, -+ unsigned long tx_desc_base_addr, -+ unsigned long tx_dma) -+{ -+ titan_ge_tx_desc *tx_desc; -+ int index; -+ unsigned long titan_ge_tx_desc_bus = tx_dma; -+ -+ if (tx_desc_base_addr & 0xF) -+ return 0; -+ -+ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr; -+ -+ for (index = 0; index < tx_desc_num; index++) { -+ titan_ge_port->tx_dma_array[index] = -+ (dma_addr_t) titan_ge_tx_desc_bus; -+ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc); -+ tx_desc[index].cmd_sts = 0x0000; -+ tx_desc[index].buffer_len = 0; -+ tx_desc[index].buffer_addr = 0x00000000; -+ titan_ge_port->tx_skb[index] = NULL; -+ } -+ -+ titan_ge_port->tx_curr_desc_q = 0; -+ titan_ge_port->tx_used_desc_q = 0; -+ -+ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr; -+ titan_ge_port->tx_desc_area_size = -+ tx_desc_num * sizeof(titan_ge_tx_desc); -+ -+ titan_ge_port->tx_dma = tx_dma; -+ return TITAN_OK; -+} -+ -+/* -+ * Initialize the device as an Ethernet device -+ */ -+static int __init titan_ge_probe(struct device *device) -+{ -+ titan_ge_port_info *titan_ge_eth; -+ struct net_device *netdev; -+ int port = to_platform_device(device)->id; -+ int err; -+ -+ netdev = alloc_etherdev(sizeof(titan_ge_port_info)); -+ if (!netdev) { -+ err = -ENODEV; -+ goto out; -+ } -+ -+ netdev->open = titan_ge_open; -+ netdev->stop = titan_ge_stop; -+ netdev->hard_start_xmit = titan_ge_start_xmit; -+ netdev->get_stats = titan_ge_get_stats; -+ netdev->set_multicast_list = titan_ge_set_multi; -+ netdev->set_mac_address = titan_ge_set_mac_address; -+ -+ /* Tx timeout */ -+ netdev->tx_timeout = titan_ge_tx_timeout; -+ netdev->watchdog_timeo = 2 * HZ; -+ -+ /* Set these to very high values */ -+ netdev->poll = titan_ge_poll; -+ netdev->weight = 64; -+ -+ netdev->tx_queue_len = TITAN_GE_TX_QUEUE; -+ netif_carrier_off(netdev); -+ netdev->base_addr = 0; -+ -+ netdev->change_mtu = titan_ge_change_mtu; -+ -+ titan_ge_eth = netdev_priv(netdev); -+ /* Allocation of memory for the driver structures */ -+ -+ titan_ge_eth->port_num = port; -+ -+ /* Configure the Tx timeout handler */ -+ INIT_WORK(&titan_ge_eth->tx_timeout_task, -+ (void (*)(void *)) titan_ge_tx_timeout_task, netdev); -+ -+ spin_lock_init(&titan_ge_eth->lock); -+ -+ /* set MAC addresses */ -+ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6); -+ netdev->dev_addr[5] += port; -+ -+ err = register_netdev(netdev); -+ -+ if (err) -+ goto out_free_netdev; -+ -+ printk(KERN_NOTICE -+ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", -+ netdev->name, port, netdev->dev_addr[0], -+ netdev->dev_addr[1], netdev->dev_addr[2], -+ netdev->dev_addr[3], netdev->dev_addr[4], -+ netdev->dev_addr[5]); -+ -+ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n"); -+ -+ return 0; -+ -+out_free_netdev: -+ kfree(netdev); -+ -+out: -+ return err; -+} -+ -+static void __devexit titan_device_remove(struct device *device) -+{ -+} -+ -+/* -+ * Reset the Ethernet port -+ */ -+static void titan_ge_port_reset(unsigned int port_num) -+{ -+ unsigned int reg_data; -+ -+ /* Stop the Tx port activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x0001); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ /* Stop the Rx port activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x0001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ return; -+} -+ -+/* -+ * Return the Tx desc after use by the XDMA -+ */ -+static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port) -+{ -+ int tx_desc_used; -+ struct sk_buff *skb; -+ -+ tx_desc_used = titan_ge_eth->tx_used_desc_q; -+ -+ /* return right away */ -+ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q) -+ return TITAN_ERROR; -+ -+ /* Now the critical stuff */ -+ skb = titan_ge_eth->tx_skb[tx_desc_used]; -+ -+ dev_kfree_skb_any(skb); -+ -+ titan_ge_eth->tx_skb[tx_desc_used] = NULL; -+ titan_ge_eth->tx_used_desc_q = -+ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE; -+ -+ return 0; -+} -+ -+/* -+ * Coalescing for the Tx path -+ */ -+static unsigned long titan_ge_tx_coal(unsigned long delay, int port) -+{ -+ unsigned long rx_delay; -+ -+ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING); -+ delay = (delay << 16) | rx_delay; -+ -+ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay); -+ TITAN_GE_WRITE(0x5038, delay); -+ -+ return delay; -+} -+ -+static struct device_driver titan_soc_driver = { -+ .name = titan_string, -+ .bus = &platform_bus_type, -+ .probe = titan_ge_probe, -+ .remove = __devexit_p(titan_device_remove), -+}; -+ -+static void titan_platform_release (struct device *device) -+{ -+ struct platform_device *pldev; -+ -+ /* free device */ -+ pldev = to_platform_device (device); -+ kfree (pldev); -+} -+ -+/* -+ * Register the Titan GE with the kernel -+ */ -+static int __init titan_ge_init_module(void) -+{ -+ struct platform_device *pldev; -+ unsigned int version, device; -+ int i; -+ -+ printk(KERN_NOTICE -+ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n"); -+ -+ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE); -+ if (!titan_ge_base) { -+ printk("Mapping Titan GE failed\n"); -+ goto out; -+ } -+ -+ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID); -+ version = (device & 0x000f0000) >> 16; -+ device &= 0x0000ffff; -+ -+ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version); -+ -+#ifdef TITAN_RX_RING_IN_SRAM -+ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE, -+ TITAN_SRAM_SIZE); -+ if (!titan_ge_sram) { -+ printk("Mapping Titan SRAM failed\n"); -+ goto out_unmap_ge; -+ } -+#endif -+ -+ if (driver_register(&titan_soc_driver)) { -+ printk(KERN_ERR "Driver registration failed\n"); -+ goto out_unmap_sram; -+ } -+ -+ for (i = 0; i < 3; i++) { -+ titan_ge_device[i] = NULL; -+ -+ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) -+ continue; -+ -+ memset (pldev, 0, sizeof (*pldev)); -+ pldev->name = titan_string; -+ pldev->id = i; -+ pldev->dev.release = titan_platform_release; -+ titan_ge_device[i] = pldev; -+ -+ if (platform_device_register (pldev)) { -+ kfree (pldev); -+ titan_ge_device[i] = NULL; -+ continue; -+ } -+ -+ if (!pldev->dev.driver) { -+ /* -+ * The driver was not bound to this device, there was -+ * no hardware at this address. Unregister it, as the -+ * release fuction will take care of freeing the -+ * allocated structure -+ */ -+ titan_ge_device[i] = NULL; -+ platform_device_unregister (pldev); -+ } -+ } -+ -+ return 0; -+ -+out_unmap_sram: -+ iounmap((void *)titan_ge_sram); -+ -+out_unmap_ge: -+ iounmap((void *)titan_ge_base); -+ -+out: -+ return -ENOMEM; -+} -+ -+/* -+ * Unregister the Titan GE from the kernel -+ */ -+static void __exit titan_ge_cleanup_module(void) -+{ -+ int i; -+ -+ driver_unregister(&titan_soc_driver); -+ -+ for (i = 0; i < 3; i++) { -+ if (titan_ge_device[i]) { -+ platform_device_unregister (titan_ge_device[i]); -+ titan_ge_device[i] = NULL; -+ } -+ } -+ -+ iounmap((void *)titan_ge_sram); -+ iounmap((void *)titan_ge_base); -+} -+ -+MODULE_AUTHOR("Manish Lachwani "); -+MODULE_DESCRIPTION("Titan GE Ethernet driver"); -+MODULE_LICENSE("GPL"); -+ -+module_init(titan_ge_init_module); -+module_exit(titan_ge_cleanup_module); -diff --git a/drivers/net/titan_ge.h b/drivers/net/titan_ge.h -new file mode 100644 -index 0000000..3719f78 ---- /dev/null -+++ b/drivers/net/titan_ge.h -@@ -0,0 +1,415 @@ -+#ifndef _TITAN_GE_H_ -+#define _TITAN_GE_H_ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * These functions should be later moved to a more generic location since there -+ * will be others accessing it also -+ */ -+ -+/* -+ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in -+ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 -+ * register. -+ */ -+ -+#define TITAN_GE_BASE 0xfe000000UL -+#define TITAN_GE_SIZE 0x10000UL -+ -+extern unsigned long titan_ge_base; -+ -+#define TITAN_GE_WRITE(offset, data) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) = (data) -+ -+#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset)) -+ -+#ifndef msec_delay -+#define msec_delay(x) do { if(in_interrupt()) { \ -+ /* Don't mdelay in interrupt context! */ \ -+ BUG(); \ -+ } else { \ -+ set_current_state(TASK_UNINTERRUPTIBLE); \ -+ schedule_timeout((x * HZ)/1000); \ -+ } } while(0) -+#endif -+ -+#define TITAN_GE_PORT_0 -+ -+#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4) -+#define TITAN_SRAM_SIZE 0x2000UL -+ -+/* -+ * We may need these constants -+ */ -+#define TITAN_BIT0 0x00000001 -+#define TITAN_BIT1 0x00000002 -+#define TITAN_BIT2 0x00000004 -+#define TITAN_BIT3 0x00000008 -+#define TITAN_BIT4 0x00000010 -+#define TITAN_BIT5 0x00000020 -+#define TITAN_BIT6 0x00000040 -+#define TITAN_BIT7 0x00000080 -+#define TITAN_BIT8 0x00000100 -+#define TITAN_BIT9 0x00000200 -+#define TITAN_BIT10 0x00000400 -+#define TITAN_BIT11 0x00000800 -+#define TITAN_BIT12 0x00001000 -+#define TITAN_BIT13 0x00002000 -+#define TITAN_BIT14 0x00004000 -+#define TITAN_BIT15 0x00008000 -+#define TITAN_BIT16 0x00010000 -+#define TITAN_BIT17 0x00020000 -+#define TITAN_BIT18 0x00040000 -+#define TITAN_BIT19 0x00080000 -+#define TITAN_BIT20 0x00100000 -+#define TITAN_BIT21 0x00200000 -+#define TITAN_BIT22 0x00400000 -+#define TITAN_BIT23 0x00800000 -+#define TITAN_BIT24 0x01000000 -+#define TITAN_BIT25 0x02000000 -+#define TITAN_BIT26 0x04000000 -+#define TITAN_BIT27 0x08000000 -+#define TITAN_BIT28 0x10000000 -+#define TITAN_BIT29 0x20000000 -+#define TITAN_BIT30 0x40000000 -+#define TITAN_BIT31 0x80000000 -+ -+/* Flow Control */ -+#define TITAN_GE_FC_NONE 0x0 -+#define TITAN_GE_FC_FULL 0x1 -+#define TITAN_GE_FC_TX_PAUSE 0x2 -+#define TITAN_GE_FC_RX_PAUSE 0x3 -+ -+/* Duplex Settings */ -+#define TITAN_GE_FULL_DUPLEX 0x1 -+#define TITAN_GE_HALF_DUPLEX 0x2 -+ -+/* Speed settings */ -+#define TITAN_GE_SPEED_1000 0x1 -+#define TITAN_GE_SPEED_100 0x2 -+#define TITAN_GE_SPEED_10 0x3 -+ -+/* Debugging info only */ -+#undef TITAN_DEBUG -+ -+/* Keep the rings in the Titan's SSRAM */ -+#define TITAN_RX_RING_IN_SRAM -+ -+#ifdef CONFIG_64BIT -+#define TITAN_GE_IE_MASK 0xfffffffffb001b64 -+#define TITAN_GE_IE_STATUS 0xfffffffffb001b60 -+#else -+#define TITAN_GE_IE_MASK 0xfb001b64 -+#define TITAN_GE_IE_STATUS 0xfb001b60 -+#endif -+ -+/* Support for Jumbo Frames */ -+#undef TITAN_GE_JUMBO_FRAMES -+ -+/* Rx buffer size */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+#define TITAN_GE_JUMBO_BUFSIZE 9080 -+#else -+#define TITAN_GE_STD_BUFSIZE 1580 -+#endif -+ -+/* -+ * Tx and Rx Interrupt Coalescing parameter. These values are -+ * for 1 Ghz processor. Rx coalescing can be taken care of -+ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing -+ * is not adaptive. Hence, these values need to be adjusted -+ * based on load, CPU speed etc. -+ */ -+#define TITAN_GE_RX_COAL 150 -+#define TITAN_GE_TX_COAL 300 -+ -+#if defined(__BIG_ENDIAN) -+ -+/* Define the Rx descriptor */ -+typedef struct eth_rx_desc { -+ u32 reserved; /* Unused */ -+ u32 buffer_addr; /* CPU buffer address */ -+ u32 cmd_sts; /* Command and Status */ -+ u32 buffer; /* XDMA buffer address */ -+} titan_ge_rx_desc; -+ -+/* Define the Tx descriptor */ -+typedef struct eth_tx_desc { -+ u16 cmd_sts; /* Command, Status and Buffer count */ -+ u16 buffer_len; /* Length of the buffer */ -+ u32 buffer_addr; /* Physical address of the buffer */ -+} titan_ge_tx_desc; -+ -+#elif defined(__LITTLE_ENDIAN) -+ -+/* Define the Rx descriptor */ -+typedef struct eth_rx_desc { -+ u32 buffer_addr; /* CPU buffer address */ -+ u32 reserved; /* Unused */ -+ u32 buffer; /* XDMA buffer address */ -+ u32 cmd_sts; /* Command and Status */ -+} titan_ge_rx_desc; -+ -+/* Define the Tx descriptor */ -+typedef struct eth_tx_desc { -+ u32 buffer_addr; /* Physical address of the buffer */ -+ u16 buffer_len; /* Length of the buffer */ -+ u16 cmd_sts; /* Command, Status and Buffer count */ -+} titan_ge_tx_desc; -+#endif -+ -+/* Default Tx Queue Size */ -+#define TITAN_GE_TX_QUEUE 128 -+#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc)) -+ -+/* Default Rx Queue Size */ -+#define TITAN_GE_RX_QUEUE 64 -+#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc)) -+ -+/* Packet Structure */ -+typedef struct _pkt_info { -+ unsigned int len; -+ unsigned int cmd_sts; -+ unsigned int buffer; -+ struct sk_buff *skb; -+ unsigned int checksum; -+} titan_ge_packet; -+ -+ -+#define PHYS_CNT 3 -+ -+/* Titan Port specific data structure */ -+typedef struct _eth_port_ctrl { -+ unsigned int port_num; -+ u8 port_mac_addr[6]; -+ -+ /* Rx descriptor pointers */ -+ int rx_curr_desc_q, rx_used_desc_q; -+ -+ /* Tx descriptor pointers */ -+ int tx_curr_desc_q, tx_used_desc_q; -+ -+ /* Rx descriptor area */ -+ volatile titan_ge_rx_desc *rx_desc_area; -+ unsigned int rx_desc_area_size; -+ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE]; -+ -+ /* Tx Descriptor area */ -+ volatile titan_ge_tx_desc *tx_desc_area; -+ unsigned int tx_desc_area_size; -+ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE]; -+ -+ /* Timeout task */ -+ struct work_struct tx_timeout_task; -+ -+ /* DMA structures and handles */ -+ dma_addr_t tx_dma; -+ dma_addr_t rx_dma; -+ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE]; -+ -+ /* Device lock */ -+ spinlock_t lock; -+ -+ unsigned int tx_ring_skbs; -+ unsigned int rx_ring_size; -+ unsigned int tx_ring_size; -+ unsigned int rx_ring_skbs; -+ -+ struct net_device_stats stats; -+ -+ /* Tx and Rx coalescing */ -+ unsigned long rx_int_coal; -+ unsigned long tx_int_coal; -+ -+ /* Threshold for replenishing the Rx and Tx rings */ -+ unsigned int tx_threshold; -+ unsigned int rx_threshold; -+ -+ /* NAPI work limit */ -+ unsigned int rx_work_limit; -+} titan_ge_port_info; -+ -+/* Titan specific constants */ -+#define TITAN_ETH_PORT_IRQ 3 -+ -+/* Max Rx buffer */ -+#define TITAN_GE_MAX_RX_BUFFER 65536 -+ -+/* Tx and Rx Error */ -+#define TITAN_GE_ERROR -+ -+/* Rx Descriptor Command and Status */ -+ -+#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */ -+#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */ -+#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */ -+#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */ -+#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */ -+#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */ -+#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */ -+#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */ -+#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */ -+#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */ -+ -+/* Tx Descriptor Command */ -+#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */ -+#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */ -+ -+/* Return Status */ -+#define TITAN_OK 0x1 /* Good Status */ -+#define TITAN_ERROR 0x2 /* Error Status */ -+ -+/* MIB specific register offset */ -+#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */ -+#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */ -+#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */ -+#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */ -+#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */ -+ -+/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */ -+#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040 -+#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050 -+#define TITAN_GE_MSTATX_RXFRAMES 0x0060 -+#define TITAN_GE_MSTATX_RXOCTETS 0x0070 -+#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080 -+#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090 -+#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0 -+#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0 -+#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0 -+#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0 -+#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0 -+#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0 -+#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100 -+#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110 -+#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120 -+#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130 -+#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140 -+#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150 -+#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160 -+#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170 -+#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180 -+#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190 -+#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0 -+#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0 -+#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0 -+#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0 -+#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0 -+#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0 -+#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200 -+#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210 -+#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220 -+#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230 -+#define TITAN_GE_MSTATX_HASHFILTERED 0x0240 -+#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250 -+#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260 -+#define TITAN_GE_MSTATX_TXOCTETS 0x0270 -+#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280 -+#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290 -+#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0 -+#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0 -+#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0 -+#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0 -+#define TITAN_GE_MSTATX_TXMACERROR 0x02E0 -+#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0 -+#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300 -+#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310 -+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320 -+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330 -+#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340 -+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350 -+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360 -+#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370 -+#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380 -+#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390 -+#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0 -+#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0 -+#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0 -+#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0 -+#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0 -+#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0 -+#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400 -+#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410 -+#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420 -+#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430 -+#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440 -+ -+/* Interrupt specific defines */ -+#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */ -+#define TITAN_GE_RESET 0x0004 /* Reset reg */ -+#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */ -+#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */ -+#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */ -+#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/ -+#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/ -+#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */ -+#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */ -+#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/ -+#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */ -+#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/ -+#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */ -+#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */ -+#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */ -+#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */ -+#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */ -+#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */ -+#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */ -+#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */ -+ -+/* Rx MAC defines */ -+#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */ -+#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */ -+#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */ -+#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */ -+#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */ -+#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */ -+#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */ -+ -+/* Tx MAC defines */ -+#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */ -+#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */ -+#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */ -+#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */ -+#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */ -+#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */ -+#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */ -+#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */ -+#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */ -+#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */ -+ -+/* GMII register */ -+#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */ -+#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */ -+#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */ -+ -+/* Tx and Rx XDMA defines */ -+#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */ -+#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */ -+#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */ -+#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */ -+#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */ -+#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */ -+#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */ -+#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */ -+ -+/* AFX (Address Filter Exact) register offsets for Slice 0 */ -+#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/ -+#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/ -+#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */ -+#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */ -+#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */ -+#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */ -+#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */ -+#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */ -+ -+/* Traffic Groomer block */ -+#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */ -+ -+#endif /* _TITAN_GE_H_ */ -+ -diff --git a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c -new file mode 100644 -index 0000000..8a8785b ---- /dev/null -+++ b/drivers/net/titan_mdio.c -@@ -0,0 +1,217 @@ -+/* -+ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports -+ * -+ * Copyright (C) 2003 PMC-Sierra Inc. -+ * Author : Manish Lachwani (lachwani@pmc-sierra.com) -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY -+ * on the Titan. No support for the TBI as yet. -+ * -+ */ -+ -+#include "titan_mdio.h" -+ -+#define MDIO_DEBUG -+ -+/* -+ * Local constants -+ */ -+#define MAX_CLKA 1023 -+#define MAX_PHY_DEV 31 -+#define MAX_PHY_REG 31 -+#define WRITEADDRS_OPCODE 0x0 -+#define READ_OPCODE 0x2 -+#define WRITE_OPCODE 0x1 -+#define MAX_MDIO_POLL 100 -+ -+/* -+ * Titan MDIO and SCMB registers -+ */ -+#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */ -+#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */ -+#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */ -+#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */ -+#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */ -+#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */ -+ -+/* -+ * Function to poll the MDIO -+ */ -+static int titan_ge_mdio_poll(void) -+{ -+ int i, val; -+ -+ for (i = 0; i < MAX_MDIO_POLL; i++) { -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ -+ if (!(val & 0x8000)) -+ return TITAN_GE_MDIO_GOOD; -+ } -+ -+ return TITAN_GE_MDIO_ERROR; -+} -+ -+ -+/* -+ * Initialize and configure the MDIO -+ */ -+int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio) -+{ -+ unsigned long val; -+ -+ /* Reset the SCMB and program into MDIO mode*/ -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000); -+ -+ /* CLK A */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA); -+ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val); -+ -+ /* Preamble Suppresion */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ /* MDIO mode */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Set the PHY address in indirect mode -+ */ -+int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr) -+{ -+ volatile unsigned long val; -+ -+ /* Setup the PHY device */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ /* Write the new address */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Read the MDIO register. This is what the individual parametes mean: -+ * -+ * dev_addr : PHY ID -+ * reg_addr : register offset -+ * -+ * See the spec for the Titan MAC. We operate in the Direct Mode. -+ */ -+ -+#define MAX_RETRIES 2 -+ -+int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata) -+{ -+ volatile unsigned long val; -+ int retries = 0; -+ -+ /* Setup the PHY device */ -+ -+again: -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ val |= 0x4000; -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ udelay(30); -+ -+ /* Issue the read command */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ udelay(30); -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA); -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); -+ -+ udelay(30); -+ -+ if (val & 0x2) { -+ if (retries == MAX_RETRIES) -+ return TITAN_GE_MDIO_ERROR; -+ else { -+ retries++; -+ goto again; -+ } -+ } -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Write to the MDIO register -+ * -+ * dev_addr : PHY ID -+ * reg_addr : register that needs to be written to -+ * -+ */ -+int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data) -+{ -+ volatile unsigned long val; -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ /* Setup the PHY device */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ val |= 0x4000; -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ udelay(30); -+ -+ /* Setup the data to write */ -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data); -+ -+ udelay(30); -+ -+ /* Issue the write command */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ udelay(30); -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); -+ if (val & 0x2) -+ return TITAN_GE_MDIO_ERROR; -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -diff --git a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h -new file mode 100644 -index 0000000..5d23344 ---- /dev/null -+++ b/drivers/net/titan_mdio.h -@@ -0,0 +1,56 @@ -+/* -+ * MDIO used to interact with the PHY when using GMII/MII -+ */ -+#ifndef _TITAN_MDIO_H -+#define _TITAN_MDIO_H -+ -+#include -+#include -+#include -+#include "titan_ge.h" -+ -+ -+#define TITAN_GE_MDIO_ERROR (-9000) -+#define TITAN_GE_MDIO_GOOD 0 -+ -+#define TITAN_GE_MDIO_BASE titan_ge_base -+ -+#define TITAN_GE_MDIO_READ(offset) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) -+ -+#define TITAN_GE_MDIO_WRITE(offset, data) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) = (data) -+ -+ -+/* GMII specific registers */ -+#define TITAN_GE_MARVEL_PHY_ID 0x00 -+#define TITAN_PHY_AUTONEG_ADV 0x04 -+#define TITAN_PHY_LP_ABILITY 0x05 -+#define TITAN_GE_MDIO_MII_CTRL 0x09 -+#define TITAN_GE_MDIO_MII_EXTENDED 0x0f -+#define TITAN_GE_MDIO_PHY_CTRL 0x10 -+#define TITAN_GE_MDIO_PHY_STATUS 0x11 -+#define TITAN_GE_MDIO_PHY_IE 0x12 -+#define TITAN_GE_MDIO_PHY_IS 0x13 -+#define TITAN_GE_MDIO_PHY_LED 0x18 -+#define TITAN_GE_MDIO_PHY_LED_OVER 0x19 -+#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */ -+ -+/* -+ * MDIO Config Structure -+ */ -+typedef struct { -+ unsigned int clka; -+ int mdio_spre; -+ int mdio_mode; -+} titan_ge_mdio_config; -+ -+/* -+ * Function Prototypes -+ */ -+int titan_ge_mdio_setup(titan_ge_mdio_config *); -+int titan_ge_mdio_inaddrs(int, int); -+int titan_ge_mdio_read(int, int, unsigned int *); -+int titan_ge_mdio_write(int, int, unsigned int); -+ -+#endif /* _TITAN_MDIO_H */ -diff --git a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -index 3411671..4d252c1 100644 ---- a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -+++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -@@ -22,6 +22,10 @@ - - static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) - { -+#ifdef CONFIG_LEMOTE_MACH2F -+ /* Allow users to activate rfkill through only the /sys interface */ -+ return 1; -+#else - u8 gpio; - - gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); -@@ -29,6 +33,7 @@ static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) - gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); - - return gpio & priv->rfkill_mask; -+#endif - } - - void rtl8187_rfkill_init(struct ieee80211_hw *hw) -diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig -index 09fde58..eacabd1 100644 ---- a/drivers/platform/Kconfig -+++ b/drivers/platform/Kconfig -@@ -4,5 +4,8 @@ endif - if GOLDFISH - source "drivers/platform/goldfish/Kconfig" - endif -+if MIPS -+source "drivers/platform/mips/Kconfig" -+endif - - source "drivers/platform/chrome/Kconfig" -diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile -index 3656b7b..ca26925 100644 ---- a/drivers/platform/Makefile -+++ b/drivers/platform/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_X86) += x86/ -+obj-$(CONFIG_MIPS) += mips/ - obj-$(CONFIG_OLPC) += olpc/ - obj-$(CONFIG_GOLDFISH) += goldfish/ - obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ -diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig -new file mode 100644 -index 0000000..722d690 ---- /dev/null -+++ b/drivers/platform/mips/Kconfig -@@ -0,0 +1,60 @@ -+# -+# MIPS Platform Specific Drivers -+# -+ -+menuconfig MIPS_PLATFORM_DEVICES -+ bool "MIPS Platform Specific Device Drivers" -+ default y -+ help -+ Say Y here to get to see options for device drivers of various -+ MIPS platforms, including vendor-specific netbook/laptop/pc extension -+ drivers. This option alone does not add any kernel code. -+ -+ If you say N, all options in this submenu will be skipped and disabled. -+ -+if MIPS_PLATFORM_DEVICES -+ -+config LEMOTE_YEELOONG2F -+ tristate "Lemote YeeLoong Laptop" -+ depends on LEMOTE_MACH2F -+ select BACKLIGHT_LCD_SUPPORT -+ select LCD_CLASS_DEVICE -+ select BACKLIGHT_CLASS_DEVICE -+ select POWER_SUPPLY -+ select HWMON -+ select VIDEO_OUTPUT_CONTROL -+ select INPUT_SPARSEKMAP -+ select INPUT_EVDEV -+ depends on INPUT -+ default m -+ help -+ YeeLoong netbook is a mini laptop made by Lemote, which is basically -+ compatible to FuLoong2F mini PC, but it has an extra Embedded -+ Controller(kb3310b) for battery, hotkey, backlight, temperature and -+ fan management. -+ -+config LEMOTE_LYNLOONG2F -+ tristate "Lemote LynLoong PC" -+ depends on LEMOTE_MACH2F -+ select BACKLIGHT_LCD_SUPPORT -+ select BACKLIGHT_CLASS_DEVICE -+ select VIDEO_OUTPUT_CONTROL -+ default m -+ help -+ LynLoong PC is an AllINONE machine made by Lemote, which is basically -+ compatible to FuLoong2F Mini PC, the only difference is that it has a -+ size-fixed screen: 1360x768 with sisfb video driver. and also, it has -+ its own specific suspend support. -+ -+config GDIUM_LAPTOP -+ tristate "GDIUM laptop extras" -+ depends on DEXXON_GDIUM -+ select POWER_SUPPLY -+ select I2C -+ select INPUT_POLLDEV -+ default m -+ help -+ This mini-driver drives the ST7 chipset present in the Gdium laptops. -+ This gives battery support, wlan rfkill. -+ -+endif # MIPS_PLATFORM_DEVICES -diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile -new file mode 100644 -index 0000000..f013e78 ---- /dev/null -+++ b/drivers/platform/mips/Makefile -@@ -0,0 +1,9 @@ -+# -+# Makefile for MIPS Platform-Specific Drivers -+# -+ -+obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o # yeeloong_ecrom.o -+CFLAGS_yeeloong_laptop.o = -I$(srctree)/arch/mips/loongson/lemote-2f -+ -+obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o -+obj-$(CONFIG_GDIUM_LAPTOP) += gdium_laptop.o -diff --git a/drivers/platform/mips/gdium_laptop.c b/drivers/platform/mips/gdium_laptop.c -new file mode 100644 -index 0000000..41a65ad ---- /dev/null -+++ b/drivers/platform/mips/gdium_laptop.c -@@ -0,0 +1,927 @@ -+/* -+ * gdium_laptop -- Gdium laptop extras -+ * -+ * Arnaud Patard -+ * -+ * 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. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* For input device */ -+#define SCAN_INTERVAL 150 -+ -+/* For battery status */ -+#define BAT_SCAN_INTERVAL 500 -+ -+#define EC_FIRM_VERSION 0 -+ -+#if CONFIG_GDIUM_VERSION > 2 -+#define EC_REG_BASE 1 -+#else -+#define EC_REG_BASE 0 -+#endif -+ -+#define EC_STATUS (EC_REG_BASE+0) -+#define EC_STATUS_LID (1<<0) -+#define EC_STATUS_PWRBUT (1<<1) -+#define EC_STATUS_BATID (1<<2) /* this bit has no real meaning on v2. */ -+ /* Same as EC_STATUS_ADAPT */ -+ /* but on v3 it's BATID which mean bat present */ -+#define EC_STATUS_SYS_POWER (1<<3) -+#define EC_STATUS_WLAN (1<<4) -+#define EC_STATUS_ADAPT (1<<5) -+ -+#define EC_CTRL (EC_REG_BASE+1) -+#define EC_CTRL_DDR_CLK (1<<0) -+#define EC_CTRL_CHARGE_LED (1<<1) -+#define EC_CTRL_BEEP (1<<2) -+#define EC_CTRL_SUSB (1<<3) /* memory power */ -+#define EC_CTRL_TRICKLE (1<<4) -+#define EC_CTRL_WLAN_EN (1<<5) -+#define EC_CTRL_SUSC (1<<6) /* main power */ -+#define EC_CTRL_CHARGE_EN (1<<7) -+ -+#define EC_BAT_LOW (EC_REG_BASE+2) -+#define EC_BAT_HIGH (EC_REG_BASE+3) -+ -+#define EC_SIGN (EC_REG_BASE+4) -+#define EC_SIGN_OS 0xAE /* write 0xae to control pm stuff */ -+#define EC_SIGN_EC 0x00 /* write 0x00 to let the st7 manage pm stuff */ -+ -+#if 0 -+#define EC_TEST (EC_REG_BASE+5) /* Depending on firmware version this register */ -+ /* may be the programmation register so don't play */ -+ /* with it */ -+#endif -+ -+#define BAT_VOLT_PRESENT 500000 /* Min voltage to consider battery present uV */ -+#define BAT_MIN 7000000 /* Min battery voltage in uV */ -+#define BAT_MIN_MV 7000 /* Min battery voltage in mV */ -+#define BAT_TRICKLE_EN 8000000 /* Charging at 1.4A before 8.0V and then charging at 0.25A */ -+#define BAT_MAX 7950000 /* Max battery voltage ~8V in V */ -+#define BAT_MAX_MV 7950 /* Max battery voltage ~8V in V */ -+#define BAT_READ_ERROR 300000 /* battery read error of 0.3V */ -+#define BAT_READ_ERROR_MV 300 /* battery read error of 0.3V */ -+ -+#define SM502_WLAN_ON (224+16)/* SM502 GPIO16 may be used on gdium v2 (v3?) as wlan_on */ -+ /* when R422 is connected */ -+ -+static unsigned char verbose; -+static unsigned char gpio16; -+static unsigned char ec; -+module_param(verbose, byte, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(verbose, "Add some debugging messages"); -+module_param(gpio16, byte, S_IRUGO); -+MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502"); -+module_param(ec, byte, S_IRUGO); -+MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)"); -+ -+struct gdium_laptop_data { -+ struct i2c_client *client; -+ struct input_polled_dev *input_polldev; -+ struct dentry *debugfs; -+ struct mutex mutex; -+ struct platform_device *bat_pdev; -+ struct power_supply gdium_ac; -+ struct power_supply gdium_battery; -+ struct workqueue_struct *workqueue; -+ struct delayed_work work; -+ char charge_cmd; -+ /* important registers value */ -+ char status; -+ char ctrl; -+ /* mV */ -+ int battery_level; -+ char version; -+}; -+ -+/**********************************************************************/ -+/* Low level I2C functions */ -+/* All are supposed to be called with mutex held */ -+/**********************************************************************/ -+/* -+ * Return battery voltage in mV -+ * >= 0 battery voltage -+ * < 0 error -+ */ -+static s32 ec_read_battery(struct i2c_client *client) -+{ -+ unsigned char bat_low, bat_high; -+ s32 data; -+ unsigned int ret; -+ -+ /* -+ * a = battery high -+ * b = battery low -+ * bat = a << 2 | b & 0x03; -+ * battery voltage = (bat / 1024) * 5 * 2 -+ */ -+ data = i2c_smbus_read_byte_data(client, EC_BAT_LOW); -+ if (data < 0) { -+ dev_err(&client->dev, "ec_read_bat: read bat_low failed\n"); -+ return data; -+ } -+ bat_low = data & 0xff; -+ if (verbose) -+ dev_info(&client->dev, "bat_low %x\n", bat_low); -+ -+ data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH); -+ if (data < 0) { -+ dev_err(&client->dev, "ec_read_bat: read bat_high failed\n"); -+ return data; -+ } -+ bat_high = data & 0xff; -+ if (verbose) -+ dev_info(&client->dev, "bat_high %x\n", bat_high); -+ -+ ret = (bat_high << 2) | (bat_low & 3); -+ /* -+ * mV -+ */ -+ ret = (ret * 5 * 2) * 1000 / 1024; -+ -+ return ret; -+} -+ -+static s32 ec_read_version(struct i2c_client *client) -+{ -+#if CONFIG_GDIUM_VERSION > 2 -+ return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION); -+#else -+ return 0; -+#endif -+} -+ -+static s32 ec_read_status(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_STATUS); -+} -+ -+static s32 ec_read_ctrl(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_CTRL); -+} -+ -+static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue) -+{ -+ return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue); -+} -+ -+static s32 ec_read_sign(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_SIGN); -+} -+ -+static s32 ec_write_sign(struct i2c_client *client, unsigned char sign) -+{ -+ unsigned char value; -+ s32 ret; -+ -+ ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign); -+ if (ret < 0) { -+ dev_err(&client->dev, "ec_set_control: write failed\n"); -+ return ret; -+ } -+ -+ value = ec_read_sign(client); -+ if (value != sign) { -+ dev_err(&client->dev, "Failed to set control to %s\n", -+ sign == EC_SIGN_OS ? "OS" : "EC"); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+#if 0 -+static int ec_power_off(struct i2c_client *client) -+{ -+ char value; -+ int ret; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) { -+ dev_err(&client->dev, "ec_power_off: read failed\n"); -+ return value; -+ } -+ value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC); -+ ret = ec_write_ctrl(client, value); -+ if (ret < 0) { -+ dev_err(&client->dev, "ec_power_off: write failed\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+#endif -+ -+static s32 ec_wlan_status(struct i2c_client *client) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ return (value & EC_CTRL_WLAN_EN) ? 1 : 0; -+} -+ -+static s32 ec_wlan_en(struct i2c_client *client, int on) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ value &= ~EC_CTRL_WLAN_EN; -+ if (on) -+ value |= EC_CTRL_WLAN_EN; -+ -+ return ec_write_ctrl(client, value&0xff); -+} -+ -+#if 0 -+static s32 ec_led_status(struct i2c_client *client) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ return (value & EC_CTRL_CHARGE_LED) ? 1 : 0; -+} -+#endif -+ -+/* Changing the charging led status has never worked */ -+static s32 ec_led_en(struct i2c_client *client, int on) -+{ -+#if 0 -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ value &= ~EC_CTRL_CHARGE_LED; -+ if (on) -+ value |= EC_CTRL_CHARGE_LED; -+ return ec_write_ctrl(client, value&0xff); -+#else -+ return 0; -+#endif -+} -+ -+static s32 ec_charge_en(struct i2c_client *client, int on, int trickle) -+{ -+ s32 value; -+ s32 set = 0; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ if (on) -+ set |= EC_CTRL_CHARGE_EN; -+ if (trickle) -+ set |= EC_CTRL_TRICKLE; -+ -+ /* Be clever : don't change values if you don't need to */ -+ if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set) -+ return 0; -+ -+ value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE); -+ value |= set; -+ ec_led_en(client, on); -+ return ec_write_ctrl(client, (unsigned char)(value&0xff)); -+ -+} -+ -+/**********************************************************************/ -+/* Input functions */ -+/**********************************************************************/ -+struct gdium_keys { -+ int last_state; -+ int key_code; -+ int mask; -+ int type; -+}; -+ -+static struct gdium_keys gkeys[] = { -+ { -+ .key_code = KEY_WLAN, -+ .mask = EC_STATUS_WLAN, -+ .type = EV_KEY, -+ }, -+ { -+ .key_code = KEY_POWER, -+ .mask = EC_STATUS_PWRBUT, -+ .type = EV_KEY, /*EV_PWR,*/ -+ }, -+ { -+ .key_code = SW_LID, -+ .mask = EC_STATUS_LID, -+ .type = EV_SW, -+ }, -+}; -+ -+static void gdium_laptop_keys_poll(struct input_polled_dev *dev) -+{ -+ int state, i; -+ struct gdium_laptop_data *data = dev->private; -+ struct i2c_client *client = data->client; -+ struct input_dev *input = dev->input; -+ s32 status; -+ -+ mutex_lock(&data->mutex); -+ status = ec_read_status(client); -+ mutex_unlock(&data->mutex); -+ -+ if (status < 0) { -+ /* -+ * Don't know exactly which version of the firmware -+ * has this bug but when the power button is pressed -+ * there are i2c read errors :( -+ */ -+ if ((data->version >= 0x13) && !gkeys[1].last_state) { -+ input_event(input, EV_KEY, KEY_POWER, 1); -+ input_sync(input); -+ gkeys[1].last_state = 1; -+ } -+ return; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(gkeys); i++) { -+ state = status & gkeys[i].mask; -+ if (state != gkeys[i].last_state) { -+ gkeys[i].last_state = state; -+ /* for power key, we want power & key press/release event */ -+ if (gkeys[i].type == EV_PWR) { -+ input_event(input, EV_KEY, gkeys[i].key_code, !!state); -+ input_sync(input); -+ } -+ /* Disable wifi on key press but not key release */ -+ /* -+ * On firmware >= 0x13 the EC_STATUS_WLAN has it's -+ * original meaning of Wifi status and no more the -+ * wifi button status so we have to ignore the event -+ * on theses versions -+ */ -+ if (state && (gkeys[i].key_code == KEY_WLAN) && (data->version < 0x13)) { -+ mutex_lock(&data->mutex); -+ ec_wlan_en(client, !ec_wlan_status(client)); -+ if (gpio16) -+ gpio_set_value(SM502_WLAN_ON, !ec_wlan_status(client)); -+ mutex_unlock(&data->mutex); -+ } -+ -+ input_event(input, gkeys[i].type, gkeys[i].key_code, !!state); -+ input_sync(input); -+ } -+ } -+} -+ -+static int gdium_laptop_input_init(struct gdium_laptop_data *data) -+{ -+ struct i2c_client *client = data->client; -+ struct input_dev *input; -+ int ret, i; -+ -+ data->input_polldev = input_allocate_polled_device(); -+ if (!data->input_polldev) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ input = data->input_polldev->input; -+ input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW); -+ data->input_polldev->poll = gdium_laptop_keys_poll; -+ data->input_polldev->poll_interval = SCAN_INTERVAL; -+ data->input_polldev->private = data; -+ input->name = "gdium-keys"; -+ input->dev.parent = &client->dev; -+ -+ input->id.bustype = BUS_HOST; -+ input->id.vendor = 0x0001; -+ input->id.product = 0x0001; -+ input->id.version = 0x0100; -+ -+ for (i = 0; i < ARRAY_SIZE(gkeys); i++) -+ input_set_capability(input, gkeys[i].type, gkeys[i].key_code); -+ -+ ret = input_register_polled_device(data->input_polldev); -+ if (ret) { -+ dev_err(&client->dev, "Unable to register button device\n"); -+ goto err_poll_dev; -+ } -+ -+ return 0; -+ -+err_poll_dev: -+ input_free_polled_device(data->input_polldev); -+err: -+ return ret; -+} -+ -+static void gdium_laptop_input_exit(struct gdium_laptop_data *data) -+{ -+ input_unregister_polled_device(data->input_polldev); -+ input_free_polled_device(data->input_polldev); -+} -+ -+/**********************************************************************/ -+/* Battery management */ -+/**********************************************************************/ -+static int gdium_ac_get_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ char status; -+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_ac); -+ int ret = 0; -+ -+ if (!data) { -+ pr_err("gdium-ac: gdium_laptop_data not found\n"); -+ return -EINVAL; -+ } -+ -+ status = data->status; -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ val->intval = !!(status & EC_STATUS_ADAPT); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+#undef RET -+#define RET (val->intval) -+ -+static int gdium_battery_get_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ char status, ctrl; -+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_battery); -+ int percentage_capacity = 0, charge_now = 0, time_to_empty = 0; -+ int ret = 0, tmp; -+ -+ if (!data) { -+ pr_err("gdium-battery: gdium_laptop_data not found\n"); -+ return -EINVAL; -+ } -+ -+ status = data->status; -+ ctrl = data->ctrl; -+ switch (psp) { -+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: -+ /* uAh */ -+ RET = 5000000; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: -+ /* This formula is gotten by gnuplot with the statistic data */ -+ time_to_empty = (data->battery_level - BAT_MIN_MV + BAT_READ_ERROR_MV) * 113 - 29870; -+ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) { -+ /* seconds */ -+ RET = time_to_empty / 10; -+ break; -+ } -+ /* fall through */ -+ case POWER_SUPPLY_PROP_CHARGE_NOW: -+ case POWER_SUPPLY_PROP_CAPACITY: { -+ tmp = data->battery_level * 1000; -+ /* > BAT_MIN to avoid negative values */ -+ percentage_capacity = 0; -+ if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN)) -+ percentage_capacity = (tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN); -+ -+ if (percentage_capacity > 100) -+ percentage_capacity = 100; -+ -+ if (psp == POWER_SUPPLY_PROP_CAPACITY) { -+ RET = percentage_capacity; -+ break; -+ } -+ charge_now = 50000 * percentage_capacity; -+ if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) { -+ /* uAh */ -+ RET = charge_now; -+ break; -+ } -+ } /* fall through */ -+ case POWER_SUPPLY_PROP_STATUS: { -+ if (status & EC_STATUS_ADAPT) -+ if (ctrl & EC_CTRL_CHARGE_EN) -+ RET = POWER_SUPPLY_STATUS_CHARGING; -+ else -+ RET = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ else -+ RET = POWER_SUPPLY_STATUS_DISCHARGING; -+ -+ if (psp == POWER_SUPPLY_PROP_STATUS) -+ break; -+ /* mAh -> µA */ -+ switch (RET) { -+ case POWER_SUPPLY_STATUS_CHARGING: -+ RET = -(data->charge_cmd == 2) ? 1400000 : 250000; -+ break; -+ case POWER_SUPPLY_STATUS_DISCHARGING: -+ RET = charge_now / time_to_empty * 36000; -+ break; -+ case POWER_SUPPLY_STATUS_NOT_CHARGING: -+ default: -+ RET = 0; -+ break; -+ } -+ } break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ RET = BAT_MAX+BAT_READ_ERROR; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: -+ RET = BAT_MIN-BAT_READ_ERROR; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ /* mV -> uV */ -+ RET = data->battery_level * 1000; -+ break; -+ case POWER_SUPPLY_PROP_PRESENT: -+#if CONFIG_GDIUM_VERSION > 2 -+ RET = !!(status & EC_STATUS_BATID); -+#else -+ RET = !!(data->battery_level > BAT_VOLT_PRESENT); -+#endif -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: -+ tmp = data->battery_level * 1000; -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ if (status & EC_STATUS_BATID) { -+ if (tmp >= BAT_MAX) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; -+ if (tmp >= BAT_MAX+BAT_READ_ERROR) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; -+ } else if (tmp <= BAT_MIN+BAT_READ_ERROR) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; -+ if (tmp <= BAT_MIN) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; -+ } else -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; -+ } -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_TYPE: -+ if (ctrl & EC_CTRL_TRICKLE) -+ RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; -+ else if (ctrl & EC_CTRL_CHARGE_EN) -+ RET = POWER_SUPPLY_CHARGE_TYPE_FAST; -+ else -+ RET = POWER_SUPPLY_CHARGE_TYPE_NONE; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_MAX: -+ /* 1.4A ? */ -+ RET = 1400000; -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+#undef RET -+ -+static enum power_supply_property gdium_ac_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static enum power_supply_property gdium_battery_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_MAX, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_CAPACITY_LEVEL, -+ POWER_SUPPLY_PROP_CHARGE_TYPE, -+}; -+ -+static void gdium_laptop_battery_work(struct work_struct *work) -+{ -+ struct gdium_laptop_data *data = container_of(work, struct gdium_laptop_data, work.work); -+ struct i2c_client *client; -+ int ret; -+ char old_status, old_charge_cmd; -+ char present; -+ s32 status; -+ -+ mutex_lock(&data->mutex); -+ client = data->client; -+ status = ec_read_status(client); -+ ret = ec_read_battery(client); -+ -+ if ((status < 0) || (ret < 0)) -+ goto i2c_read_error; -+ -+ old_status = data->status; -+ old_charge_cmd = data->charge_cmd; -+ data->status = status; -+ -+ /* -+ * Charge only if : -+ * - battery present -+ * - ac adapter plugged in -+ * - battery not fully charged -+ */ -+#if CONFIG_GDIUM_VERSION > 2 -+ present = !!(data->status & EC_STATUS_BATID); -+#else -+ present = !!(ret > BAT_VOLT_PRESENT); -+#endif -+ data->battery_level = 0; -+ if (present) { -+ data->battery_level = (unsigned int)ret; -+ if (data->status & EC_STATUS_ADAPT) -+ data->battery_level -= BAT_READ_ERROR_MV; -+ } -+ -+ data->charge_cmd = 0; -+ if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level <= BAT_MAX_MV)) -+ data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3; -+ -+ ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1); -+ -+ /* -+ * data->ctrl must be set _after_ calling ec_charge_en as this will change the -+ * control register content -+ */ -+ data->ctrl = ec_read_ctrl(client); -+ -+ if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) { -+ power_supply_changed(&data->gdium_ac); -+ /* Send charging/discharging state change */ -+ power_supply_changed(&data->gdium_battery); -+ } else if ((data->status & EC_STATUS_ADAPT) && -+ ((old_charge_cmd&2) != (data->charge_cmd&2))) -+ power_supply_changed(&data->gdium_battery); -+ -+i2c_read_error: -+ mutex_unlock(&data->mutex); -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+} -+ -+static int gdium_laptop_battery_init(struct gdium_laptop_data *data) -+{ -+ int ret; -+ -+ data->bat_pdev = platform_device_register_simple("gdium-battery", 0, NULL, 0); -+ if (IS_ERR(data->bat_pdev)) -+ return PTR_ERR(data->bat_pdev); -+ -+ data->gdium_battery.name = data->bat_pdev->name; -+ data->gdium_battery.properties = gdium_battery_props; -+ data->gdium_battery.num_properties = ARRAY_SIZE(gdium_battery_props); -+ data->gdium_battery.get_property = gdium_battery_get_props; -+ data->gdium_battery.use_for_apm = 1; -+ -+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery); -+ if (ret) -+ goto err_platform; -+ -+ data->gdium_ac.name = "gdium-ac"; -+ data->gdium_ac.type = POWER_SUPPLY_TYPE_MAINS; -+ data->gdium_ac.properties = gdium_ac_props; -+ data->gdium_ac.num_properties = ARRAY_SIZE(gdium_ac_props); -+ data->gdium_ac.get_property = gdium_ac_get_props; -+/* data->gdium_ac.use_for_apm_ac = 1, */ -+ -+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac); -+ if (ret) -+ goto err_battery; -+ -+ if (!ec) { -+ INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work); -+ data->workqueue = create_singlethread_workqueue("gdium-battery-work"); -+ if (!data->workqueue) { -+ ret = -ESRCH; -+ goto err_work; -+ } -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+ } -+ -+ return 0; -+ -+err_work: -+err_battery: -+ power_supply_unregister(&data->gdium_battery); -+err_platform: -+ platform_device_unregister(data->bat_pdev); -+ -+ return ret; -+} -+static void gdium_laptop_battery_exit(struct gdium_laptop_data *data) -+{ -+ if (!ec) { -+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); -+ destroy_workqueue(data->workqueue); -+ } -+ power_supply_unregister(&data->gdium_battery); -+ power_supply_unregister(&data->gdium_ac); -+ platform_device_unregister(data->bat_pdev); -+} -+ -+/* Debug fs */ -+static int gdium_laptop_regs_show(struct seq_file *s, void *p) -+{ -+ struct gdium_laptop_data *data = s->private; -+ struct i2c_client *client = data->client; -+ -+ mutex_lock(&data->mutex); -+ seq_printf(s, "Version : 0x%02x\n", (unsigned char)ec_read_version(client)); -+ seq_printf(s, "Status : 0x%02x\n", (unsigned char)ec_read_status(client)); -+ seq_printf(s, "Ctrl : 0x%02x\n", (unsigned char)ec_read_ctrl(client)); -+ seq_printf(s, "Sign : 0x%02x\n", (unsigned char)ec_read_sign(client)); -+ seq_printf(s, "Bat Lo : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_LOW)); -+ seq_printf(s, "Bat Hi : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH)); -+ seq_printf(s, "Battery : %d uV\n", (unsigned int)ec_read_battery(client) * 1000); -+ seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", data->charge_cmd & 1 ? "T" : " "); -+ -+ mutex_unlock(&data->mutex); -+ return 0; -+} -+ -+static int gdium_laptop_regs_open(struct inode *inode, -+ struct file *file) -+{ -+ return single_open(file, gdium_laptop_regs_show, inode->i_private); -+} -+ -+static const struct file_operations gdium_laptop_regs_fops = { -+ .open = gdium_laptop_regs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+ -+ -+static int gdium_laptop_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct gdium_laptop_data *data; -+ int ret; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -+ dev_err(&client->dev, -+ "%s: no smbus_byte support !\n", __func__); -+ return -ENODEV; -+ } -+ -+ data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(client, data); -+ data->client = client; -+ mutex_init(&data->mutex); -+ -+ ret = ec_read_version(client); -+ if (ret < 0) -+ goto err_alloc; -+ -+ data->version = (unsigned char)ret; -+ -+ ret = gdium_laptop_input_init(data); -+ if (ret) -+ goto err_alloc; -+ -+ ret = gdium_laptop_battery_init(data); -+ if (ret) -+ goto err_input; -+ -+ -+ if (!ec) { -+ ret = ec_write_sign(client, EC_SIGN_OS); -+ if (ret) -+ goto err_sign; -+ } -+ -+ if (gpio16) { -+ ret = gpio_request(SM502_WLAN_ON, "wlan-on"); -+ if (ret < 0) -+ goto err_sign; -+ gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client)); -+ gpio_direction_output(SM502_WLAN_ON, 1); -+ } -+ -+ dev_info(&client->dev, "Found firmware 0x%02x\n", data->version); -+ data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO, -+ NULL, data, &gdium_laptop_regs_fops); -+ -+ return 0; -+ -+err_sign: -+ gdium_laptop_battery_exit(data); -+err_input: -+ gdium_laptop_input_exit(data); -+err_alloc: -+ kfree(data); -+ return ret; -+} -+ -+static int gdium_laptop_remove(struct i2c_client *client) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (gpio16) -+ gpio_free(SM502_WLAN_ON); -+ ec_write_sign(client, EC_SIGN_EC); -+ if (data->debugfs) -+ debugfs_remove(data->debugfs); -+ -+ gdium_laptop_battery_exit(data); -+ gdium_laptop_input_exit(data); -+ -+ kfree(data); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (!ec) -+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); -+ return 0; -+} -+ -+static int gdium_laptop_resume(struct i2c_client *client) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (!ec) -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+ return 0; -+} -+#else -+#define gdium_laptop_suspend NULL -+#define gdium_laptop_resume NULL -+#endif -+static const struct i2c_device_id gdium_id[] = { -+ { "gdium-laptop" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(i2c, gdium_id); -+ -+static struct i2c_driver gdium_laptop_driver = { -+ .driver = { -+ .name = "gdium-laptop", -+ .owner = THIS_MODULE, -+ }, -+ .probe = gdium_laptop_probe, -+ .remove = gdium_laptop_remove, -+ .shutdown = gdium_laptop_remove, -+ .suspend = gdium_laptop_suspend, -+ .resume = gdium_laptop_resume, -+ .id_table = gdium_id, -+}; -+ -+static int __init gdium_laptop_init(void) -+{ -+ return i2c_add_driver(&gdium_laptop_driver); -+} -+ -+static void __exit gdium_laptop_exit(void) -+{ -+ i2c_del_driver(&gdium_laptop_driver); -+} -+ -+module_init(gdium_laptop_init); -+module_exit(gdium_laptop_exit); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("Gdium laptop extras"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/lynloong_pc.c b/drivers/platform/mips/lynloong_pc.c -new file mode 100644 -index 0000000..68f29e4 ---- /dev/null -+++ b/drivers/platform/mips/lynloong_pc.c -@@ -0,0 +1,515 @@ -+/* -+ * Driver for LynLoong PC extras -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin , Xiang Yu -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include /* for backlight subdriver */ -+#include -+#include /* for video output subdriver */ -+#include /* for suspend support */ -+ -+#include -+#include -+ -+#include -+ -+static u32 gpio_base, mfgpt_base; -+ -+static void set_gpio_reg_high(int gpio, int reg) -+{ -+ u32 val; -+ -+ val = inl(gpio_base + reg); -+ val |= (1 << gpio); -+ val &= ~(1 << (16 + gpio)); -+ outl(val, gpio_base + reg); -+ mmiowb(); -+} -+ -+static void set_gpio_reg_low(int gpio, int reg) -+{ -+ u32 val; -+ -+ val = inl(gpio_base + reg); -+ val |= (1 << (16 + gpio)); -+ val &= ~(1 << gpio); -+ outl(val, gpio_base + reg); -+ mmiowb(); -+} -+ -+static void set_gpio_output_low(int gpio) -+{ -+ set_gpio_reg_high(gpio, GPIOL_OUT_EN); -+ set_gpio_reg_low(gpio, GPIOL_OUT_VAL); -+} -+ -+static void set_gpio_output_high(int gpio) -+{ -+ set_gpio_reg_high(gpio, GPIOL_OUT_EN); -+ set_gpio_reg_high(gpio, GPIOL_OUT_VAL); -+} -+ -+/* backlight subdriver */ -+ -+#define MAX_BRIGHTNESS 100 -+#define DEFAULT_BRIGHTNESS 50 -+#define MIN_BRIGHTNESS 0 -+static unsigned int level; -+ -+DEFINE_SPINLOCK(backlight_lock); -+/* Tune the brightness */ -+static void setup_mfgpt2(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&backlight_lock, flags); -+ -+ /* Set MFGPT2 comparator 1,2 */ -+ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1); -+ outw(MAX_BRIGHTNESS, MFGPT2_CMP2); -+ /* Clear MFGPT2 UP COUNTER */ -+ outw(0, MFGPT2_CNT); -+ /* Enable counter, compare mode, 32k */ -+ outw(0x8280, MFGPT2_SETUP); -+ -+ spin_unlock_irqrestore(&backlight_lock, flags); -+} -+ -+static int lynloong_set_brightness(struct backlight_device *bd) -+{ -+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && -+ bd->props.power == FB_BLANK_UNBLANK) ? -+ bd->props.brightness : 0; -+ -+ if (level > MAX_BRIGHTNESS) -+ level = MAX_BRIGHTNESS; -+ else if (level < MIN_BRIGHTNESS) -+ level = MIN_BRIGHTNESS; -+ -+ setup_mfgpt2(); -+ -+ return 0; -+} -+ -+static int lynloong_get_brightness(struct backlight_device *bd) -+{ -+ return level; -+} -+ -+static struct backlight_ops backlight_ops = { -+ .get_brightness = lynloong_get_brightness, -+ .update_status = lynloong_set_brightness, -+}; -+ -+static struct backlight_device *lynloong_backlight_dev; -+ -+static int lynloong_backlight_init(void) -+{ -+ int ret; -+ u32 hi; -+ struct backlight_properties props; -+ -+ /* Get gpio_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); -+ /* Get mfgpt_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base); -+ /* Get gpio_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); -+ -+ /* Select for mfgpt */ -+ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL); -+ /* Enable brightness controlling */ -+ set_gpio_output_high(7); -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.max_brightness = MAX_BRIGHTNESS; -+ props.type = BACKLIGHT_PLATFORM; -+ lynloong_backlight_dev = backlight_device_register("backlight0", NULL, -+ NULL, &backlight_ops, &props); -+ -+ if (IS_ERR(lynloong_backlight_dev)) { -+ ret = PTR_ERR(lynloong_backlight_dev); -+ return ret; -+ } -+ -+ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS; -+ backlight_update_status(lynloong_backlight_dev); -+ -+ return 0; -+} -+ -+static void lynloong_backlight_exit(void) -+{ -+ if (lynloong_backlight_dev) { -+ backlight_device_unregister(lynloong_backlight_dev); -+ lynloong_backlight_dev = NULL; -+ } -+ /* Disable brightness controlling */ -+ set_gpio_output_low(7); -+} -+ -+/* video output driver */ -+static int vo_status = 1; -+ -+static int lcd_video_output_get(struct output_device *od) -+{ -+ return vo_status; -+} -+ -+static int lcd_video_output_set(struct output_device *od) -+{ -+ int i; -+ unsigned long status; -+ -+ status = !!od->request_state; -+ -+ if (status == 0) { -+ /* Set the current status as off */ -+ vo_status = 0; -+ /* Turn off the backlight */ -+ set_gpio_output_low(11); -+ for (i = 0; i < 0x500; i++) -+ delay(); -+ /* Turn off the LCD */ -+ set_gpio_output_high(8); -+ } else { -+ /* Turn on the LCD */ -+ set_gpio_output_low(8); -+ for (i = 0; i < 0x500; i++) -+ delay(); -+ /* Turn on the backlight */ -+ set_gpio_output_high(11); -+ /* Set the current status as on */ -+ vo_status = 1; -+ } -+ -+ return 0; -+} -+ -+static struct output_properties lcd_output_properties = { -+ .set_state = lcd_video_output_set, -+ .get_status = lcd_video_output_get, -+}; -+ -+static struct output_device *lcd_output_dev; -+ -+static void lynloong_lcd_vo_set(int status) -+{ -+ lcd_output_dev->request_state = status; -+ lcd_video_output_set(lcd_output_dev); -+} -+ -+static int lynloong_vo_init(void) -+{ -+ int ret; -+ -+ /* Register video output device: lcd */ -+ lcd_output_dev = video_output_register("LCD", NULL, NULL, -+ &lcd_output_properties); -+ -+ if (IS_ERR(lcd_output_dev)) { -+ ret = PTR_ERR(lcd_output_dev); -+ lcd_output_dev = NULL; -+ return ret; -+ } -+ /* Ensure LCD is on by default */ -+ lynloong_lcd_vo_set(1); -+ -+ return 0; -+} -+ -+static void lynloong_vo_exit(void) -+{ -+ if (lcd_output_dev) { -+ video_output_unregister(lcd_output_dev); -+ lcd_output_dev = NULL; -+ } -+} -+ -+/* suspend support */ -+ -+#ifdef CONFIG_PM -+ -+static u32 smb_base; -+ -+/* I2C operations */ -+ -+static int i2c_wait(void) -+{ -+ char c; -+ int i; -+ -+ udelay(1000); -+ for (i = 0; i < 20; i++) { -+ c = inb(smb_base | SMB_STS); -+ if (c & (SMB_STS_BER | SMB_STS_NEGACK)) -+ return -1; -+ if (c & SMB_STS_SDAST) -+ return 0; -+ udelay(100); -+ } -+ return -2; -+} -+ -+static void i2c_read_single(int addr, int regNo, char *value) -+{ -+ unsigned char c; -+ -+ /* Start condition */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ -+ /* Send slave address */ -+ outb(addr & 0xfe, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Send register index */ -+ outb(regNo, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Start condition again */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ -+ /* Send salve address again */ -+ outb(1 | addr, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Read data */ -+ *value = inb(smb_base | SMB_SDA); -+ -+ /* Stop condition */ -+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); -+ i2c_wait(); -+} -+ -+static void i2c_write_single(int addr, int regNo, char value) -+{ -+ unsigned char c; -+ -+ /* Start condition */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ /* Send slave address */ -+ outb(addr & 0xfe, smb_base | SMB_SDA); -+ i2c_wait();; -+ -+ /* Send register index */ -+ outb(regNo, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Write data */ -+ outb(value, smb_base | SMB_SDA); -+ i2c_wait(); -+ /* Stop condition */ -+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); -+ i2c_wait(); -+} -+ -+static void stop_clock(int clk_reg, int clk_sel) -+{ -+ u8 value; -+ -+ i2c_read_single(0xd3, clk_reg, &value); -+ value &= ~(1 << clk_sel); -+ i2c_write_single(0xd2, clk_reg, value); -+} -+ -+static void enable_clock(int clk_reg, int clk_sel) -+{ -+ u8 value; -+ -+ i2c_read_single(0xd3, clk_reg, &value); -+ value |= (1 << clk_sel); -+ i2c_write_single(0xd2, clk_reg, value); -+} -+ -+static char cached_clk_freq; -+static char cached_pci_fixed_freq; -+ -+static void decrease_clk_freq(void) -+{ -+ char value; -+ -+ i2c_read_single(0xd3, 1, &value); -+ cached_clk_freq = value; -+ -+ /* Select frequency by software */ -+ value |= (1 << 1); -+ /* CPU, 3V66, PCI : 100, 66, 33(1) */ -+ value |= (1 << 2); -+ i2c_write_single(0xd2, 1, value); -+ -+ /* Cache the pci frequency */ -+ i2c_read_single(0xd3, 14, &value); -+ cached_pci_fixed_freq = value; -+ -+ /* Enable PCI fix mode */ -+ value |= (1 << 5); -+ /* 3V66, PCI : 64MHz, 32MHz */ -+ value |= (1 << 3); -+ i2c_write_single(0xd2, 14, value); -+ -+} -+ -+static void resume_clk_freq(void) -+{ -+ i2c_write_single(0xd2, 1, cached_clk_freq); -+ i2c_write_single(0xd2, 14, cached_pci_fixed_freq); -+} -+ -+static void stop_clocks(void) -+{ -+ /* CPU Clock Register */ -+ stop_clock(2, 5); /* not used */ -+ stop_clock(2, 6); /* not used */ -+ stop_clock(2, 7); /* not used */ -+ -+ /* PCI Clock Register */ -+ stop_clock(3, 1); /* 8100 */ -+ stop_clock(3, 5); /* SIS */ -+ stop_clock(3, 0); /* not used */ -+ stop_clock(3, 6); /* not used */ -+ -+ /* PCI 48M Clock Register */ -+ stop_clock(4, 6); /* USB grounding */ -+ stop_clock(4, 5); /* REF(5536_14M) */ -+ -+ /* 3V66 Control Register */ -+ stop_clock(5, 0); /* VCH_CLK..., grounding */ -+} -+ -+static void enable_clocks(void) -+{ -+ enable_clock(3, 1); /* 8100 */ -+ enable_clock(3, 5); /* SIS */ -+ -+ enable_clock(4, 6); -+ enable_clock(4, 5); /* REF(5536_14M) */ -+ -+ enable_clock(5, 0); /* VCH_CLOCK, grounding */ -+} -+ -+static int lynloong_suspend(struct device *dev) -+{ -+ /* Disable AMP */ -+ set_gpio_output_high(6); -+ /* Turn off LCD */ -+ lynloong_lcd_vo_set(0); -+ -+ /* Stop the clocks of some devices */ -+ stop_clocks(); -+ -+ /* Decrease the external clock frequency */ -+ decrease_clk_freq(); -+ -+ return 0; -+} -+ -+static int lynloong_resume(struct device *dev) -+{ -+ /* Turn on the LCD */ -+ lynloong_lcd_vo_set(1); -+ -+ /* Resume clock frequency, enable the relative clocks */ -+ resume_clk_freq(); -+ enable_clocks(); -+ -+ /* Enable AMP */ -+ set_gpio_output_low(6); -+ -+ return 0; -+} -+ -+static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend, -+ lynloong_resume); -+#endif /* !CONFIG_PM */ -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "lynloong_pc", -+ }, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver platform_driver = { -+ .driver = { -+ .name = "lynloong_pc", -+ .owner = THIS_MODULE, -+#ifdef CONFIG_PM -+ .pm = &lynloong_pm_ops, -+#endif -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int __init lynloong_init(void) -+{ -+ int ret; -+ -+ pr_info("LynLoong platform specific driver loaded.\n"); -+ -+ /* Register platform stuff */ -+ ret = platform_driver_register(&platform_driver); -+ if (ret) { -+ pr_err("Failed to register LynLoong platform driver.\n"); -+ return ret; -+ } -+ -+ ret = lynloong_backlight_init(); -+ if (ret) { -+ pr_err("Failed to register LynLoong backlight driver.\n"); -+ return ret; -+ } -+ -+ ret = lynloong_vo_init(); -+ if (ret) { -+ pr_err("Failed to register LynLoong backlight driver.\n"); -+ lynloong_vo_exit(); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void __exit lynloong_exit(void) -+{ -+ lynloong_vo_exit(); -+ lynloong_backlight_exit(); -+ platform_driver_unregister(&platform_driver); -+ -+ pr_info("LynLoong platform specific driver unloaded.\n"); -+} -+ -+module_init(lynloong_init); -+module_exit(lynloong_exit); -+ -+MODULE_AUTHOR("Wu Zhangjin ; Xiang Yu "); -+MODULE_DESCRIPTION("LynLoong PC driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/yeeloong_ecrom.c b/drivers/platform/mips/yeeloong_ecrom.c -new file mode 100644 -index 0000000..1bfe4cf ---- /dev/null -+++ b/drivers/platform/mips/yeeloong_ecrom.c -@@ -0,0 +1,944 @@ -+/* -+ * Driver for flushing/dumping ROM of EC on YeeLoong laptop -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: liujl -+ * -+ * NOTE : -+ * The EC resources accessing and programming are supported. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define EC_MISC_DEV "ec_misc" -+#define EC_IOC_MAGIC 'E' -+ -+/* ec registers range */ -+#define EC_MAX_REGADDR 0xFFFF -+#define EC_MIN_REGADDR 0xF000 -+#define EC_RAM_ADDR 0xF800 -+ -+/* version burned address */ -+#define VER_ADDR 0xf7a1 -+#define VER_MAX_SIZE 7 -+#define EC_ROM_MAX_SIZE 0x10000 -+ -+/* ec internal register */ -+#define REG_POWER_MODE 0xF710 -+#define FLAG_NORMAL_MODE 0x00 -+#define FLAG_IDLE_MODE 0x01 -+#define FLAG_RESET_MODE 0x02 -+ -+/* ec update program flag */ -+#define PROGRAM_FLAG_NONE 0x00 -+#define PROGRAM_FLAG_IE 0x01 -+#define PROGRAM_FLAG_ROM 0x02 -+ -+/* XBI relative registers */ -+#define REG_XBISEG0 0xFEA0 -+#define REG_XBISEG1 0xFEA1 -+#define REG_XBIRSV2 0xFEA2 -+#define REG_XBIRSV3 0xFEA3 -+#define REG_XBIRSV4 0xFEA4 -+#define REG_XBICFG 0xFEA5 -+#define REG_XBICS 0xFEA6 -+#define REG_XBIWE 0xFEA7 -+#define REG_XBISPIA0 0xFEA8 -+#define REG_XBISPIA1 0xFEA9 -+#define REG_XBISPIA2 0xFEAA -+#define REG_XBISPIDAT 0xFEAB -+#define REG_XBISPICMD 0xFEAC -+#define REG_XBISPICFG 0xFEAD -+#define REG_XBISPIDATR 0xFEAE -+#define REG_XBISPICFG2 0xFEAF -+ -+/* commands definition for REG_XBISPICMD */ -+#define SPICMD_WRITE_STATUS 0x01 -+#define SPICMD_BYTE_PROGRAM 0x02 -+#define SPICMD_READ_BYTE 0x03 -+#define SPICMD_WRITE_DISABLE 0x04 -+#define SPICMD_READ_STATUS 0x05 -+#define SPICMD_WRITE_ENABLE 0x06 -+#define SPICMD_HIGH_SPEED_READ 0x0B -+#define SPICMD_POWER_DOWN 0xB9 -+#define SPICMD_SST_EWSR 0x50 -+#define SPICMD_SST_SEC_ERASE 0x20 -+#define SPICMD_SST_BLK_ERASE 0x52 -+#define SPICMD_SST_CHIP_ERASE 0x60 -+#define SPICMD_FRDO 0x3B -+#define SPICMD_SEC_ERASE 0xD7 -+#define SPICMD_BLK_ERASE 0xD8 -+#define SPICMD_CHIP_ERASE 0xC7 -+ -+/* bits definition for REG_XBISPICFG */ -+#define SPICFG_AUTO_CHECK 0x01 -+#define SPICFG_SPI_BUSY 0x02 -+#define SPICFG_DUMMY_READ 0x04 -+#define SPICFG_EN_SPICMD 0x08 -+#define SPICFG_LOW_SPICS 0x10 -+#define SPICFG_EN_SHORT_READ 0x20 -+#define SPICFG_EN_OFFSET_READ 0x40 -+#define SPICFG_EN_FAST_READ 0x80 -+ -+/* watchdog timer registers */ -+#define REG_WDTCFG 0xfe80 -+#define REG_WDTPF 0xfe81 -+#define REG_WDT 0xfe82 -+ -+/* lpc configure register */ -+#define REG_LPCCFG 0xfe95 -+ -+/* 8051 reg */ -+#define REG_PXCFG 0xff14 -+ -+/* Fan register in KB3310 */ -+#define REG_ECFAN_SPEED_LEVEL 0xf4e4 -+#define REG_ECFAN_SWITCH 0xf4d2 -+ -+/* the ec flash rom id number */ -+#define EC_ROM_PRODUCT_ID_SPANSION 0x01 -+#define EC_ROM_PRODUCT_ID_MXIC 0xC2 -+#define EC_ROM_PRODUCT_ID_AMIC 0x37 -+#define EC_ROM_PRODUCT_ID_EONIC 0x1C -+ -+/* misc ioctl operations */ -+#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int) -+#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int) -+#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int) -+#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int) -+#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int) -+ -+/* start address for programming of EC content or IE */ -+/* ec running code start address */ -+#define EC_START_ADDR 0x00000000 -+/* ec information element storing address */ -+#define IE_START_ADDR 0x00020000 -+ -+/* EC state */ -+#define EC_STATE_IDLE 0x00 /* ec in idle state */ -+#define EC_STATE_BUSY 0x01 /* ec in busy state */ -+ -+/* timeout value for programming */ -+#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */ -+/* command checkout timeout including cmd to port or state flag check */ -+#define EC_CMD_TIMEOUT 0x1000 -+#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */ -+#define EC_MAX_DELAY_UNIT (10) /* every time for polling */ -+#define SPI_FINISH_WAIT_TIME 10 -+/* EC content max size */ -+#define EC_CONTENT_MAX_SIZE (64 * 1024) -+#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR) -+ -+/* the register operation access struct */ -+struct ec_reg { -+ u32 addr; /* the address of kb3310 registers */ -+ u8 val; /* the register value */ -+}; -+ -+struct ec_info { -+ u32 start_addr; -+ u32 size; -+ u8 *buf; -+}; -+ -+/* open for using rom protection action */ -+#define EC_ROM_PROTECTION -+ -+/* enable the chip reset mode */ -+static int ec_init_reset_mode(void) -+{ -+ int timeout; -+ unsigned char status = 0; -+ int ret = 0; -+ -+ /* make chip goto reset mode */ -+ ret = ec_query_seq(CMD_INIT_RESET_MODE); -+ if (ret < 0) { -+ printk(KERN_ERR "ec init reset mode failed.\n"); -+ goto out; -+ } -+ -+ /* make the action take active */ -+ timeout = EC_CMD_TIMEOUT; -+ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; -+ while (timeout--) { -+ if (status) { -+ udelay(EC_REG_DELAY); -+ break; -+ } -+ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; -+ udelay(EC_REG_DELAY); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR "ec rom fixup : can't check reset status.\n"); -+ ret = -EINVAL; -+ } else -+ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout, -+ EC_CMD_TIMEOUT - timeout, status); -+ -+ /* set MCU to reset mode */ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_PXCFG); -+ status |= (1 << 0); -+ ec_write(REG_PXCFG, status); -+ udelay(EC_REG_DELAY); -+ -+ /* disable FWH/LPC */ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_LPCCFG); -+ status &= ~(1 << 7); -+ ec_write(REG_LPCCFG, status); -+ udelay(EC_REG_DELAY); -+ -+ printk(KERN_INFO "entering reset mode ok..............\n"); -+ -+ out: -+ return ret; -+} -+ -+/* make ec exit from reset mode */ -+static void ec_exit_reset_mode(void) -+{ -+ unsigned char regval; -+ -+ udelay(EC_REG_DELAY); -+ regval = ec_read(REG_LPCCFG); -+ regval |= (1 << 7); -+ ec_write(REG_LPCCFG, regval); -+ regval = ec_read(REG_PXCFG); -+ regval &= ~(1 << 0); -+ ec_write(REG_PXCFG, regval); -+ printk(KERN_INFO "exit reset mode ok..................\n"); -+ -+ return; -+} -+ -+/* make ec disable WDD */ -+static void ec_disable_WDD(void) -+{ -+ unsigned char status; -+ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_WDTCFG); -+ ec_write(REG_WDTPF, 0x03); -+ ec_write(REG_WDTCFG, (status & 0x80) | 0x48); -+ printk(KERN_INFO "Disable WDD ok..................\n"); -+ -+ return; -+} -+ -+/* make ec enable WDD */ -+static void ec_enable_WDD(void) -+{ -+ unsigned char status; -+ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_WDTCFG); -+ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */ -+ ec_write(REG_WDTCFG, (status & 0x80) | 0x03); -+ printk(KERN_INFO "Enable WDD ok..................\n"); -+ -+ return; -+} -+ -+/* make ec goto idle mode */ -+static int ec_init_idle_mode(void) -+{ -+ int timeout; -+ unsigned char status = 0; -+ int ret = 0; -+ -+ ec_query_seq(CMD_INIT_IDLE_MODE); -+ -+ /* make the action take active */ -+ timeout = EC_CMD_TIMEOUT; -+ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; -+ while (timeout--) { -+ if (status) { -+ udelay(EC_REG_DELAY); -+ break; -+ } -+ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; -+ udelay(EC_REG_DELAY); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR "ec rom fixup : can't check out the status.\n"); -+ ret = -EINVAL; -+ } else -+ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout, -+ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE)); -+ -+ printk(KERN_INFO "entering idle mode ok...................\n"); -+ -+ return ret; -+} -+ -+/* make ec exit from idle mode */ -+static int ec_exit_idle_mode(void) -+{ -+ -+ ec_query_seq(CMD_EXIT_IDLE_MODE); -+ -+ printk(KERN_INFO "exit idle mode ok...................\n"); -+ -+ return 0; -+} -+ -+static int ec_instruction_cycle(void) -+{ -+ unsigned long timeout; -+ int ret = 0; -+ -+ timeout = EC_FLASH_TIMEOUT; -+ while (timeout-- >= 0) { -+ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY)) -+ break; -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ return ret; -+} -+ -+/* To see if the ec is in busy state or not. */ -+static inline int ec_flash_busy(unsigned long timeout) -+{ -+ /* assurance the first command be going to rom */ -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+#if 1 -+ timeout = timeout / EC_MAX_DELAY_UNIT; -+ while (timeout-- > 0) { -+ /* check the rom's status of busy flag */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) -+ return EC_STATE_IDLE; -+ udelay(EC_MAX_DELAY_UNIT); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_FLASH_BUSY : timeout for check rom flag.\n"); -+ return EC_STATE_BUSY; -+ } -+#else -+ /* check the rom's status of busy flag */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+ -+ timeout = timeout / EC_MAX_DELAY_UNIT; -+ while (timeout-- > 0) { -+ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) -+ return EC_STATE_IDLE; -+ udelay(EC_MAX_DELAY_UNIT); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_FLASH_BUSY : timeout for check rom flag.\n"); -+ return EC_STATE_BUSY; -+ } -+#endif -+ -+ return EC_STATE_IDLE; -+} -+ -+static int rom_instruction_cycle(unsigned char cmd) -+{ -+ unsigned long timeout = 0; -+ -+ switch (cmd) { -+ case SPICMD_READ_STATUS: -+ case SPICMD_WRITE_ENABLE: -+ case SPICMD_WRITE_DISABLE: -+ case SPICMD_READ_BYTE: -+ case SPICMD_HIGH_SPEED_READ: -+ timeout = 0; -+ break; -+ case SPICMD_WRITE_STATUS: -+ timeout = 300 * 1000; -+ break; -+ case SPICMD_BYTE_PROGRAM: -+ timeout = 5 * 1000; -+ break; -+ case SPICMD_SST_SEC_ERASE: -+ case SPICMD_SEC_ERASE: -+ timeout = 1000 * 1000; -+ break; -+ case SPICMD_SST_BLK_ERASE: -+ case SPICMD_BLK_ERASE: -+ timeout = 3 * 1000 * 1000; -+ break; -+ case SPICMD_SST_CHIP_ERASE: -+ case SPICMD_CHIP_ERASE: -+ timeout = 20 * 1000 * 1000; -+ break; -+ default: -+ timeout = EC_SPICMD_STANDARD_TIMEOUT; -+ } -+ if (timeout == 0) -+ return ec_instruction_cycle(); -+ if (timeout < EC_SPICMD_STANDARD_TIMEOUT) -+ timeout = EC_SPICMD_STANDARD_TIMEOUT; -+ -+ return ec_flash_busy(timeout); -+} -+ -+/* delay for start/stop action */ -+static void delay_spi(int n) -+{ -+ while (n--) -+ inb(EC_IO_PORT_HIGH); -+} -+ -+/* start the action to spi rom function */ -+static void ec_start_spi(void) -+{ -+ unsigned char val; -+ -+ delay_spi(SPI_FINISH_WAIT_TIME); -+ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK; -+ ec_write(REG_XBISPICFG, val); -+ delay_spi(SPI_FINISH_WAIT_TIME); -+} -+ -+/* stop the action to spi rom function */ -+static void ec_stop_spi(void) -+{ -+ unsigned char val; -+ -+ delay_spi(SPI_FINISH_WAIT_TIME); -+ val = -+ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK)); -+ ec_write(REG_XBISPICFG, val); -+ delay_spi(SPI_FINISH_WAIT_TIME); -+} -+ -+/* read one byte from xbi interface */ -+static int ec_read_byte(unsigned int addr, unsigned char *byte) -+{ -+ int ret = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* write the address */ -+ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); -+ /* start action */ -+ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ); -+ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ *byte = ec_read(REG_XBISPIDAT); -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* write one byte to ec rom */ -+static int ec_write_byte(unsigned int addr, unsigned char byte) -+{ -+ int ret = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* write the address */ -+ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); -+ ec_write(REG_XBISPIDAT, byte); -+ /* start action */ -+ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM); -+ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* unprotect SPI ROM */ -+/* EC_ROM_unprotect function code */ -+static int EC_ROM_unprotect(void) -+{ -+ unsigned char status; -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); -+ return 1; -+ } -+ -+ /* unprotect the status register of rom */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n"); -+ return 1; -+ } -+ status = ec_read(REG_XBISPIDAT); -+ ec_write(REG_XBISPIDAT, status & 0x02); -+ if (ec_instruction_cycle() < 0) { -+ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n"); -+ return 1; -+ } -+ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); -+ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n"); -+ return 1; -+ } -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/* erase one block or chip or sector as needed */ -+static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr) -+{ -+ unsigned char status; -+ int ret = 0, i = 0; -+ int unprotect_count = 3; -+ int check_flag = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+#ifdef EC_ROM_PROTECTION -+ /* added for re-check SPICMD_READ_STATUS */ -+ while (unprotect_count-- > 0) { -+ if (EC_ROM_unprotect()) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* first time:500ms --> 5.5sec -->10.5sec */ -+ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++) -+ udelay(50000); -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) -+ == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); -+ } else { -+ status = ec_read(REG_XBISPIDAT); -+ printk(KERN_INFO "Read unprotect status : 0x%x\n", -+ status); -+ if ((status & 0x1C) == 0x00) { -+ printk(KERN_INFO -+ "Read unprotect status OK1 : 0x%x\n", -+ status & 0x1C); -+ check_flag = 1; -+ break; -+ } -+ } -+ } -+ -+ if (!check_flag) { -+ printk(KERN_INFO "SPI ROM unprotect fail.\n"); -+ return 1; -+ } -+#endif -+ -+ /* block address fill */ -+ if (erase_cmd == SPICMD_BLK_ERASE) { -+ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0); -+ } -+ -+ /* erase the whole chip first */ -+ ec_write(REG_XBISPICMD, erase_cmd); -+ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* update the whole rom content with H/W mode -+ * PLEASE USING ec_unit_erase() FIRSTLY -+ */ -+static int ec_program_rom(struct ec_info *info, int flag) -+{ -+ unsigned int addr = 0; -+ unsigned long size = 0; -+ unsigned char *ptr = NULL; -+ unsigned char data; -+ unsigned char val = 0; -+ int ret = 0; -+ int i, j; -+ unsigned char status; -+ -+ /* modify for program serial No. -+ * set IE_START_ADDR & use idle mode, -+ * disable WDD -+ */ -+ if (flag == PROGRAM_FLAG_ROM) { -+ ret = ec_init_reset_mode(); -+ addr = info->start_addr + EC_START_ADDR; -+ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n"); -+ } else if (flag == PROGRAM_FLAG_IE) { -+ ret = ec_init_idle_mode(); -+ ec_disable_WDD(); -+ addr = info->start_addr + IE_START_ADDR; -+ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n"); -+ } else { -+ return 0; -+ } -+ -+ if (ret < 0) { -+ if (flag == PROGRAM_FLAG_IE) -+ ec_enable_WDD(); -+ return ret; -+ } -+ -+ size = info->size; -+ ptr = info->buf; -+ printk(KERN_INFO "starting update ec ROM..............\n"); -+ -+ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr); -+ if (ret) { -+ printk(KERN_ERR "program ec : erase block failed.\n"); -+ goto out; -+ } -+ printk(KERN_ERR "program ec : erase block OK.\n"); -+ -+ i = 0; -+ while (i < size) { -+ data = *(ptr + i); -+ ec_write_byte(addr, data); -+ ec_read_byte(addr, &val); -+ if (val != data) { -+ ec_write_byte(addr, data); -+ ec_read_byte(addr, &val); -+ if (val != data) { -+ printk(KERN_INFO -+ "EC : Second flash program failed at:\t"); -+ printk(KERN_INFO -+ "addr : 0x%x, source : 0x%x, dest: 0x%x\n", -+ addr, data, val); -+ printk(KERN_INFO "This should not happen... STOP\n"); -+ break; -+ } -+ } -+ i++; -+ addr++; -+ } -+ -+#ifdef EC_ROM_PROTECTION -+ /* we should start spi access firstly */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n"); -+ goto out1; -+ } -+ -+ /* protect the status register of rom */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); -+ goto out1; -+ } -+ status = ec_read(REG_XBISPIDAT); -+ -+ ec_write(REG_XBISPIDAT, status | 0x1C); -+ if (ec_instruction_cycle() < 0) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : write status value failed.\n"); -+ goto out1; -+ } -+ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); -+ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n"); -+ goto out1; -+ } -+#endif -+ -+ /* disable the write action to spi rom */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n"); -+ goto out1; -+ } -+ -+ out1: -+ /* we should stop spi access firstly */ -+ ec_stop_spi(); -+ out: -+ /* for security */ -+ for (j = 0; j < 2000; j++) -+ udelay(1000); -+ -+ /* modify for program serial No. -+ * after program No exit idle mode -+ * and enable WDD -+ */ -+ if (flag == PROGRAM_FLAG_ROM) { -+ /* exit from the reset mode */ -+ ec_exit_reset_mode(); -+ } else { -+ /* ec exit from idle mode */ -+ ret = ec_exit_idle_mode(); -+ ec_enable_WDD(); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* ioctl */ -+static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd, -+ u_long arg) -+{ -+ struct ec_info ecinfo; -+ void __user *ptr = (void __user *)arg; -+ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); -+ int ret = 0; -+ -+ switch (cmd) { -+ case IOCTL_RDREG: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg read : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_MAX_REGADDR) -+ || (ecreg->addr < EC_MIN_REGADDR)) { -+ printk(KERN_ERR -+ "reg read : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ecreg->val = ec_read(ecreg->addr); -+ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg read : copy to user error.\n"); -+ return -EFAULT; -+ } -+ break; -+ case IOCTL_WRREG: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg write : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_MAX_REGADDR) -+ || (ecreg->addr < EC_MIN_REGADDR)) { -+ printk(KERN_ERR -+ "reg write : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ec_write(ecreg->addr, ecreg->val); -+ break; -+ case IOCTL_READ_EC: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "spi read : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_RAM_ADDR) -+ && (ecreg->addr < EC_MAX_REGADDR)) { -+ printk(KERN_ERR -+ "spi read : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ec_read_byte(ecreg->addr, &(ecreg->val)); -+ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "spi read : copy to user error.\n"); -+ return -EFAULT; -+ } -+ break; -+ case IOCTL_PROGRAM_IE: -+ ecinfo.start_addr = EC_START_ADDR; -+ ecinfo.size = EC_CONTENT_MAX_SIZE; -+ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); -+ if (ecinfo.buf == NULL) { -+ printk(KERN_ERR "program ie : kmalloc failed.\n"); -+ return -ENOMEM; -+ } -+ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size); -+ if (ret) { -+ printk(KERN_ERR "program ie : copy from user error.\n"); -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ return -EFAULT; -+ } -+ -+ /* use ec_program_rom to write serial No */ -+ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE); -+ -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ break; -+ case IOCTL_PROGRAM_EC: -+ ecinfo.start_addr = EC_START_ADDR; -+ if (get_user((ecinfo.size), (u32 *) ptr)) { -+ printk(KERN_ERR "program ec : get user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) { -+ printk(KERN_ERR "program ec : size out of limited.\n"); -+ return -EINVAL; -+ } -+ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); -+ if (ecinfo.buf == NULL) { -+ printk(KERN_ERR "program ec : kmalloc failed.\n"); -+ return -ENOMEM; -+ } -+ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size); -+ if (ret) { -+ printk(KERN_ERR "program ec : copy from user error.\n"); -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ return -EFAULT; -+ } -+ -+ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM); -+ -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ break; -+ -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static long misc_compat_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg); -+} -+ -+static int misc_open(struct inode *inode, struct file *filp) -+{ -+ struct ec_reg *ecreg = NULL; -+ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL); -+ if (ecreg) -+ filp->private_data = ecreg; -+ -+ return ecreg ? 0 : -ENOMEM; -+} -+ -+static int misc_release(struct inode *inode, struct file *filp) -+{ -+ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); -+ -+ filp->private_data = NULL; -+ kfree(ecreg); -+ -+ return 0; -+} -+ -+static const struct file_operations ecmisc_fops = { -+ .open = misc_open, -+ .release = misc_release, -+ .read = NULL, -+ .write = NULL, -+#ifdef CONFIG_64BIT -+ .compat_ioctl = misc_compat_ioctl, -+#else -+ .ioctl = misc_ioctl, -+#endif -+}; -+ -+static struct miscdevice ecmisc_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = EC_MISC_DEV, -+ .fops = &ecmisc_fops -+}; -+ -+static int __init ecmisc_init(void) -+{ -+ int ret; -+ -+ printk(KERN_INFO "EC misc device init.\n"); -+ ret = misc_register(&ecmisc_device); -+ -+ return ret; -+} -+ -+static void __exit ecmisc_exit(void) -+{ -+ printk(KERN_INFO "EC misc device exit.\n"); -+ misc_deregister(&ecmisc_device); -+} -+ -+module_init(ecmisc_init); -+module_exit(ecmisc_exit); -+ -+MODULE_AUTHOR("liujl "); -+MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c -new file mode 100644 -index 0000000..32a2bdb ---- /dev/null -+++ b/drivers/platform/mips/yeeloong_laptop.c -@@ -0,0 +1,1360 @@ -+/* -+ * Driver for YeeLoong laptop extras -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin , Liu Junliang -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include /* for backlight subdriver */ -+#include -+#include /* for hwmon subdriver */ -+#include -+#include /* for video output subdriver */ -+#include /* for lcd output subdriver */ -+#include /* for hotkey subdriver */ -+#include -+#include -+#include -+#include /* for AC & Battery subdriver */ -+#include /* for register_reboot_notifier */ -+#include /* for register_pm_notifier */ -+ -+#include -+ -+#include /* for loongson_cmdline */ -+#include -+ -+#define ON 1 -+#define OFF 0 -+#define EVENT_START EVENT_LID -+ -+/* common function */ -+#define EC_VER_LEN 64 -+ -+static int ec_version_before(char *version) -+{ -+ char *p, ec_ver[EC_VER_LEN]; -+ -+ p = strstr(loongson_cmdline, "EC_VER="); -+ if (!p) -+ memset(ec_ver, 0, EC_VER_LEN); -+ else { -+ strncpy(ec_ver, p, EC_VER_LEN); -+ p = strstr(ec_ver, " "); -+ if (p) -+ *p = '\0'; -+ } -+ -+ return (strncasecmp(ec_ver, version, 64) < 0); -+} -+ -+/* backlight subdriver */ -+#define MIN_BRIGHTNESS 1 -+#define MAX_BRIGHTNESS 8 -+ -+static int yeeloong_set_brightness(struct backlight_device *bd) -+{ -+ unsigned char level; -+ static unsigned char old_level; -+ -+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && -+ bd->props.power == FB_BLANK_UNBLANK) ? -+ bd->props.brightness : 0; -+ -+ level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS); -+ -+ /* Avoid to modify the brightness when EC is tuning it */ -+ if (old_level != level) { -+ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level) -+ ec_write(REG_DISPLAY_BRIGHTNESS, level); -+ old_level = level; -+ } -+ -+ return 0; -+} -+ -+static int yeeloong_get_brightness(struct backlight_device *bd) -+{ -+ return ec_read(REG_DISPLAY_BRIGHTNESS); -+} -+ -+static struct backlight_ops backlight_ops = { -+ .get_brightness = yeeloong_get_brightness, -+ .update_status = yeeloong_set_brightness, -+}; -+ -+static struct backlight_device *yeeloong_backlight_dev; -+ -+static int yeeloong_backlight_init(void) -+{ -+ int ret; -+ struct backlight_properties props; -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.max_brightness = MAX_BRIGHTNESS; -+ props.type = BACKLIGHT_PLATFORM; -+ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL, -+ NULL, &backlight_ops, &props); -+ -+ if (IS_ERR(yeeloong_backlight_dev)) { -+ ret = PTR_ERR(yeeloong_backlight_dev); -+ yeeloong_backlight_dev = NULL; -+ return ret; -+ } -+ -+ yeeloong_backlight_dev->props.brightness = -+ yeeloong_get_brightness(yeeloong_backlight_dev); -+ backlight_update_status(yeeloong_backlight_dev); -+ -+ return 0; -+} -+ -+static void yeeloong_backlight_exit(void) -+{ -+ if (yeeloong_backlight_dev) { -+ backlight_device_unregister(yeeloong_backlight_dev); -+ yeeloong_backlight_dev = NULL; -+ } -+} -+ -+/* AC & Battery subdriver */ -+ -+static struct power_supply yeeloong_ac, yeeloong_bat; -+ -+#define RET (val->intval) -+ -+#define BAT_CAP_CRITICAL 5 -+#define BAT_CAP_HIGH 95 -+ -+#define get_bat(type) \ -+ ec_read(REG_BAT_##type) -+ -+#define get_bat_l(type) \ -+ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW)) -+ -+static int yeeloong_get_ac_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ if (psp == POWER_SUPPLY_PROP_ONLINE) -+ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN); -+ -+ return 0; -+} -+ -+static enum power_supply_property yeeloong_ac_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static struct power_supply yeeloong_ac = { -+ .name = "yeeloong-ac", -+ .type = POWER_SUPPLY_TYPE_MAINS, -+ .properties = yeeloong_ac_props, -+ .num_properties = ARRAY_SIZE(yeeloong_ac_props), -+ .get_property = yeeloong_get_ac_props, -+}; -+ -+static inline bool is_bat_in(void) -+{ -+ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN); -+} -+ -+static int get_bat_temp(void) -+{ -+ return get_bat_l(TEMPERATURE) * 10; -+} -+ -+static int get_bat_current(void) -+{ -+ return -(s16)get_bat_l(CURRENT); -+} -+ -+static int get_bat_voltage(void) -+{ -+ return get_bat_l(VOLTAGE); -+} -+ -+static char *get_manufacturer(void) -+{ -+ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO"; -+} -+ -+static int get_relative_cap(void) -+{ -+ /* -+ * When the relative capacity becomes 2, the hardware is observed to -+ * have been turned off forcely. so, we must tune it be suitable to -+ * make the software do related actions. -+ */ -+ int tmp = get_bat_l(RELATIVE_CAP); -+ -+ if (tmp <= (BAT_CAP_CRITICAL * 2)) -+ tmp -= 3; -+ -+ return tmp; -+} -+ -+static int yeeloong_get_bat_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ switch (psp) { -+ /* Fixed information */ -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ /* mV -> µV */ -+ RET = get_bat_l(DESIGN_VOL) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: -+ /* mAh->µAh */ -+ RET = get_bat_l(DESIGN_CAP) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL: -+ /* µAh */ -+ RET = get_bat_l(FULLCHG_CAP) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_MANUFACTURER: -+ val->strval = get_manufacturer(); -+ break; -+ /* Dynamic information */ -+ case POWER_SUPPLY_PROP_PRESENT: -+ RET = is_bat_in(); -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ /* mA -> µA */ -+ RET = is_bat_in() ? get_bat_current() * 1000 : 0; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ /* mV -> µV */ -+ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0; -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ /* Celcius */ -+ RET = is_bat_in() ? get_bat_temp() : 0; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ RET = is_bat_in() ? get_relative_cap() : 0; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: { -+ int status; -+ -+ if (!is_bat_in()) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ break; -+ } -+ -+ status = get_bat(STATUS); -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; -+ -+ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ break; -+ } -+ -+ if (status & BIT_BAT_STATUS_FULL) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; -+ else { -+ int curr_cap = get_relative_cap(); -+ -+ if (status & BIT_BAT_STATUS_LOW) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; -+ if (curr_cap <= BAT_CAP_CRITICAL) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; -+ } else if (curr_cap >= BAT_CAP_HIGH) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; -+ } -+ } break; -+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: -+ /* seconds */ -+ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0; -+ break; -+ case POWER_SUPPLY_PROP_STATUS: { -+ int charge = get_bat(CHARGE); -+ -+ RET = POWER_SUPPLY_STATUS_UNKNOWN; -+ if (charge & FLAG_BAT_CHARGE_DISCHARGE) -+ RET = POWER_SUPPLY_STATUS_DISCHARGING; -+ else if (charge & FLAG_BAT_CHARGE_CHARGE) -+ RET = POWER_SUPPLY_STATUS_CHARGING; -+ } break; -+ case POWER_SUPPLY_PROP_HEALTH: { -+ int status; -+ -+ if (!is_bat_in()) { -+ RET = POWER_SUPPLY_HEALTH_UNKNOWN; -+ break; -+ } -+ -+ status = get_bat(STATUS); -+ RET = POWER_SUPPLY_HEALTH_GOOD; -+ -+ if (status & (BIT_BAT_STATUS_DESTROY | -+ BIT_BAT_STATUS_LOW)) -+ RET = POWER_SUPPLY_HEALTH_DEAD; -+ if (get_bat(CHARGE_STATUS) & -+ BIT_BAT_CHARGE_STATUS_OVERTEMP) -+ RET = POWER_SUPPLY_HEALTH_OVERHEAT; -+ } break; -+ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */ -+ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+#undef RET -+ -+static enum power_supply_property yeeloong_bat_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_FULL, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_CAPACITY_LEVEL, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_MANUFACTURER, -+}; -+ -+static struct power_supply yeeloong_bat = { -+ .name = "yeeloong-bat", -+ .type = POWER_SUPPLY_TYPE_BATTERY, -+ .properties = yeeloong_bat_props, -+ .num_properties = ARRAY_SIZE(yeeloong_bat_props), -+ .get_property = yeeloong_get_bat_props, -+}; -+ -+static int ac_bat_initialized; -+ -+static int yeeloong_bat_init(void) -+{ -+ int ret; -+ -+ ret = power_supply_register(NULL, &yeeloong_ac); -+ if (ret) -+ return ret; -+ ret = power_supply_register(NULL, &yeeloong_bat); -+ if (ret) { -+ power_supply_unregister(&yeeloong_ac); -+ return ret; -+ } -+ ac_bat_initialized = 1; -+ -+ return 0; -+} -+ -+static void yeeloong_bat_exit(void) -+{ -+ ac_bat_initialized = 0; -+ -+ power_supply_unregister(&yeeloong_ac); -+ power_supply_unregister(&yeeloong_bat); -+} -+/* hwmon subdriver */ -+ -+#define MIN_FAN_SPEED 0 -+#define MAX_FAN_SPEED 3 -+ -+#define get_fan(type) \ -+ ec_read(REG_FAN_##type) -+ -+#define set_fan(type, val) \ -+ ec_write(REG_FAN_##type, val) -+ -+static inline int get_fan_speed_level(void) -+{ -+ return get_fan(SPEED_LEVEL); -+} -+static inline void set_fan_speed_level(int speed) -+{ -+ set_fan(SPEED_LEVEL, speed); -+} -+ -+static inline int get_fan_mode(void) -+{ -+ return get_fan(AUTO_MAN_SWITCH); -+} -+static inline void set_fan_mode(int mode) -+{ -+ set_fan(AUTO_MAN_SWITCH, mode); -+} -+ -+/* -+ * 3 different modes: Full speed(0); manual mode(1); auto mode(2) -+ */ -+static int get_fan_pwm_enable(void) -+{ -+ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 : -+ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1; -+} -+ -+static void set_fan_pwm_enable(int mode) -+{ -+ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL); -+ if (mode == 0) -+ set_fan_speed_level(MAX_FAN_SPEED); -+} -+ -+static int get_fan_pwm(void) -+{ -+ return get_fan_speed_level(); -+} -+ -+static void set_fan_pwm(int value) -+{ -+ if (get_fan_mode() != BIT_FAN_MANUAL) -+ return; -+ -+ value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED); -+ -+ /* We must ensure the fan is on */ -+ if (value > 0) -+ set_fan(CONTROL, ON); -+ -+ set_fan_speed_level(value); -+} -+ -+static inline int get_fan_speed(void) -+{ -+ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW); -+} -+ -+static int get_fan_rpm(void) -+{ -+ return FAN_SPEED_DIVIDER / get_fan_speed(); -+} -+ -+static int get_cpu_temp(void) -+{ -+ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000; -+} -+ -+static int get_cpu_temp_max(void) -+{ -+ return 60 * 1000; -+} -+ -+static int get_bat_temp_alarm(void) -+{ -+ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP); -+} -+ -+static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long value; -+ -+ if (!count) -+ return 0; -+ -+ ret = kstrtoul(buf, 10, &value); -+ if (ret) -+ return ret; -+ -+ set(value); -+ -+ return count; -+} -+ -+static ssize_t show_sys_hwmon(int (*get) (void), char *buf) -+{ -+ return sprintf(buf, "%d\n", get()); -+} -+ -+#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ -+ static ssize_t show_##_name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ char *buf) \ -+ { \ -+ return show_sys_hwmon(_set, buf); \ -+ } \ -+ static ssize_t store_##_name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ return store_sys_hwmon(_get, buf, count); \ -+ } \ -+ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); -+ -+CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL); -+CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm); -+CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable, -+ set_fan_pwm_enable); -+CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL); -+CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL); -+CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL); -+CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL); -+CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL); -+CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL); -+ -+static ssize_t -+show_name(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ return sprintf(buf, "yeeloong\n"); -+} -+ -+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); -+ -+static struct attribute *hwmon_attributes[] = { -+ &sensor_dev_attr_pwm1.dev_attr.attr, -+ &sensor_dev_attr_pwm1_enable.dev_attr.attr, -+ &sensor_dev_attr_fan1_input.dev_attr.attr, -+ &sensor_dev_attr_temp1_input.dev_attr.attr, -+ &sensor_dev_attr_temp1_max.dev_attr.attr, -+ &sensor_dev_attr_temp2_input.dev_attr.attr, -+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, -+ &sensor_dev_attr_curr1_input.dev_attr.attr, -+ &sensor_dev_attr_in1_input.dev_attr.attr, -+ &sensor_dev_attr_name.dev_attr.attr, -+ NULL -+}; -+ -+static struct attribute_group hwmon_attribute_group = { -+ .attrs = hwmon_attributes -+}; -+ -+static struct device *yeeloong_hwmon_dev; -+ -+static int yeeloong_hwmon_init(void) -+{ -+ int ret; -+ -+ yeeloong_hwmon_dev = hwmon_device_register(NULL); -+ if (IS_ERR(yeeloong_hwmon_dev)) { -+ yeeloong_hwmon_dev = NULL; -+ return PTR_ERR(yeeloong_hwmon_dev); -+ } -+ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj, -+ &hwmon_attribute_group); -+ if (ret) { -+ hwmon_device_unregister(yeeloong_hwmon_dev); -+ yeeloong_hwmon_dev = NULL; -+ return ret; -+ } -+ /* ensure fan is set to auto mode */ -+ set_fan_pwm_enable(2); -+ -+ return 0; -+} -+ -+static void yeeloong_hwmon_exit(void) -+{ -+ if (yeeloong_hwmon_dev) { -+ sysfs_remove_group(&yeeloong_hwmon_dev->kobj, -+ &hwmon_attribute_group); -+ hwmon_device_unregister(yeeloong_hwmon_dev); -+ yeeloong_hwmon_dev = NULL; -+ } -+} -+ -+/* video output subdriver */ -+ -+#define LCD 0 -+#define CRT 1 -+#define VOD_NUM 2 /* The total number of video output device*/ -+ -+static struct output_device *vod[VOD_NUM]; -+ -+static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT}; -+ -+static int get_vo_dev(struct output_device *od) -+{ -+ int i, dev; -+ -+ dev = -1; -+ for (i = 0; i < VOD_NUM; i++) -+ if (od == vod[i]) -+ dev = i; -+ -+ return dev; -+} -+ -+static int vo_get_status(int dev) -+{ -+ return ec_read(vor[dev]); -+} -+ -+static int yeeloong_vo_get_status(struct output_device *od) -+{ -+ int vd; -+ -+ vd = get_vo_dev(od); -+ if (vd != -1) -+ return vo_get_status(vd); -+ -+ return -ENODEV; -+} -+ -+static void vo_set_state(int dev, int state) -+{ -+ int addr; -+ unsigned long value; -+ -+ switch (dev) { -+ case LCD: -+ addr = 0x31; -+ break; -+ case CRT: -+ addr = 0x21; -+ break; -+ default: -+ /* return directly if the wrong video output device */ -+ return; -+ } -+ -+ outb(addr, 0x3c4); -+ value = inb(0x3c5); -+ -+ switch (dev) { -+ case LCD: -+ value |= (state ? 0x03 : 0x02); -+ break; -+ case CRT: -+ if (state) -+ clear_bit(7, &value); -+ else -+ set_bit(7, &value); -+ break; -+ default: -+ break; -+ } -+ -+ outb(addr, 0x3c4); -+ outb(value, 0x3c5); -+ -+ if (dev == LCD) -+ ec_write(REG_BACKLIGHT_CTRL, state); -+} -+ -+static int yeeloong_vo_set_state(struct output_device *od) -+{ -+ int vd; -+ -+ vd = get_vo_dev(od); -+ if (vd == -1) -+ return -ENODEV; -+ -+ if (vd == CRT && !vo_get_status(vd)) -+ return 0; -+ -+ vo_set_state(vd, !!od->request_state); -+ -+ return 0; -+} -+ -+static struct output_properties vop = { -+ .set_state = yeeloong_vo_set_state, -+ .get_status = yeeloong_vo_get_status, -+}; -+ -+static int yeeloong_vo_init(void) -+{ -+ int ret, i; -+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; -+ -+ /* Register video output device: lcd, crt */ -+ for (i = 0; i < VOD_NUM; i++) { -+ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop); -+ if (IS_ERR(vod[i])) { -+ if (i != 0) -+ video_output_unregister(vod[i-1]); -+ ret = PTR_ERR(vod[i]); -+ vod[i] = NULL; -+ return ret; -+ } -+ } -+ /* Ensure LCD is on by default */ -+ vo_set_state(LCD, ON); -+ -+ /* -+ * Turn off CRT by default, and will be enabled when the CRT -+ * connectting event reported by SCI -+ */ -+ vo_set_state(CRT, OFF); -+ -+ return 0; -+} -+ -+static void yeeloong_vo_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < VOD_NUM; i++) { -+ if (vod[i]) { -+ video_output_unregister(vod[i]); -+ vod[i] = NULL; -+ } -+ } -+} -+ -+/* lcd subdriver */ -+ -+struct lcd_device *lcd[VOD_NUM]; -+ -+static int get_lcd_dev(struct lcd_device *ld) -+{ -+ int i, dev; -+ -+ dev = -1; -+ for (i = 0; i < VOD_NUM; i++) -+ if (ld == lcd[i]) -+ dev = i; -+ -+ return dev; -+} -+ -+static int yeeloong_lcd_set_power(struct lcd_device *ld, int power) -+{ -+ int dev = get_lcd_dev(ld); -+ -+ if (power == FB_BLANK_UNBLANK) -+ vo_set_state(dev, ON); -+ if (power == FB_BLANK_POWERDOWN) -+ vo_set_state(dev, OFF); -+ -+ return 0; -+} -+ -+static int yeeloong_lcd_get_power(struct lcd_device *ld) -+{ -+ return vo_get_status(get_lcd_dev(ld)); -+} -+ -+static struct lcd_ops lcd_ops = { -+ .set_power = yeeloong_lcd_set_power, -+ .get_power = yeeloong_lcd_get_power, -+}; -+ -+static int yeeloong_lcd_init(void) -+{ -+ int ret, i; -+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; -+ -+ /* Register video output device: lcd, crt */ -+ for (i = 0; i < VOD_NUM; i++) { -+ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops); -+ if (IS_ERR(lcd[i])) { -+ if (i != 0) -+ lcd_device_unregister(lcd[i-1]); -+ ret = PTR_ERR(lcd[i]); -+ lcd[i] = NULL; -+ return ret; -+ } -+ } -+#if 0 -+ /* This has been done by the vide output driver */ -+ -+ /* Ensure LCD is on by default */ -+ vo_set_state(LCD, ON); -+ -+ /* -+ * Turn off CRT by default, and will be enabled when the CRT -+ * connectting event reported by SCI -+ */ -+ vo_set_state(CRT, OFF); -+#endif -+ return 0; -+} -+ -+static void yeeloong_lcd_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < VOD_NUM; i++) { -+ if (lcd[i]) { -+ lcd_device_unregister(lcd[i]); -+ lcd[i] = NULL; -+ } -+ } -+} -+ -+/* hotkey subdriver */ -+ -+static struct input_dev *yeeloong_hotkey_dev; -+ -+static atomic_t reboot_flag, sleep_flag; -+#define in_sleep() (&sleep_flag) -+#define in_reboot() (&reboot_flag) -+ -+static const struct key_entry yeeloong_keymap[] = { -+ {KE_SW, EVENT_LID, { SW_LID } }, -+ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */ -+ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */ -+ {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */ -+ {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */ -+ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */ -+ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */ -+ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */ -+ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */ -+ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */ -+ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */ -+ {KE_END, 0} -+}; -+ -+static int is_fake_event(u16 keycode) -+{ -+ switch (keycode) { -+ case KEY_SLEEP: -+ case SW_LID: -+ return atomic_read(in_sleep()) | atomic_read(in_reboot()); -+ break; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static struct key_entry *get_event_key_entry(int event, int status) -+{ -+ struct key_entry *ke; -+ static int old_brightness_status = -1; -+ static int old_volume_status = -1; -+ -+ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event); -+ if (!ke) -+ return NULL; -+ -+ switch (event) { -+ case EVENT_DISPLAY_BRIGHTNESS: -+ /* current status > old one, means up */ -+ if ((status < old_brightness_status) || (0 == status)) -+ ke++; -+ old_brightness_status = status; -+ break; -+ case EVENT_AUDIO_VOLUME: -+ if ((status < old_volume_status) || (0 == status)) -+ ke++; -+ old_volume_status = status; -+ break; -+ default: -+ break; -+ } -+ -+ return ke; -+} -+ -+static int report_lid_switch(int status) -+{ -+ static int old_status; -+ -+ /* -+ * LID is a switch button, so, two continuous same status should be -+ * ignored -+ */ -+ if (old_status != status) { -+ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status); -+ input_sync(yeeloong_hotkey_dev); -+ } -+ old_status = status; -+ -+ return status; -+} -+ -+static int crt_detect_handler(int status) -+{ -+ /* -+ * When CRT is inserted, enable its output and disable the LCD output, -+ * otherwise, do reversely. -+ */ -+ vo_set_state(CRT, status); -+ vo_set_state(LCD, !status); -+ -+ return status; -+} -+ -+static int displaytoggle_handler(int status) -+{ -+ /* EC(>=PQ1D26) does this job for us, we can not do it again, -+ * otherwise, the brightness will not resume to the normal level! */ -+ if (ec_version_before("EC_VER=PQ1D26")) -+ vo_set_state(LCD, status); -+ -+ return status; -+} -+ -+static int mypow(int x, int y) -+{ -+ int i, j = x; -+ -+ for (i = 1; i < y; i++) -+ j *= j; -+ -+ return j; -+} -+ -+static int switchvideomode_handler(int status) -+{ -+ /* Default status: CRT|LCD = 0|1 = 1 */ -+ static int bin_state = 1; -+ int i; -+ -+ /* -+ * Only enable switch video output button -+ * when CRT is connected -+ */ -+ if (!vo_get_status(CRT)) -+ return 0; -+ /* -+ * 2. no CRT connected: LCD on, CRT off -+ * 3. BOTH on -+ * 0. BOTH off -+ * 1. LCD off, CRT on -+ */ -+ -+ bin_state++; -+ if (bin_state > mypow(2, VOD_NUM) - 1) -+ bin_state = 0; -+ -+ for (i = 0; i < VOD_NUM; i++) -+ vo_set_state(i, bin_state & (1 << i)); -+ -+ return bin_state; -+} -+ -+static int camera_handler(int status) -+{ -+ int value; -+ -+ value = ec_read(REG_CAMERA_CONTROL); -+ ec_write(REG_CAMERA_CONTROL, value | (1 << 1)); -+ -+ return status; -+} -+ -+static int usb2_handler(int status) -+{ -+ pr_emerg("USB2 Over Current occurred\n"); -+ -+ return status; -+} -+ -+static int usb0_handler(int status) -+{ -+ pr_emerg("USB0 Over Current occurred\n"); -+ -+ return status; -+} -+ -+static int ac_bat_handler(int status) -+{ -+ if (ac_bat_initialized) { -+ power_supply_changed(&yeeloong_ac); -+ power_supply_changed(&yeeloong_bat); -+ } -+ -+ return status; -+} -+ -+struct sci_event { -+ int reg; -+ sci_handler handler; -+}; -+ -+static const struct sci_event se[] = { -+ [EVENT_AC_BAT] = {0, ac_bat_handler}, -+ [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL}, -+ [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL}, -+ [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler}, -+ [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler}, -+ [EVENT_BLACK_SCREEN] = {REG_DISPLAY_LCD, displaytoggle_handler}, -+ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL}, -+ [EVENT_LID] = {REG_LID_DETECT, NULL}, -+ [EVENT_DISPLAY_TOGGLE] = {0, switchvideomode_handler}, -+ [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler}, -+ [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler}, -+ [EVENT_WLAN] = {REG_WLAN, NULL}, -+}; -+ -+static void do_event_action(int event) -+{ -+ int status = -1; -+ struct key_entry *ke; -+ struct sci_event *sep; -+ -+ sep = (struct sci_event *)&se[event]; -+ -+ if (sep->reg != 0) -+ status = ec_read(sep->reg); -+ -+ if (status == -1) { -+ /* ec_read hasn't been called, status is invalid */ -+ return; -+ } -+ -+ if (sep->handler != NULL) -+ status = sep->handler(status); -+ -+ pr_debug("%s: event: %d status: %d\n", __func__, event, status); -+ -+ /* Report current key to user-space */ -+ ke = get_event_key_entry(event, status); -+ -+ /* -+ * Ignore the LID and SLEEP event when we are already in sleep or -+ * reboot state, this will avoid the recursive pm operations. but note: -+ * the report_lid_switch() called in arch/mips/loongson/lemote-2f/pm.c -+ * is necessary, because it is used to wake the system from sleep -+ * state. In the future, perhaps SW_LID should works like SLEEP, no -+ * need to function as a SWITCH, just report the state when the LID is -+ * closed is enough, this event can tell the software to "SLEEP", no -+ * need to tell the softwares when we are resuming from "SLEEP". -+ */ -+ if (ke && !is_fake_event(ke->keycode)) { -+ if (ke->keycode == SW_LID) -+ report_lid_switch(status); -+ else -+ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1, -+ true); -+ } -+} -+ -+/* -+ * SCI(system control interrupt) main interrupt routine -+ * -+ * We will do the query and get event number together so the interrupt routine -+ * should be longer than 120us now at least 3ms elpase for it. -+ */ -+static irqreturn_t sci_irq_handler(int irq, void *dev_id) -+{ -+ int ret, event; -+ -+ if (SCI_IRQ_NUM != irq) -+ return IRQ_NONE; -+ -+ /* Query the event number */ -+ ret = ec_query_event_num(); -+ if (ret < 0) -+ return IRQ_NONE; -+ -+ event = ec_get_event_num(); -+ if (event < EVENT_START || event > EVENT_END) -+ return IRQ_NONE; -+ -+ /* Execute corresponding actions */ -+ do_event_action(event); -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Config and init some msr and gpio register properly. -+ */ -+static int sci_irq_init(void) -+{ -+ u32 hi, lo; -+ u32 gpio_base; -+ unsigned long flags; -+ int ret; -+ -+ /* Get gpio base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); -+ gpio_base = lo & 0xff00; -+ -+ /* Filter the former kb3310 interrupt for security */ -+ ret = ec_query_event_num(); -+ if (ret) -+ return ret; -+ -+ /* For filtering next number interrupt */ -+ udelay(10000); -+ -+ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN -+ * gpio : -+ * input, pull-up, no-invert, event-count and value 0, -+ * no-filter, no edge mode -+ * gpio27 map to Virtual gpio0 -+ * msr : -+ * no primary and lpc -+ * Unrestricted Z input to IG10 from Virtual gpio 0. -+ */ -+ local_irq_save(flags); -+ _rdmsr(0x80000024, &hi, &lo); -+ lo &= ~(1 << 10); -+ _wrmsr(0x80000024, hi, lo); -+ _rdmsr(0x80000025, &hi, &lo); -+ lo &= ~(1 << 10); -+ _wrmsr(0x80000025, hi, lo); -+ _rdmsr(0x80000023, &hi, &lo); -+ lo |= (0x0a << 0); -+ _wrmsr(0x80000023, hi, lo); -+ local_irq_restore(flags); -+ -+ /* Set gpio27 as sci interrupt -+ * -+ * input, pull-up, no-fliter, no-negedge, invert -+ * the sci event is just about 120us -+ */ -+ asm(".set noreorder\n"); -+ /* input enable */ -+ outl(0x00000800, (gpio_base | 0xA0)); -+ /* revert the input */ -+ outl(0x00000800, (gpio_base | 0xA4)); -+ /* event-int enable */ -+ outl(0x00000800, (gpio_base | 0xB8)); -+ asm(".set reorder\n"); -+ -+ return 0; -+} -+ -+static int notify_reboot(struct notifier_block *nb, unsigned long event, void *buf) -+{ -+ switch (event) { -+ case SYS_RESTART: -+ case SYS_HALT: -+ case SYS_POWER_OFF: -+ atomic_set(in_reboot(), 1); -+ break; -+ default: -+ return NOTIFY_DONE; -+ } -+ -+ return NOTIFY_OK; -+} -+ -+static int notify_pm(struct notifier_block *nb, unsigned long event, void *buf) -+{ -+ switch (event) { -+ case PM_HIBERNATION_PREPARE: -+ case PM_SUSPEND_PREPARE: -+ atomic_inc(in_sleep()); -+ break; -+ case PM_POST_HIBERNATION: -+ case PM_POST_SUSPEND: -+ case PM_RESTORE_PREPARE: /* do we need this ?? */ -+ atomic_dec(in_sleep()); -+ break; -+ default: -+ return NOTIFY_DONE; -+ } -+ -+ pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event, -+ atomic_read(in_sleep())); -+ -+ return NOTIFY_OK; -+} -+ -+static struct notifier_block reboot_notifier = { -+ .notifier_call = notify_reboot, -+}; -+ -+static struct notifier_block pm_notifier = { -+ .notifier_call = notify_pm, -+}; -+ -+static int yeeloong_hotkey_init(void) -+{ -+ int ret = 0; -+ -+ ret = register_reboot_notifier(&reboot_notifier); -+ if (ret) { -+ pr_err("Can't register reboot notifier\n"); -+ goto end; -+ } -+ -+ ret = register_pm_notifier(&pm_notifier); -+ if (ret) { -+ pr_err("Can't register pm notifier\n"); -+ goto free_reboot_notifier; -+ } -+ -+ ret = sci_irq_init(); -+ if (ret) { -+ pr_err("Can't init SCI interrupt\n"); -+ goto free_pm_notifier; -+ } -+ -+ ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler, -+ IRQF_ONESHOT, "sci", NULL); -+ if (ret) { -+ pr_err("Can't thread SCI interrupt handler\n"); -+ goto free_pm_notifier; -+ } -+ -+ yeeloong_hotkey_dev = input_allocate_device(); -+ -+ if (!yeeloong_hotkey_dev) { -+ ret = -ENOMEM; -+ goto free_irq; -+ } -+ -+ yeeloong_hotkey_dev->name = "HotKeys"; -+ yeeloong_hotkey_dev->phys = "button/input0"; -+ yeeloong_hotkey_dev->id.bustype = BUS_HOST; -+ yeeloong_hotkey_dev->dev.parent = NULL; -+ -+ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL); -+ if (ret) { -+ pr_err("Failed to setup input device keymap\n"); -+ goto free_dev; -+ } -+ -+ ret = input_register_device(yeeloong_hotkey_dev); -+ if (ret) -+ goto free_keymap; -+ -+ /* Update the current status of LID */ -+ report_lid_switch(ON); -+ -+#ifdef CONFIG_LOONGSON_SUSPEND -+ /* Install the real yeeloong_report_lid_status for pm.c */ -+ yeeloong_report_lid_status = report_lid_switch; -+#endif -+ return 0; -+ -+free_keymap: -+ sparse_keymap_free(yeeloong_hotkey_dev); -+free_dev: -+ input_free_device(yeeloong_hotkey_dev); -+free_irq: -+ free_irq(SCI_IRQ_NUM, NULL); -+free_pm_notifier: -+ unregister_pm_notifier(&pm_notifier); -+free_reboot_notifier: -+ unregister_reboot_notifier(&reboot_notifier); -+end: -+ return ret; -+} -+ -+static void yeeloong_hotkey_exit(void) -+{ -+ /* Free irq */ -+ free_irq(SCI_IRQ_NUM, NULL); -+ -+#ifdef CONFIG_LOONGSON_SUSPEND -+ /* Uninstall yeeloong_report_lid_status for pm.c */ -+ if (yeeloong_report_lid_status == report_lid_switch) -+ yeeloong_report_lid_status = NULL; -+#endif -+ -+ if (yeeloong_hotkey_dev) { -+ sparse_keymap_free(yeeloong_hotkey_dev); -+ input_unregister_device(yeeloong_hotkey_dev); -+ yeeloong_hotkey_dev = NULL; -+ } -+} -+ -+#ifdef CONFIG_PM -+static void usb_ports_set(int status) -+{ -+ status = !!status; -+ -+ ec_write(REG_USB0_FLAG, status); -+ ec_write(REG_USB1_FLAG, status); -+ ec_write(REG_USB2_FLAG, status); -+} -+ -+static int yeeloong_suspend(struct device *dev) -+ -+{ -+ if (ec_version_before("EC_VER=PQ1D27")) -+ vo_set_state(LCD, OFF); -+ vo_set_state(CRT, OFF); -+ usb_ports_set(OFF); -+ -+ return 0; -+} -+ -+static int yeeloong_resume(struct device *dev) -+{ -+ int ret; -+ -+ if (ec_version_before("EC_VER=PQ1D27")) -+ vo_set_state(LCD, ON); -+ vo_set_state(CRT, ON); -+ usb_ports_set(ON); -+ -+ ret = sci_irq_init(); -+ if (ret) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend, -+ yeeloong_resume); -+#endif -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "yeeloong_laptop", -+ }, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver platform_driver = { -+ .driver = { -+ .name = "yeeloong_laptop", -+ .owner = THIS_MODULE, -+#ifdef CONFIG_PM -+ .pm = &yeeloong_pm_ops, -+#endif -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int __init yeeloong_init(void) -+{ -+ int ret; -+ -+ pr_info("YeeLoong Laptop platform specific driver loaded.\n"); -+ -+ /* Register platform stuff */ -+ ret = platform_driver_register(&platform_driver); -+ if (ret) { -+ pr_err("Failed to register YeeLoong platform driver.\n"); -+ return ret; -+ } -+ -+#define yeeloong_init_drv(drv, alias) do { \ -+ pr_info("Registered YeeLoong " alias " driver.\n"); \ -+ ret = yeeloong_ ## drv ## _init(); \ -+ if (ret) { \ -+ pr_err("Failed to register YeeLoong " alias " driver.\n"); \ -+ yeeloong_ ## drv ## _exit(); \ -+ return ret; \ -+ } \ -+} while (0) -+ -+ yeeloong_init_drv(backlight, "backlight"); -+ yeeloong_init_drv(bat, "battery and AC"); -+ yeeloong_init_drv(hwmon, "hardware monitor"); -+ yeeloong_init_drv(vo, "video output"); -+ yeeloong_init_drv(lcd, "lcd output"); -+ yeeloong_init_drv(hotkey, "hotkey input"); -+ -+ return 0; -+} -+ -+static void __exit yeeloong_exit(void) -+{ -+ yeeloong_hotkey_exit(); -+ yeeloong_lcd_exit(); -+ yeeloong_vo_exit(); -+ yeeloong_hwmon_exit(); -+ yeeloong_bat_exit(); -+ yeeloong_backlight_exit(); -+ platform_driver_unregister(&platform_driver); -+ -+ pr_info("YeeLoong platform specific driver unloaded.\n"); -+} -+ -+module_init(yeeloong_init); -+module_exit(yeeloong_exit); -+ -+MODULE_AUTHOR("Wu Zhangjin ; Liu Junliang "); -+MODULE_DESCRIPTION("YeeLoong laptop driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index b5b5c3d..f908003 100644 ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -727,6 +727,7 @@ comment "Platform RTC drivers" - config RTC_DRV_CMOS - tristate "PC-style 'CMOS'" - depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 -+ depends on !DEXXON_GDIUM - default y if X86 - help - Say "yes" here to get direct support for the real time clock -diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c -index f940056..a9bb1db 100644 ---- a/drivers/usb/host/pci-quirks.c -+++ b/drivers/usb/host/pci-quirks.c -@@ -450,6 +450,26 @@ void usb_amd_dev_put(void) - } - EXPORT_SYMBOL_GPL(usb_amd_dev_put); - -+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) -+static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) -+{ -+ u16 cmd; -+ return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); -+} -+ -+#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) -+#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) -+ -+static int mmio_resource_enabled(struct pci_dev *pdev, int idx) -+{ -+ return pci_resource_start(pdev, idx) && mmio_enabled(pdev); -+} -+#endif -+ -+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) - /* - * Make sure the controller is completely inactive, unable to - * generate interrupts or do DMA. -@@ -531,15 +551,6 @@ reset_needed: - } - EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); - --static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) --{ -- u16 cmd; -- return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); --} -- --#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) --#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) -- - static void quirk_usb_handoff_uhci(struct pci_dev *pdev) - { - unsigned long base = 0; -@@ -557,12 +568,11 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev) - if (base) - uhci_check_and_reset_hc(pdev, base); - } -+#else -+#define quirk_usb_handoff_uhci(x) do { } while (0) -+#endif /* CONFIG_USB_UHCI_HCD* */ - --static int mmio_resource_enabled(struct pci_dev *pdev, int idx) --{ -- return pci_resource_start(pdev, idx) && mmio_enabled(pdev); --} -- -+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) - static void quirk_usb_handoff_ohci(struct pci_dev *pdev) - { - void __iomem *base; -@@ -641,7 +651,11 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) - /* Now the controller is safely in SUSPEND and nothing can wake it up */ - iounmap(base); - } -+#else -+#define quirk_usb_handoff_ohci(x) do { } while(0) -+#endif /* CONFIG_USB_OHCI_HCD* */ - -+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) - static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { - { - /* Pegatron Lucid (ExoPC) */ -@@ -816,6 +830,9 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev) - - iounmap(base); - } -+#else -+#define quirk_usb_disable_ehci(x) do { } while (0) -+#endif /* CONFIG_USB_EHCI_HCD* */ - - /* - * handshake - spin reading a register until handshake completes -@@ -956,6 +973,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) - } - EXPORT_SYMBOL_GPL(usb_disable_xhci_ports); - -+#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) - /** - * PCI Quirks for xHCI. - * -@@ -1064,6 +1082,9 @@ hc_init: - - iounmap(base); - } -+#else -+#define quirk_usb_handoff_xhci(x) do { } while (0) -+#endif /* CONFIG_USB_UHCI_HCD* */ - - static void quirk_usb_early_handoff(struct pci_dev *pdev) - { -diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c -index f0c0c53..84dff90 100644 ---- a/drivers/usb/serial/option.c -+++ b/drivers/usb/serial/option.c -@@ -79,6 +79,9 @@ static void option_instat_callback(struct urb *urb); - #define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 - #define OPTION_PRODUCT_GTM380_MODEM 0x7201 - -+#define HUAWO_VENDOR_ID 0x21F5 -+#define HUAWO_PRODUCT_E1621 0x2008 -+ - #define HUAWEI_VENDOR_ID 0x12D1 - #define HUAWEI_PRODUCT_E173 0x140C - #define HUAWEI_PRODUCT_E1750 0x1406 -@@ -633,6 +636,7 @@ static const struct usb_device_id option_ids[] = { - { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, - { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, -+ { USB_DEVICE(HUAWO_VENDOR_ID, HUAWO_PRODUCT_E1621) }, /* QUANTA 6500 chips, Unicom extensive use of this card */ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, -diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig -index 8bf495f..f6a15b6 100644 ---- a/drivers/video/Kconfig -+++ b/drivers/video/Kconfig -@@ -36,6 +36,12 @@ config VGASTATE - tristate - default n - -+config VIDEO_OUTPUT_CONTROL -+ tristate "Lowlevel video output switch controls" -+ help -+ This framework adds support for low-level control of the video -+ output switch. -+ - config VIDEOMODE_HELPERS - bool - -diff --git a/drivers/video/Makefile b/drivers/video/Makefile -index 9ad3c17..3d869d9 100644 ---- a/drivers/video/Makefile -+++ b/drivers/video/Makefile -@@ -7,6 +7,8 @@ obj-y += backlight/ - - obj-y += fbdev/ - -+#video output switch sysfs driver -+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o - obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o - ifeq ($(CONFIG_OF),y) - obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o -diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig -index b3dd417..452035ad 100644 ---- a/drivers/video/fbdev/Kconfig -+++ b/drivers/video/fbdev/Kconfig -@@ -2450,6 +2450,19 @@ config FB_SIMPLE - Configuration re: surface address, size, and format must be provided - through device tree, or plain old platform data. - -+config FB_SM712 -+ tristate "Silicon Motion SM712 framebuffer support" -+ depends on FB && PCI -+ select FB_CFB_FILLRECT -+ select FB_CFB_COPYAREA -+ select FB_CFB_IMAGEBLIT -+ help -+ Frame buffer driver for the Silicon Motion SM712 chip. -+ -+ This driver is also available as a module. The module will be -+ called sm712fb. If you want to compile it as a module, say M -+ here and read . -+ - source "drivers/video/fbdev/omap/Kconfig" - source "drivers/video/fbdev/omap2/Kconfig" - source "drivers/video/fbdev/exynos/Kconfig" -diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile -index 1979aff..9b694f9 100644 ---- a/drivers/video/fbdev/Makefile -+++ b/drivers/video/fbdev/Makefile -@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o - obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o - obj-$(CONFIG_FB_PS3) += ps3fb.o - obj-$(CONFIG_FB_SM501) += sm501fb.o -+obj-$(CONFIG_FB_SM712) += sm712fb/ - obj-$(CONFIG_FB_UDL) += udlfb.o - obj-$(CONFIG_FB_SMSCUFX) += smscufx.o - obj-$(CONFIG_FB_XILINX) += xilinxfb.o -diff --git a/drivers/video/fbdev/sm712fb/Makefile b/drivers/video/fbdev/sm712fb/Makefile -new file mode 100644 -index 0000000..9bf3519 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_FB_SM712) += sm712fb.o -+ -+sm712fb-objs := sm712fb_drv.o sm712fb_accel.o -diff --git a/drivers/video/fbdev/sm712fb/TODO b/drivers/video/fbdev/sm712fb/TODO -new file mode 100644 -index 0000000..dcfd4e7 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/TODO -@@ -0,0 +1,7 @@ -+TODO: -+- Dual head support -+- refine the code, convert more registers magic numbers to macros -+- Does it really works on Big Endian machines? -+ -+Please send any patches to Greg Kroah-Hartman and -+Tom Li . -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.c b/drivers/video/fbdev/sm712fb/sm712fb_accel.c -new file mode 100644 -index 0000000..12fce1f ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.c -@@ -0,0 +1,246 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#include -+#include -+#include -+ -+#include "sm712fb_drv.h" -+#include "sm712fb_accel.h" -+ -+static inline u32 bytes_to_dword(const u8 *bytes, int length) -+{ -+ u32 dword = 0; -+ -+ switch (length) { -+ case 4: -+#ifdef __BIG_ENDIAN -+ dword += bytes[3]; -+#else -+ dword += bytes[3] << 24; -+#endif -+ case 3: -+#ifdef __BIG_ENDIAN -+ dword += bytes[2] << 8; -+#else -+ dword += bytes[2] << 16; -+#endif -+ case 2: -+#ifdef __BIG_ENDIAN -+ dword += bytes[1] << 16; -+#else -+ dword += bytes[1] << 8; -+#endif -+ case 1: -+#ifdef __BIG_ENDIAN -+ dword += bytes[0] << 24; -+#else -+ dword += bytes[0]; -+#endif -+ } -+ return dword; -+} -+ -+int sm712fb_init_accel(struct sm712fb_info *fb) -+{ -+ u8 reg; -+ -+ /* reset the 2D engine */ -+ sm712_write_seq(fb, 0x21, sm712_read_seq(fb, 0x21) & 0xf8); -+ reg = sm712_read_seq(fb, 0x15); -+ sm712_write_seq(fb, 0x15, reg | 0x30); -+ sm712_write_seq(fb, 0x15, reg); -+ -+ if (sm712fb_wait(fb) != 0) -+ return -1; -+ -+ sm712_write_dpr(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0)); -+ -+ /* same width for DPR_PITCH and DPR_SRC_WINDOW */ -+ sm712_write_dpr(fb, DPR_PITCH, -+ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); -+ sm712_write_dpr(fb, DPR_SRC_WINDOW, -+ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); -+ -+ sm712_write_dpr(fb, DPR_BYTE_BIT_MASK, 0xffffffff); -+ sm712_write_dpr(fb, DPR_COLOR_COMPARE_MASK, 0); -+ sm712_write_dpr(fb, DPR_COLOR_COMPARE, 0); -+ sm712_write_dpr(fb, DPR_SRC_BASE, 0); -+ sm712_write_dpr(fb, DPR_DST_BASE, 0); -+ sm712_read_dpr(fb, DPR_DST_BASE); -+ -+ return 0; -+} -+ -+int sm712fb_wait(struct sm712fb_info *fb) -+{ -+ int i; -+ u8 reg; -+ -+ for (i = 0; i < 10000; i++) { -+ reg = sm712_read_seq(fb, SCR_DE_STATUS); -+ if ((reg & SCR_DE_STATUS_MASK) == SCR_DE_ENGINE_IDLE) -+ return 0; -+ udelay(1); -+ } -+ return -EBUSY; -+} -+ -+void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -+{ -+ u32 width = rect->width, height = rect->height; -+ u32 dx = rect->dx, dy = rect->dy; -+ u32 color; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((rect->dx >= info->var.xres_virtual) || -+ (rect->dy >= info->var.yres_virtual)) -+ return; -+ -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) -+ color = ((u32 *) (info->pseudo_palette))[rect->color]; -+ else -+ color = rect->color; -+ -+ sm712_write_dpr(sfb, DPR_FG_COLOR, color); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | -+ (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -+ -+void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) -+{ -+ u32 sx = area->sx, sy = area->sy; -+ u32 dx = area->dx, dy = area->dy; -+ u32 height = area->height, width = area->width; -+ u32 direction; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((sx >= info->var.xres_virtual) || (sy >= info->var.yres_virtual)) -+ return; -+ -+ if (sy < dy || (sy == dy && sx <= dx)) { -+ sx += width - 1; -+ dx += width - 1; -+ sy += height - 1; -+ dy += height - 1; -+ direction = DE_CTRL_RTOL; -+ } else -+ direction = 0; -+ -+ sm712_write_dpr(sfb, DPR_SRC_COORDS, DPR_COORDS(sx, sy)); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_DE_CTRL, -+ DE_CTRL_START | DE_CTRL_ROP_ENABLE | direction | -+ (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -+ -+void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image) -+{ -+ u32 dx = image->dx, dy = image->dy; -+ u32 width = image->width, height = image->height; -+ u32 fg_color, bg_color; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ u32 imgidx = 0; -+ u32 line = image->width >> 3; -+ -+ int i, j; -+ u32 total_bytes, total_dwords, remain_bytes; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((image->dx >= info->var.xres_virtual) || -+ (image->dy >= info->var.yres_virtual)) -+ return; -+ -+ if (unlikely(image->depth != 1)) { -+ /* unsupported depth, fallback to draw Tux */ -+ cfb_imageblit(info, image); -+ return; -+ } -+ -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) { -+ fg_color = ((u32 *) (info->pseudo_palette))[image->fg_color]; -+ bg_color = ((u32 *) (info->pseudo_palette))[image->bg_color]; -+ } else { -+ fg_color = image->fg_color; -+ bg_color = image->bg_color; -+ } -+ -+ /* total bytes we need to write */ -+ total_bytes = (width + 7) / 8; -+ -+ /* split the bytes into dwords and remainder bytes */ -+ total_dwords = (total_bytes & ~3) / 4; -+ remain_bytes = total_bytes & 3; -+ -+ sm712_write_dpr(sfb, DPR_SRC_COORDS, 0); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_FG_COLOR, fg_color); -+ sm712_write_dpr(sfb, DPR_BG_COLOR, bg_color); -+ -+ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | -+ (DE_CTRL_COMMAND_HOST_WRITE << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_HOST_MONO << DE_CTRL_HOST_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ -+ for (i = 0; i < height; i++) { -+ /* cast bytes data into dwords and write to the dataport */ -+ for (j = 0; j < total_dwords; j++) { -+ sm712_write_dataport(sfb, -+ bytes_to_dword(&image-> -+ data[imgidx] + -+ j * 4, 4)); -+ } -+ -+ if (remain_bytes) { -+ sm712_write_dataport(sfb, -+ bytes_to_dword(&image-> -+ data[imgidx] + -+ (total_dwords * 4), -+ remain_bytes)); -+ } -+ imgidx += line; -+ } -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.h b/drivers/video/fbdev/sm712fb/sm712fb_accel.h -new file mode 100644 -index 0000000..6f79177 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.h -@@ -0,0 +1,33 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#ifndef _SM712FB_ACCEL_H -+#define _SM712FB_ACCEL_H -+ -+int sm712fb_init_accel(struct sm712fb_info *fb); -+int sm712fb_wait(struct sm712fb_info *fb); -+void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -+void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area); -+void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image); -+ -+#endif -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.c b/drivers/video/fbdev/sm712fb/sm712fb_drv.c -new file mode 100644 -index 0000000..7f7cd4f ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.c -@@ -0,0 +1,1022 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_PM -+#include -+#endif -+ -+#include "sm712fb_drv.h" -+#include "sm712fb_accel.h" -+#include "sm712fb_modedb.h" -+ -+static struct fb_var_screeninfo sm712fb_var = { -+ .xres = 1024, -+ .yres = 600, -+ .xres_virtual = 1024, -+ .yres_virtual = 600, -+ .bits_per_pixel = 16, -+ .red = {16, 8, 0}, -+ .green = {8, 8, 0}, -+ .blue = {0, 8, 0}, -+ .activate = FB_ACTIVATE_NOW, -+ .height = -1, -+ .width = -1, -+ .vmode = FB_VMODE_NONINTERLACED, -+ .nonstd = 0, -+ .accel_flags = FB_ACCELF_TEXT, -+}; -+ -+static struct fb_fix_screeninfo sm712fb_fix = { -+ .id = "smXXXfb", -+ .type = FB_TYPE_PACKED_PIXELS, -+ .visual = FB_VISUAL_TRUECOLOR, -+ .line_length = 800 * 3, -+ .accel = FB_ACCEL_SMI_LYNX, -+ .type_aux = 0, -+ .xpanstep = 0, -+ .ypanstep = 0, -+ .ywrapstep = 0, -+}; -+ -+struct vesa_mode { -+ char index[6]; -+ u16 lfb_width; -+ u16 lfb_height; -+ u16 lfb_depth; -+}; -+ -+static bool accel = 1; -+ -+static struct vesa_mode vesa_mode_table[] = { -+ {"0x301", 640, 480, 8}, -+ {"0x303", 800, 600, 8}, -+ {"0x305", 1024, 768, 8}, -+ {"0x307", 1280, 1024, 8}, -+ -+ {"0x311", 640, 480, 16}, -+ {"0x314", 800, 600, 16}, -+ {"0x317", 1024, 768, 16}, -+ {"0x31A", 1280, 1024, 16}, -+ -+ {"0x312", 640, 480, 24}, -+ {"0x315", 800, 600, 24}, -+ {"0x318", 1024, 768, 24}, -+ {"0x31B", 1280, 1024, 24}, -+}; -+ -+struct screen_info sm712_scr_info; -+ -+static int sm712fb_setup(char *options) -+{ -+ char *this_opt; -+ -+ if (!options || !*options) -+ return 0; -+ -+ while ((this_opt = strsep(&options, ",")) != NULL) { -+ if (!*this_opt) -+ continue; -+ -+ if (!strcmp(this_opt, "accel:0")) -+ accel = false; -+ else if (!strcmp(this_opt, "accel:1")) -+ accel = true; -+ } -+ return 0; -+} -+ -+/* process command line options, get vga parameter */ -+static int __init sm712_vga_setup(char *options) -+{ -+ int i; -+ -+ if (!options || !*options) -+ return -EINVAL; -+ -+ sm712_scr_info.lfb_width = 0; -+ sm712_scr_info.lfb_height = 0; -+ sm712_scr_info.lfb_depth = 0; -+ -+ pr_debug("sm712_vga_setup = %s\n", options); -+ -+ for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { -+ if (strstr(options, vesa_mode_table[i].index)) { -+ sm712_scr_info.lfb_width = vesa_mode_table[i].lfb_width; -+ sm712_scr_info.lfb_height = -+ vesa_mode_table[i].lfb_height; -+ sm712_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; -+ return 0; -+ } -+ } -+ -+ return -1; -+} -+ -+__setup("vga=", sm712_vga_setup); -+ -+static void sm712_setpalette(int regno, unsigned red, unsigned green, -+ unsigned blue, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb = info->par; -+ -+ /* set bit 5:4 = 01 (write LCD RAM only) */ -+ sm712_write_seq(sfb, 0x66, (sm712_read_seq(sfb, 0x66) & 0xC3) | 0x10); -+ -+ sm712_writeb(sfb->mmio, DAC_REG, regno); -+ sm712_writeb(sfb->mmio, DAC_VAL, red >> 10); -+ sm712_writeb(sfb->mmio, DAC_VAL, green >> 10); -+ sm712_writeb(sfb->mmio, DAC_VAL, blue >> 10); -+} -+ -+/* chan_to_field -+ * -+ * convert a colour value into a field position -+ * -+ * from pxafb.c -+ */ -+ -+static inline unsigned int chan_to_field(unsigned int chan, -+ struct fb_bitfield *bf) -+{ -+ chan &= 0xffff; -+ chan >>= 16 - bf->length; -+ return chan << bf->offset; -+} -+ -+static int sm712_blank(int blank_mode, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb = info->par; -+ -+ /* clear DPMS setting */ -+ switch (blank_mode) { -+ case FB_BLANK_UNBLANK: -+ /* Screen On: HSync: On, VSync : On */ -+ sm712_write_seq(sfb, 0x01, -+ (sm712_read_seq(sfb, 0x01) & (~0x20))); -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) & 0x77)); -+ sm712_write_seq(sfb, 0x22, -+ (sm712_read_seq(sfb, 0x22) & (~0x30))); -+ sm712_write_seq(sfb, 0x23, -+ (sm712_read_seq(sfb, 0x23) & (~0xc0))); -+ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); -+ sm712_write_seq(sfb, 0x31, (sm712_read_seq(sfb, 0x31) | 0x03)); -+ break; -+ case FB_BLANK_NORMAL: -+ /* Screen Off: HSync: On, VSync : On Soft blank */ -+ sm712_write_seq(sfb, 0x01, -+ (sm712_read_seq(sfb, 0x01) & (~0x20))); -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x22, -+ (sm712_read_seq(sfb, 0x22) & (~0x30))); -+ sm712_write_seq(sfb, 0x23, -+ (sm712_read_seq(sfb, 0x23) & (~0xc0))); -+ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ break; -+ case FB_BLANK_VSYNC_SUSPEND: -+ /* Screen On: HSync: On, VSync : Off */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x0c); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x20)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0x20)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ case FB_BLANK_HSYNC_SUSPEND: -+ /* Screen On: HSync: Off, VSync : On */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x0c); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x10)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ case FB_BLANK_POWERDOWN: -+ /* Screen On: HSync: Off, VSync : Off */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x5a); -+ sm712_write_seq(sfb, 0x6b, 0x20); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x30)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int sm712_setcolreg(unsigned regno, unsigned red, unsigned green, -+ unsigned blue, unsigned trans, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb; -+ u32 val; -+ -+ sfb = info->par; -+ -+ if (regno > 255) -+ return 1; -+ -+ switch (sfb->fb.fix.visual) { -+ case FB_VISUAL_DIRECTCOLOR: -+ case FB_VISUAL_TRUECOLOR: -+ /* -+ * 16/32 bit true-colour, use pseudo-palette for 16 base color -+ */ -+ if (regno < 16) { -+ if (sfb->fb.var.bits_per_pixel == 16) { -+ u32 *pal = sfb->fb.pseudo_palette; -+ -+ val = chan_to_field(red, &sfb->fb.var.red); -+ val |= chan_to_field(green, &sfb->fb.var.green); -+ val |= chan_to_field(blue, &sfb->fb.var.blue); -+#ifdef __BIG_ENDIAN -+ pal[regno] = -+ ((red & 0xf800) >> 8) | -+ ((green & 0xe000) >> 13) | -+ ((green & 0x1c00) << 3) | -+ ((blue & 0xf800) >> 3); -+#else -+ pal[regno] = val; -+#endif -+ } else { -+ u32 *pal = sfb->fb.pseudo_palette; -+ -+ val = chan_to_field(red, &sfb->fb.var.red); -+ val |= chan_to_field(green, &sfb->fb.var.green); -+ val |= chan_to_field(blue, &sfb->fb.var.blue); -+#ifdef __BIG_ENDIAN -+ val = -+ (val & 0xff00ff00 >> 8) | -+ (val & 0x00ff00ff << 8); -+#endif -+ pal[regno] = val; -+ } -+ } -+ break; -+ -+ case FB_VISUAL_PSEUDOCOLOR: -+ /* color depth 8 bit */ -+ sm712_setpalette(regno, red, green, blue, info); -+ break; -+ -+ default: -+ return 1; /* unknown type */ -+ } -+ -+ return 0; -+ -+} -+ -+#ifdef __BIG_ENDIAN -+static ssize_t sm712fb_read(struct fb_info *info, char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ unsigned long p = *ppos; -+ -+ u32 *buffer, *dst; -+ u32 __iomem *src; -+ int c, i, cnt = 0, err = 0; -+ unsigned long total_size; -+ -+ if (!info || !info->screen_base) -+ return -ENODEV; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return -EPERM; -+ -+ total_size = info->screen_size; -+ -+ if (total_size == 0) -+ total_size = info->fix.smem_len; -+ -+ if (p >= total_size) -+ return 0; -+ -+ if (count >= total_size) -+ count = total_size; -+ -+ if (count + p > total_size) -+ count = total_size - p; -+ -+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ src = (u32 __iomem *) (info->screen_base + p); -+ -+ if (info->fbops->fb_sync) -+ info->fbops->fb_sync(info); -+ -+ while (count) { -+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; -+ dst = buffer; -+ for (i = c >> 2; i--;) { -+ *dst = fb_readl(src++); -+ *dst = -+ (*dst & 0xff00ff00 >> 8) | (*dst & 0x00ff00ff << 8); -+ dst++; -+ } -+ if (c & 3) { -+ u8 *dst8 = (u8 *) dst; -+ u8 __iomem *src8 = (u8 __iomem *) src; -+ -+ for (i = c & 3; i--;) { -+ if (i & 1) { -+ *dst8++ = fb_readb(++src8); -+ } else { -+ *dst8++ = fb_readb(--src8); -+ src8 += 2; -+ } -+ } -+ src = (u32 __iomem *) src8; -+ } -+ -+ if (copy_to_user(buf, buffer, c)) { -+ err = -EFAULT; -+ break; -+ } -+ *ppos += c; -+ buf += c; -+ cnt += c; -+ count -= c; -+ } -+ -+ kfree(buffer); -+ -+ return (err) ? err : cnt; -+} -+ -+static ssize_t -+sm712fb_write(struct fb_info *info, const char __user *buf, size_t count, -+ loff_t *ppos) -+{ -+ unsigned long p = *ppos; -+ -+ u32 *buffer, *src; -+ u32 __iomem *dst; -+ int c, i, cnt = 0, err = 0; -+ unsigned long total_size; -+ -+ if (!info || !info->screen_base) -+ return -ENODEV; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return -EPERM; -+ -+ total_size = info->screen_size; -+ -+ if (total_size == 0) -+ total_size = info->fix.smem_len; -+ -+ if (p > total_size) -+ return -EFBIG; -+ -+ if (count > total_size) { -+ err = -EFBIG; -+ count = total_size; -+ } -+ -+ if (count + p > total_size) { -+ if (!err) -+ err = -ENOSPC; -+ -+ count = total_size - p; -+ } -+ -+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ dst = (u32 __iomem *) (info->screen_base + p); -+ -+ if (info->fbops->fb_sync) -+ info->fbops->fb_sync(info); -+ -+ while (count) { -+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; -+ src = buffer; -+ -+ if (copy_from_user(src, buf, c)) { -+ err = -EFAULT; -+ break; -+ } -+ -+ for (i = c >> 2; i--;) { -+ fb_writel((*src & 0xff00ff00 >> 8) | -+ (*src & 0x00ff00ff << 8), dst++); -+ src++; -+ } -+ if (c & 3) { -+ u8 *src8 = (u8 *) src; -+ u8 __iomem *dst8 = (u8 __iomem *) dst; -+ -+ for (i = c & 3; i--;) { -+ if (i & 1) { -+ fb_writeb(*src8++, ++dst8); -+ } else { -+ fb_writeb(*src8++, --dst8); -+ dst8 += 2; -+ } -+ } -+ dst = (u32 __iomem *) dst8; -+ } -+ -+ *ppos += c; -+ buf += c; -+ cnt += c; -+ count -= c; -+ } -+ -+ kfree(buffer); -+ -+ return (cnt) ? cnt : err; -+} -+#endif /* ! __BIG_ENDIAN */ -+ -+static void sm712_set_timing(struct sm712fb_info *sfb) -+{ -+ int i = 0, j = 0; -+ u32 m_nScreenStride; -+ -+ dev_dbg(&sfb->pdev->dev, -+ "sfb->width=%d sfb->height=%d " -+ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n", -+ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz); -+ -+ for (j = 0; j < numVGAModes; j++) { -+ if (VGAMode[j].mmSizeX != sfb->width || -+ VGAMode[j].mmSizeY != sfb->height || -+ VGAMode[j].bpp != sfb->fb.var.bits_per_pixel || -+ VGAMode[j].hz != sfb->hz) { -+ continue; -+ } -+ -+ dev_dbg(&sfb->pdev->dev, -+ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d " -+ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n", -+ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, -+ VGAMode[j].bpp, VGAMode[j].hz); -+ -+ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j); -+ -+ sm712_writeb(sfb->mmio, 0x3c6, 0x0); -+ -+ sm712_write_seq(sfb, 0, 0x1); -+ -+ sm712_writeb(sfb->mmio, 0x3c2, VGAMode[j].Init_MISC); -+ -+ /* init SEQ register SR00 - SR04 */ -+ for (i = 0; i < SR00_SR04_SIZE; i++) -+ sm712_write_seq(sfb, i, VGAMode[j].Init_SR00_SR04[i]); -+ -+ /* init SEQ register SR10 - SR24 */ -+ for (i = 0; i < SR10_SR24_SIZE; i++) -+ sm712_write_seq(sfb, i + 0x10, -+ VGAMode[j].Init_SR10_SR24[i]); -+ -+ /* init SEQ register SR30 - SR75 */ -+ for (i = 0; i < SR30_SR75_SIZE; i++) -+ if ((i + 0x30) != 0x62 && -+ (i + 0x30) != 0x6a && (i + 0x30) != 0x6b) -+ sm712_write_seq(sfb, i + 0x30, -+ VGAMode[j].Init_SR30_SR75[i]); -+ -+ /* init SEQ register SR80 - SR93 */ -+ for (i = 0; i < SR80_SR93_SIZE; i++) -+ sm712_write_seq(sfb, i + 0x80, -+ VGAMode[j].Init_SR80_SR93[i]); -+ -+ /* init SEQ register SRA0 - SRAF */ -+ for (i = 0; i < SRA0_SRAF_SIZE; i++) -+ sm712_write_seq(sfb, i + 0xa0, -+ VGAMode[j].Init_SRA0_SRAF[i]); -+ -+ /* init Graphic register GR00 - GR08 */ -+ for (i = 0; i < GR00_GR08_SIZE; i++) -+ sm712_write_grph(sfb, i, VGAMode[j].Init_GR00_GR08[i]); -+ -+ /* init Attribute register AR00 - AR14 */ -+ for (i = 0; i < AR00_AR14_SIZE; i++) -+ sm712_write_attr(sfb, i, VGAMode[j].Init_AR00_AR14[i]); -+ -+ /* init CRTC register CR00 - CR18 */ -+ for (i = 0; i < CR00_CR18_SIZE; i++) -+ sm712_write_crtc(sfb, i, VGAMode[j].Init_CR00_CR18[i]); -+ -+ /* init CRTC register CR30 - CR4D */ -+ for (i = 0; i < CR30_CR4D_SIZE; i++) -+ sm712_write_crtc(sfb, i + 0x30, -+ VGAMode[j].Init_CR30_CR4D[i]); -+ -+ /* init CRTC register CR90 - CRA7 */ -+ for (i = 0; i < CR90_CRA7_SIZE; i++) -+ sm712_write_crtc(sfb, i + 0x90, -+ VGAMode[j].Init_CR90_CRA7[i]); -+ } -+ sm712_writeb(sfb->mmio, 0x3c2, 0x67); -+ -+ /* set VPR registers */ -+ sm712_writel(sfb->vpr, 0x0C, 0x0); -+ sm712_writel(sfb->vpr, 0x40, 0x0); -+ -+ /* set data width */ -+ m_nScreenStride = (sfb->width * sfb->fb.var.bits_per_pixel) / 64; -+ switch (sfb->fb.var.bits_per_pixel) { -+ case 8: -+ sm712_writel(sfb->vpr, 0x0, 0x0); -+ break; -+ case 16: -+ sm712_writel(sfb->vpr, 0x0, 0x00020000); -+ break; -+ case 24: -+ sm712_writel(sfb->vpr, 0x0, 0x00040000); -+ break; -+ case 32: -+ sm712_writel(sfb->vpr, 0x0, 0x00030000); -+ break; -+ } -+ sm712_writel(sfb->vpr, 0x10, -+ (u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride)); -+} -+ -+static void sm712fb_setmode(struct sm712fb_info *sfb) -+{ -+ switch (sfb->fb.var.bits_per_pixel) { -+ case 32: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 4; -+ sfb->fb.var.red.length = 8; -+ sfb->fb.var.green.length = 8; -+ sfb->fb.var.blue.length = 8; -+ sfb->fb.var.red.offset = 16; -+ sfb->fb.var.green.offset = 8; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 24: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 3; -+ sfb->fb.var.red.length = 8; -+ sfb->fb.var.green.length = 8; -+ sfb->fb.var.blue.length = 8; -+ sfb->fb.var.red.offset = 16; -+ sfb->fb.var.green.offset = 8; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 8: -+ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres; -+ sfb->fb.var.red.length = 3; -+ sfb->fb.var.green.length = 3; -+ sfb->fb.var.blue.length = 2; -+ sfb->fb.var.red.offset = 5; -+ sfb->fb.var.green.offset = 2; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 16: -+ default: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 2; -+ sfb->fb.var.red.length = 5; -+ sfb->fb.var.green.length = 6; -+ sfb->fb.var.blue.length = 5; -+ sfb->fb.var.red.offset = 11; -+ sfb->fb.var.green.offset = 5; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ } -+ -+ sfb->width = sfb->fb.var.xres; -+ sfb->height = sfb->fb.var.yres; -+ sfb->hz = 60; -+ sm712_set_timing(sfb); -+} -+ -+static int sm712_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ /* sanity checks */ -+ if (var->xres_virtual < var->xres) -+ var->xres_virtual = var->xres; -+ -+ if (var->yres_virtual < var->yres) -+ var->yres_virtual = var->yres; -+ -+ /* set valid default bpp */ -+ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && -+ (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) -+ var->bits_per_pixel = 16; -+ -+ return 0; -+} -+ -+static int sm712_set_par(struct fb_info *info) -+{ -+ sm712fb_setmode(info->par); -+ -+ return 0; -+} -+ -+static struct fb_ops sm712fb_ops = { -+ .owner = THIS_MODULE, -+ .fb_check_var = sm712_check_var, -+ .fb_set_par = sm712_set_par, -+ .fb_setcolreg = sm712_setcolreg, -+ .fb_blank = sm712_blank, -+ .fb_fillrect = cfb_fillrect, -+ .fb_imageblit = cfb_imageblit, -+ .fb_copyarea = cfb_copyarea, -+#ifdef __BIG_ENDIAN -+ .fb_read = sm712fb_read, -+ .fb_write = sm712fb_write, -+#endif -+}; -+ -+/* -+ * alloc struct sm712fb_info and assign default values -+ */ -+static struct sm712fb_info *sm712_fb_info_new(struct pci_dev *pdev) -+{ -+ struct sm712fb_info *sfb; -+ -+ sfb = kzalloc(sizeof(*sfb), GFP_KERNEL); -+ -+ if (!sfb) -+ return NULL; -+ -+ sfb->pdev = pdev; -+ -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT; -+ sfb->fb.fbops = &sm712fb_ops; -+ sfb->fb.fix = sm712fb_fix; -+ sfb->fb.var = sm712fb_var; -+ sfb->fb.pseudo_palette = sfb->colreg; -+ sfb->fb.par = sfb; -+ sfb->accel = accel; -+ -+ return sfb; -+} -+ -+/* -+ * free struct sm712fb_info -+ */ -+static void sm712_fb_info_free(struct sm712fb_info *sfb) -+{ -+ kfree(sfb); -+} -+ -+/* -+ * Map in the screen memory -+ */ -+ -+static int sm712_map_smem(struct sm712fb_info *sfb, -+ struct pci_dev *pdev, u_long smem_len) -+{ -+ -+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); -+ -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 32) -+ sfb->fb.fix.smem_start += 0x800000; -+#endif -+ -+ sfb->fb.fix.smem_len = smem_len; -+ -+ sfb->fb.screen_base = sfb->lfb; -+ -+ if (!sfb->fb.screen_base) { -+ dev_err(&pdev->dev, -+ "%s: unable to map screen memory\n", sfb->fb.fix.id); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Unmap in the screen memory -+ * -+ */ -+static void sm712_unmap_smem(struct sm712fb_info *sfb) -+{ -+ if (sfb && sfb->fb.screen_base) { -+ iounmap(sfb->fb.screen_base); -+ sfb->fb.screen_base = NULL; -+ sfb->lfb = NULL; -+ } -+} -+ -+static inline void sm712_init_hw(struct sm712fb_info *sfb) -+{ -+ /* enable linear memory mode and packed pixel format */ -+ outb_p(0x18, 0x3c4); -+ outb_p(0x11, 0x3c5); -+ -+ /* set MCLK = 14.31818 * (0x16 / 0x2) */ -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x62, 0x3e); -+ -+ /* enable PCI burst */ -+ sm712_write_seq(sfb, 0x17, 0x20); -+ -+#ifdef __BIG_ENDIAN -+ /* enable word swap */ -+ if (sfb->fb.var.bits_per_pixel == 32) -+ sm712_write_seq(sfb, 0x17, 0x30); -+#endif -+ -+ if (!sfb->accel) { -+ dev_info(&sfb->pdev->dev, "2d acceleration was disabled by user.\n"); -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; -+ return; -+ } -+ -+ if (sm712fb_init_accel(sfb) < 0) { -+ dev_info(&sfb->pdev->dev, "failed to enable 2d accleration.\n"); -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; -+ return; -+ } else { -+ sm712fb_ops.fb_fillrect = sm712fb_fillrect; -+ sm712fb_ops.fb_copyarea = sm712fb_copyarea; -+ sm712fb_ops.fb_imageblit = sm712fb_imageblit; -+ sfb->fb.flags |= FBINFO_HWACCEL_COPYAREA | -+ FBINFO_HWACCEL_FILLRECT | -+ FBINFO_HWACCEL_IMAGEBLIT | -+ FBINFO_READS_FAST; -+ dev_info(&sfb->pdev->dev, "sm712fb: enable 2d acceleration.\n"); -+ } -+} -+ -+static int sm712fb_pci_probe(struct pci_dev *pdev, -+ const struct pci_device_id *ent) -+{ -+ struct sm712fb_info *sfb; -+ int err; -+ unsigned long mmio_base; -+ -+#ifndef MODULE -+ char *option = NULL; -+ -+ if (!fb_get_options("sm712fb", &option)) -+ sm712fb_setup(option); -+#endif -+ -+ dev_info(&pdev->dev, "Silicon Motion display driver."); -+ -+ err = pci_enable_device(pdev); /* enable SMTC chip */ -+ if (err) -+ return err; -+ -+ sprintf(sm712fb_fix.id, "sm712fb"); -+ -+ sfb = sm712_fb_info_new(pdev); -+ -+ if (!sfb) { -+ err = -ENOMEM; -+ goto free_fail; -+ } -+ -+ sfb->chip_id = ent->device; -+ -+ pci_set_drvdata(pdev, sfb); -+ -+ /* get mode parameter from sm712_scr_info */ -+ if (sm712_scr_info.lfb_width != 0) { -+ sfb->fb.var.xres = sm712_scr_info.lfb_width; -+ sfb->fb.var.yres = sm712_scr_info.lfb_height; -+ sfb->fb.var.bits_per_pixel = sm712_scr_info.lfb_depth; -+ } else { -+ /* default resolution 1024x600 16bit mode */ -+ sfb->fb.var.xres = SM712_DEFAULT_XRES; -+ sfb->fb.var.yres = SM712_DEFAULT_YRES; -+ sfb->fb.var.bits_per_pixel = SM712_DEFAULT_BPP; -+ } -+ -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 24) -+ sfb->fb.var.bits_per_pixel = (sm712_scr_info.lfb_depth = 32); -+#endif -+ -+ /* Map address and memory detection */ -+ mmio_base = pci_resource_start(pdev, 0); -+ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); -+ -+ if (sfb->chip_id != 0x712) { -+ dev_err(&pdev->dev, -+ "No valid Silicon Motion display chip was detected!"); -+ -+ goto fb_fail; -+ } -+ -+ sfb->fb.fix.mmio_start = mmio_base + SM712_REG_BASE; -+ sfb->fb.fix.mmio_len = SM712_REG_SIZE; -+#ifdef __BIG_ENDIAN -+ sfb->lfb = ioremap(mmio_base, 0x00c00000); -+#else -+ sfb->lfb = ioremap(mmio_base, 0x00800000); -+#endif -+ sfb->mmio = sfb->lfb + SM712_MMIO_BASE; -+ sfb->dpr = sfb->lfb + SM712_DPR_BASE; -+ sfb->vpr = sfb->lfb + SM712_VPR_BASE; -+ sfb->dataport = sfb->lfb + SM712_DATAPORT_BASE; -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 32) { -+ sfb->lfb += 0x800000; -+ dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb); -+ } -+#endif -+ if (!sfb->mmio) { -+ dev_err(&pdev->dev, -+ "%s: unable to map memory mapped IO!", sfb->fb.fix.id); -+ err = -ENOMEM; -+ goto fb_fail; -+ } -+ -+ sm712_init_hw(sfb); -+ -+ /* can support 32 bpp */ -+ if (15 == sfb->fb.var.bits_per_pixel) -+ sfb->fb.var.bits_per_pixel = 16; -+ -+ sfb->fb.var.xres_virtual = sfb->fb.var.xres; -+ sfb->fb.var.yres_virtual = sfb->fb.var.yres; -+ err = sm712_map_smem(sfb, pdev, SM712_VRAM_SIZE); -+ if (err) -+ goto fail; -+ -+ sm712fb_setmode(sfb); -+ -+ err = register_framebuffer(&sfb->fb); -+ if (err < 0) -+ goto fail; -+ -+ dev_info(&pdev->dev, -+ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.", -+ sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres, -+ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); -+ -+ return 0; -+ -+fail: -+ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail."); -+ -+ sm712_unmap_smem(sfb); -+fb_fail: -+ sm712_fb_info_free(sfb); -+free_fail: -+ pci_disable_device(pdev); -+ -+ return err; -+} -+ -+/* -+ * 0x712 (LynxEM+) -+ */ -+static const struct pci_device_id sm712fb_pci_table[] = { -+ {PCI_DEVICE(0x126f, 0x712),}, -+ {0,} -+}; -+ -+static void sm712fb_pci_remove(struct pci_dev *pdev) -+{ -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ sm712_unmap_smem(sfb); -+ unregister_framebuffer(&sfb->fb); -+ sm712_fb_info_free(sfb); -+} -+ -+#ifdef CONFIG_PM -+static int sm712fb_pci_suspend(struct device *device) -+{ -+ struct pci_dev *pdev = to_pci_dev(device); -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ -+ /* set the hw in sleep mode use external clock and self memory refresh -+ * so that we can turn off internal PLLs later on -+ */ -+ sm712_write_seq(sfb, 0x20, (sm712_read_seq(sfb, 0x20) | 0xc0)); -+ sm712_write_seq(sfb, 0x69, (sm712_read_seq(sfb, 0x69) & 0xf7)); -+ -+ console_lock(); -+ fb_set_suspend(&sfb->fb, 1); -+ console_unlock(); -+ -+ /* additionally turn off all function blocks including internal PLLs */ -+ sm712_write_seq(sfb, 0x21, 0xff); -+ -+ return 0; -+} -+ -+static int sm712fb_pci_resume(struct device *device) -+{ -+ struct pci_dev *pdev = to_pci_dev(device); -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ -+ /* reinit hardware */ -+ sm712_init_hw(sfb); -+ -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0xc0)); -+ sm712_write_seq(sfb, 0x33, ((sm712_read_seq(sfb, 0x33) | 0x08) & 0xfb)); -+ -+ sm712fb_setmode(sfb); -+ -+ console_lock(); -+ fb_set_suspend(&sfb->fb, 0); -+ console_unlock(); -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(sm712_pm_ops, sm712fb_pci_suspend, sm712fb_pci_resume); -+#define SM712_PM_OPS (&sm712_pm_ops) -+ -+#else /* !CONFIG_PM */ -+ -+#define SM712_PM_OPS NULL -+ -+#endif /* !CONFIG_PM */ -+ -+static struct pci_driver sm712fb_driver = { -+ .name = "sm712fb", -+ .id_table = sm712fb_pci_table, -+ .probe = sm712fb_pci_probe, -+ .remove = sm712fb_pci_remove, -+ .driver.pm = SM712_PM_OPS, -+}; -+ -+module_pci_driver(sm712fb_driver); -+ -+module_param(accel, bool, S_IRUGO); -+MODULE_PARM_DESC(accel, "Enable or disable 2D Acceleration"); -+ -+MODULE_AUTHOR("Siliconmotion "); -+MODULE_DESCRIPTION("Framebuffer driver for Silicon Motion SM712 Graphic Cards"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.h b/drivers/video/fbdev/sm712fb/sm712fb_drv.h -new file mode 100644 -index 0000000..bf81bff ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.h -@@ -0,0 +1,130 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#ifndef _SM712FB_DRV_H -+#define _SM712FB_DRV_H -+ -+/* -+* Private structure -+*/ -+struct sm712fb_info { -+ struct pci_dev *pdev; -+ struct fb_info fb; -+ u16 chip_id; -+ u8 chip_rev_id; -+ -+ void __iomem *lfb; /* linear frame buffer, the base address */ -+ -+ void __iomem *dpr; /* drawing processor control regs */ -+ void __iomem *vpr; /* video processor control regs */ -+ void __iomem *cpr; /* capture processor control regs */ -+ void __iomem *mmio; /* memory map IO port */ -+ void __iomem *dataport; /* 2d drawing engine data port */ -+ -+ u_int width; -+ u_int height; -+ u_int hz; -+ -+ u32 colreg[17]; -+ -+ bool accel; -+}; -+ -+/* constants for registers operations */ -+ -+#include "sm712fb_io.h" -+ -+#define FB_ACCEL_SMI_LYNX 88 -+ -+#define SM712_DEFAULT_XRES 1024 -+#define SM712_DEFAULT_YRES 600 -+#define SM712_DEFAULT_BPP 16 -+ -+#define SM712_VRAM_SIZE 0x00400000 -+ -+#define SM712_REG_BASE 0x00400000 -+#define SM712_REG_SIZE 0x00400000 -+ -+#define SM712_MMIO_BASE 0x00700000 -+ -+#define SM712_DPR_BASE 0x00408000 -+#define SM712_DPR_SIZE (0x6C + 1) -+ -+#define DPR_COORDS(x, y) (((x) << 16) | (y)) -+ -+#define DPR_SRC_COORDS 0x00 -+#define DPR_DST_COORDS 0x04 -+#define DPR_SPAN_COORDS 0x08 -+#define DPR_DE_CTRL 0x0c -+#define DPR_PITCH 0x10 -+#define DPR_FG_COLOR 0x14 -+#define DPR_BG_COLOR 0x18 -+#define DPR_STRETCH 0x1c -+#define DPR_COLOR_COMPARE 0x20 -+#define DPR_COLOR_COMPARE_MASK 0x24 -+#define DPR_BYTE_BIT_MASK 0x28 -+#define DPR_CROP_TOPLEFT_COORDS 0x2c -+#define DPR_CROP_BOTRIGHT_COORDS 0x30 -+#define DPR_SRC_WINDOW 0x3c -+#define DPR_SRC_BASE 0x40 -+#define DPR_DST_BASE 0x44 -+ -+#define DE_CTRL_START 0x80000000 -+#define DE_CTRL_RTOL 0x08000000 -+#define DE_CTRL_COMMAND_MASK 0x001f0000 -+#define DE_CTRL_COMMAND_SHIFT 16 -+#define DE_CTRL_COMMAND_BITBLT 0x00 -+#define DE_CTRL_COMMAND_SOLIDFILL 0x01 -+#define DE_CTRL_COMMAND_HOST_WRITE 0x08 -+#define DE_CTRL_ROP_ENABLE 0x00008000 -+#define DE_CTRL_ROP_MASK 0x000000ff -+#define DE_CTRL_ROP_SHIFT 0 -+#define DE_CTRL_ROP_SRC 0x0c -+ -+#define DE_CTRL_HOST_SHIFT 22 -+#define DE_CTRL_HOST_MONO 1 -+ -+#define SCR_DE_STATUS 0x16 -+#define SCR_DE_STATUS_MASK 0x18 -+#define SCR_DE_ENGINE_IDLE 0x10 -+ -+#define SM712_VPR_BASE 0x0040c000 -+#define SM712_VPR_SIZE (0x44 + 1) -+ -+#define SM712_DATAPORT_BASE 0x00400000 -+ -+#define SR00_SR04_SIZE (0x04 - 0x00 + 1) -+#define SR10_SR24_SIZE (0x24 - 0x10 + 1) -+#define SR30_SR75_SIZE (0x75 - 0x30 + 1) -+#define SR80_SR93_SIZE (0x93 - 0x80 + 1) -+#define SRA0_SRAF_SIZE (0xAF - 0xA0 + 1) -+#define GR00_GR08_SIZE (0x08 - 0x00 + 1) -+#define AR00_AR14_SIZE (0x14 - 0x00 + 1) -+#define CR00_CR18_SIZE (0x18 - 0x00 + 1) -+#define CR30_CR4D_SIZE (0x4D - 0x30 + 1) -+#define CR90_CRA7_SIZE (0xA7 - 0x90 + 1) -+ -+#define DAC_REG (0x3c8) -+#define DAC_VAL (0x3c9) -+ -+#endif -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_io.h b/drivers/video/fbdev/sm712fb/sm712fb_io.h -new file mode 100644 -index 0000000..93346a0 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_io.h -@@ -0,0 +1,90 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ */ -+ -+ -+#define sm712_writeb(base, reg, dat) writeb(dat, base + reg) -+#define sm712_writew(base, reg, dat) writew(dat, base + reg) -+#define sm712_writel(base, reg, dat) writel(dat, base + reg) -+ -+#define sm712_readb(base, reg) readb(base + reg) -+#define sm712_readw(base, reg) readw(base + reg) -+#define sm712_readl(base, reg) readl(base + reg) -+ -+ -+static inline void sm712_write_crtc(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3d4, reg); -+ sm712_writeb(fb->mmio, 0x3d5, val); -+} -+ -+static inline u8 sm712_read_crtc(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3d4, reg); -+ return sm712_readb(fb->mmio, 0x3d5); -+} -+ -+static inline void sm712_write_grph(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3ce, reg); -+ sm712_writeb(fb->mmio, 0x3cf, val); -+} -+ -+static inline u8 sm712_read_grph(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3ce, reg); -+ return sm712_readb(fb->mmio, 0x3cf); -+} -+ -+static inline void sm712_write_attr(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_readb(fb->mmio, 0x3da); -+ sm712_writeb(fb->mmio, 0x3c0, reg); -+ sm712_readb(fb->mmio, 0x3c1); -+ sm712_writeb(fb->mmio, 0x3c0, val); -+} -+ -+static inline void sm712_write_seq(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3c4, reg); -+ sm712_writeb(fb->mmio, 0x3c5, val); -+} -+ -+static inline u8 sm712_read_seq(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3c4, reg); -+ return sm712_readb(fb->mmio, 0x3c5); -+} -+ -+static inline u32 sm712_read_dpr(struct sm712fb_info *fb, u8 reg) -+{ -+ return sm712_readl(fb->dpr, reg); -+} -+ -+static inline void sm712_write_dpr(struct sm712fb_info *fb, u8 reg, u32 val) -+{ -+ sm712_writel(fb->dpr, reg, val); -+} -+ -+static inline void sm712_write_dataport(struct sm712fb_info *fb, u32 val) -+{ -+ sm712_writel(fb->dataport, 0, val); -+} -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_modedb.h b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h -new file mode 100644 -index 0000000..16ee7e3 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h -@@ -0,0 +1,682 @@ -+/* The next structure holds all information relevant for a specific video mode. -+ */ -+ -+struct ModeInit { -+ int mmSizeX; -+ int mmSizeY; -+ int bpp; -+ int hz; -+ unsigned char Init_MISC; -+ unsigned char Init_SR00_SR04[SR00_SR04_SIZE]; -+ unsigned char Init_SR10_SR24[SR10_SR24_SIZE]; -+ unsigned char Init_SR30_SR75[SR30_SR75_SIZE]; -+ unsigned char Init_SR80_SR93[SR80_SR93_SIZE]; -+ unsigned char Init_SRA0_SRAF[SRA0_SRAF_SIZE]; -+ unsigned char Init_GR00_GR08[GR00_GR08_SIZE]; -+ unsigned char Init_AR00_AR14[AR00_AR14_SIZE]; -+ unsigned char Init_CR00_CR18[CR00_CR18_SIZE]; -+ unsigned char Init_CR30_CR4D[CR30_CR4D_SIZE]; -+ unsigned char Init_CR90_CRA7[CR90_CRA7_SIZE]; -+}; -+ -+/********************************************************************** -+ SM712 Mode table. -+ **********************************************************************/ -+struct ModeInit VGAMode[] = { -+ { -+ /* mode#0: 640 x 480 16Bpp 60Hz */ -+ 640, 480, 16, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ { -+ /* mode#1: 640 x 480 24Bpp 60Hz */ -+ 640, 480, 24, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ { -+ /* mode#0: 640 x 480 32Bpp 60Hz */ -+ 640, 480, 32, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ -+ { /* mode#2: 800 x 600 16Bpp 60Hz */ -+ 800, 600, 16, 60, -+ /* Init_MISC */ -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, -+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, -+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ { /* mode#3: 800 x 600 24Bpp 60Hz */ -+ 800, 600, 24, 60, -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, -+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ { /* mode#7: 800 x 600 32Bpp 60Hz */ -+ 800, 600, 32, 60, -+ /* Init_MISC */ -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, -+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, -+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ /* We use 1024x768 table to light 1024x600 panel for lemote */ -+ { /* mode#4: 1024 x 600 16Bpp 60Hz */ -+ 1024, 600, 16, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, -+ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x00, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, -+ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, -+ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, -+ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#5: 1024 x 768 24Bpp 60Hz */ -+ 1024, 768, 24, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, -+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#4: 1024 x 768 32Bpp 60Hz */ -+ 1024, 768, 32, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, -+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#6: 320 x 240 16Bpp 60Hz */ -+ 320, 240, 16, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, -+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ -+ { /* mode#8: 320 x 240 32Bpp 60Hz */ -+ 320, 240, 32, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, -+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+}; -+ -+#define numVGAModes ARRAY_SIZE(VGAMode) -diff --git a/drivers/video/output.c b/drivers/video/output.c -new file mode 100644 -index 0000000..1446c49 ---- /dev/null -+++ b/drivers/video/output.c -@@ -0,0 +1,133 @@ -+/* -+ * output.c - Display Output Switch driver -+ * -+ * Copyright (C) 2006 Luming Yu -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+ -+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Luming Yu "); -+ -+static ssize_t state_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ ssize_t ret_size = 0; -+ struct output_device *od = to_output_device(dev); -+ if (od->props) -+ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); -+ return ret_size; -+} -+ -+static ssize_t state_store(struct device *dev, struct device_attribute *attr, -+ const char *buf,size_t count) -+{ -+ char *endp; -+ struct output_device *od = to_output_device(dev); -+ int request_state = simple_strtoul(buf,&endp,0); -+ size_t size = endp - buf; -+ -+ if (isspace(*endp)) -+ size++; -+ if (size != count) -+ return -EINVAL; -+ -+ if (od->props) { -+ od->request_state = request_state; -+ od->props->set_state(od); -+ } -+ return count; -+} -+static DEVICE_ATTR_RW(state); -+ -+static void video_output_release(struct device *dev) -+{ -+ struct output_device *od = to_output_device(dev); -+ kfree(od); -+} -+ -+static struct attribute *video_output_attrs[] = { -+ &dev_attr_state.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(video_output); -+ -+static struct class video_output_class = { -+ .name = "video_output", -+ .dev_release = video_output_release, -+ .dev_groups = video_output_groups, -+}; -+ -+struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op) -+{ -+ struct output_device *new_dev; -+ int ret_code = 0; -+ -+ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); -+ if (!new_dev) { -+ ret_code = -ENOMEM; -+ goto error_return; -+ } -+ new_dev->props = op; -+ new_dev->dev.class = &video_output_class; -+ new_dev->dev.parent = dev; -+ dev_set_name(&new_dev->dev, "%s", name); -+ dev_set_drvdata(&new_dev->dev, devdata); -+ ret_code = device_register(&new_dev->dev); -+ if (ret_code) { -+ kfree(new_dev); -+ goto error_return; -+ } -+ return new_dev; -+ -+error_return: -+ return ERR_PTR(ret_code); -+} -+EXPORT_SYMBOL(video_output_register); -+ -+void video_output_unregister(struct output_device *dev) -+{ -+ if (!dev) -+ return; -+ device_unregister(&dev->dev); -+} -+EXPORT_SYMBOL(video_output_unregister); -+ -+static void __exit video_output_class_exit(void) -+{ -+ class_unregister(&video_output_class); -+} -+ -+static int __init video_output_class_init(void) -+{ -+ return class_register(&video_output_class); -+} -+ -+postcore_initcall(video_output_class_init); -+module_exit(video_output_class_exit); -diff --git a/include/linux/sm501.h b/include/linux/sm501.h -index 02fde50..a8677f0 100644 ---- a/include/linux/sm501.h -+++ b/include/linux/sm501.h -@@ -27,6 +27,9 @@ extern unsigned long sm501_set_clock(struct device *dev, - extern unsigned long sm501_find_clock(struct device *dev, - int clksrc, unsigned long req_freq); - -+extern void sm501_configure_gpio(struct device *dev, -+ unsigned int gpio, unsigned char mode); -+ - /* sm501_misc_control - * - * Modify the SM501's MISC_CONTROL register -@@ -122,6 +125,7 @@ struct sm501_reg_init { - #define SM501_USE_AC97 (1<<7) - #define SM501_USE_I2S (1<<8) - #define SM501_USE_GPIO (1<<9) -+#define SM501_USE_PWM (1<<10) - - #define SM501_USE_ALL (0xffffffff) - -diff --git a/include/linux/video_output.h b/include/linux/video_output.h -new file mode 100644 -index 0000000..ed5cdeb ---- /dev/null -+++ b/include/linux/video_output.h -@@ -0,0 +1,57 @@ -+/* -+ * -+ * Copyright (C) 2006 Luming Yu -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ */ -+#ifndef _LINUX_VIDEO_OUTPUT_H -+#define _LINUX_VIDEO_OUTPUT_H -+#include -+#include -+struct output_device; -+struct output_properties { -+ int (*set_state)(struct output_device *); -+ int (*get_status)(struct output_device *); -+}; -+struct output_device { -+ int request_state; -+ struct output_properties *props; -+ struct device dev; -+}; -+#define to_output_device(obj) container_of(obj, struct output_device, dev) -+#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE) -+struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op); -+void video_output_unregister(struct output_device *dev); -+#else -+static struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op) -+{ -+ return ERR_PTR(-ENODEV); -+} -+static void video_output_unregister(struct output_device *dev) -+{ -+ return; -+} -+#endif -+#endif -diff --git a/init/calibrate.c b/init/calibrate.c -index ce635dc..10e775d 100644 ---- a/init/calibrate.c -+++ b/init/calibrate.c -@@ -21,6 +21,7 @@ static int __init lpj_setup(char *str) - - __setup("lpj=", lpj_setup); - -+#ifndef ARCH_HAS_PREPARED_LPJ - #ifdef ARCH_HAS_READ_CURRENT_TIMER - - /* This routine uses the read_current_timer() routine and gets the -@@ -171,6 +172,7 @@ static unsigned long calibrate_delay_direct(void) - return 0; - } - #endif -+#endif /* ARCH_HAS_PREPARED_LPJ */ - - /* - * This is the number of bits of precision for the loops_per_jiffy. Each -@@ -291,6 +293,7 @@ void calibrate_delay(void) - lpj = lpj_fine; - pr_info("Calibrating delay loop (skipped), " - "value calculated using timer frequency.. "); -+#ifndef ARCH_HAS_PREPARED_LPJ - } else if ((lpj = calibrate_delay_is_known())) { - ; - } else if ((lpj = calibrate_delay_direct()) != 0) { -@@ -301,6 +304,7 @@ void calibrate_delay(void) - if (!printed) - pr_info("Calibrating delay loop... "); - lpj = calibrate_delay_converge(); -+#endif /* ARCH_HAS_PREPARED_LPJ */ - } - per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj; - if (!printed) -diff --git a/net/rfkill/core.c b/net/rfkill/core.c -index fa7cd79..616abb5 100644 ---- a/net/rfkill/core.c -+++ b/net/rfkill/core.c -@@ -111,7 +111,7 @@ static LIST_HEAD(rfkill_list); /* list of registered rf switches */ - static DEFINE_MUTEX(rfkill_global_mutex); - static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ - --static unsigned int rfkill_default_state = 1; -+static unsigned int rfkill_default_state; /* default: 0 = radio off */ - module_param_named(default_state, rfkill_default_state, uint, 0444); - MODULE_PARM_DESC(default_state, - "Default initial state for all radio types, 0 = radio off"); -diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl -index 826470d..9e6dc30 100755 ---- a/scripts/recordmcount.pl -+++ b/scripts/recordmcount.pl -@@ -309,14 +309,33 @@ if ($arch eq "x86_64") { - $cc .= " -m64"; - $objcopy .= " -O elf64-sparc"; - } elsif ($arch eq "mips") { -- # To enable module support, we need to enable the -mlong-calls option -- # of gcc for module, after using this option, we can not get the real -- # offset of the calling to _mcount, but the offset of the lui -- # instruction or the addiu one. herein, we record the address of the -- # first one, and then we can replace this instruction by a branch -- # instruction to jump over the profiling function to filter the -- # indicated functions, or swith back to the lui instruction to trace -- # them, which means dynamic tracing. -+ # -+ # To disable tracing, just replace "jal _mcount" with nop; -+ # to enable tracing, replace back. so, the offset 14 is -+ # needed to be recorded. -+ # -+ # 10: 03e0082d move at,ra -+ # 14: 0c000000 jal 0 -+ # 14: R_MIPS_26 _mcount -+ # 14: R_MIPS_NONE *ABS* -+ # 14: R_MIPS_NONE *ABS* -+ # 18: 00020021 nop -+ # -+ # -+ # -+ # If no long call(-mlong-calls), the same to kernel. -+ # -+ # If the module space differs from the kernel space, long -+ # call is needed, as a result, the address of _mcount is -+ # needed to be recorded in a register and then jump from -+ # module space to kernel space via "jalr ". To -+ # disable tracing, "jalr " can be replaced by -+ # nop; to enable tracing, replace it back. Since the -+ # offset of "jalr " is not easy to be matched, -+ # the offset of the 1st _mcount below is recorded and to -+ # disable tracing, "lui v1, 0x0" is substituted with "b -+ # label", which jumps over "jalr "; to enable -+ # tracing, replace it back. - # - # c: 3c030000 lui v1,0x0 - # c: R_MIPS_HI16 _mcount -@@ -328,19 +347,12 @@ if ($arch eq "x86_64") { - # 10: R_MIPS_NONE *ABS* - # 14: 03e0082d move at,ra - # 18: 0060f809 jalr v1 -+ # label: - # -- # for the kernel: -- # -- # 10: 03e0082d move at,ra -- # 14: 0c000000 jal 0 -- # 14: R_MIPS_26 _mcount -- # 14: R_MIPS_NONE *ABS* -- # 14: R_MIPS_NONE *ABS* -- # 18: 00020021 nop - if ($is_module eq "0") { - $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$"; - } else { -- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$"; -+ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_(HI16|26)\\s+_mcount\$"; - } - $objdump .= " -Melf-trad".$endian."mips "; - -diff --git a/scripts/sstrip.sh b/scripts/sstrip.sh -new file mode 100755 -index 0000000..49b973a ---- /dev/null -+++ b/scripts/sstrip.sh -@@ -0,0 +1,59 @@ -+#!/bin/bash -+# sstrip.sh -- strip the section table of an elf file -+# -+# Copyright (C) 2010 Wu Zhangjin, wuzhangjin@gmail.com -+# Licensed under the GPLv2 -+# -+# Since the section table is useless for the embedded device, it can be -+# stripped out. -+# -+# Note: Some bootloader may check the section table but most of the time, it -+# may be not really used, If it really need the section table, it may need the -+# decompressed kernel image. -+ -+# Usage -+ -+function usage -+{ -+cat </dev/null` -+[ "xELF" != "x${FILE_TYPE}" ] && echo "$0: ${IMAGE} is not an ELF file" && exit -1 -+ -+[ "x${V}" == "x1" ] && orig_filesz=`wc -c ${IMAGE} | cut -d' ' -f1` -+ -+# Get the offset of the section table, here get the end of the program section -+filesz=$((`${OBJDUMP} -p ${IMAGE} | grep -m1 filesz | tr -s ' ' | cut -d' ' -f3`)) -+ -+# Truncate it via the dd tool -+dd if=/dev/null bs=1 of=${IMAGE} seek=${filesz} 2>/dev/null -+ -+# Clear the section table information in the ELF header -+# The last 6 bytes of the ELF header are the section table information -+echo -ne "\x00\x00\x00\x00\x00\x00" | dd of=${IMAGE} bs=1 seek=46 count=6 conv=notrunc 2>/dev/null -+ -+# Debug -+if [ "x${V}" == "x1" ]; then -+ echo "----------------------------------------------------------------" -+ echo "Strip the section table at ${filesz} of ${IMAGE}" -+ echo "----------------------------------------------------------------" -+ echo " sstrip: $0" -+ echo " objdump: ${OBJDUMP}" -+ echo "original size: ${orig_filesz}" -+ echo "current size: ${filesz}" -+ echo "reduced size: $((${orig_filesz} - ${filesz}))" -+fi diff --git a/libre/linux-libre/4.0.2-ae91f13af5-loongson-community.patch b/libre/linux-libre/4.0.2-ae91f13af5-loongson-community.patch new file mode 100644 index 000000000..c550ff3da --- /dev/null +++ b/libre/linux-libre/4.0.2-ae91f13af5-loongson-community.patch @@ -0,0 +1,12168 @@ +diff --git a/Makefile b/Makefile +index 0649a60..d43fa5e 100644 +--- a/Makefile ++++ b/Makefile +@@ -297,8 +297,8 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + + HOSTCC = gcc + HOSTCXX = g++ +-HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 +-HOSTCXXFLAGS = -O2 ++HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O3 -fomit-frame-pointer -std=gnu89 ++HOSTCXXFLAGS = -O3 + + ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1) + HOSTCFLAGS += -Wno-unused-value -Wno-unused-parameter \ +@@ -616,7 +616,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE + KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) + else +-KBUILD_CFLAGS += -O2 ++KBUILD_CFLAGS += -O3 + endif + + # Tell gcc to never replace conditional load with a non-conditional one +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index c7a1690..0f854f0 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -333,7 +333,7 @@ config LASAT + + config MACH_LOONGSON + bool "Loongson family of machines" +- select SYS_SUPPORTS_ZBOOT ++ select SYS_SUPPORTS_ZBOOT_UART16550 + help + This enables the support of Loongson family of machines. + +@@ -1640,6 +1640,15 @@ config CPU_LOONGSON2 + bool + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_64BIT_KERNEL ++ select CPU_SUPPORTS_HIGHMEM if ! EMBEDDED ++ select ARCH_WANT_OPTIONAL_GPIOLIB ++ ++config CPU_LOONGSON1 ++ bool ++ select CPU_MIPS32 ++ select CPU_MIPSR2 ++ select CPU_HAS_PREFETCH ++ select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select CPU_SUPPORTS_HUGEPAGES + +@@ -2313,7 +2322,7 @@ config CPU_SUPPORTS_MSA + + config ARCH_FLATMEM_ENABLE + def_bool y +- depends on !NUMA && !CPU_LOONGSON2 ++ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION) + + config ARCH_DISCONTIGMEM_ENABLE + bool +diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile +index 61af6b6..8598044 100644 +--- a/arch/mips/boot/compressed/Makefile ++++ b/arch/mips/boot/compressed/Makefile +@@ -30,9 +30,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ + targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o + + # decompressor objects (linked with vmlinuz) +-vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o ++vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o + + ifdef CONFIG_DEBUG_ZBOOT ++vmlinuzobjs-y += $(obj)/dbg.o + vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o + vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o + endif +@@ -79,9 +80,18 @@ quiet_cmd_zld = LD $@ + cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ + quiet_cmd_strip = STRIP $@ + cmd_strip = $(STRIP) -s $@ ++ifdef CONFIG_EMBEDDED ++quiet_cmd_sstrip = SSTRIP $@ ++ cmd_sstrip = $(srctree)/scripts/sstrip.sh $@ ++endif + vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr + $(call cmd,zld) + $(call cmd,strip) ++ $(call cmd,sstrip) ++ ++vmlinuz.unsstrip: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr ++ $(call cmd,zld) ++ $(call cmd,strip) + + # + # Some DECstations need all possible sections of an ECOFF executable +@@ -94,14 +104,14 @@ endif + hostprogs-y += ../elf2ecoff + + ifdef CONFIG_32BIT +- VMLINUZ = vmlinuz ++ VMLINUZ = vmlinuz.unsstrip + else + VMLINUZ = vmlinuz.32 + endif + + quiet_cmd_32 = OBJCOPY $@ + cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ +-vmlinuz.32: vmlinuz ++vmlinuz.32: vmlinuz.unsstrip + $(call cmd,32) + + quiet_cmd_ecoff = ECOFF $@ +@@ -110,11 +120,11 @@ vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ) + $(call cmd,ecoff) + + OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary +-vmlinuz.bin: vmlinuz ++vmlinuz.bin: vmlinuz.unsstrip + $(call cmd,objcopy) + + OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec +-vmlinuz.srec: vmlinuz ++vmlinuz.srec: vmlinuz.unsstrip + $(call cmd,objcopy) + +-clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} ++clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec,unsstrip} +diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c +index 31903cf..14da73c 100644 +--- a/arch/mips/boot/compressed/decompress.c ++++ b/arch/mips/boot/compressed/decompress.c +@@ -28,8 +28,13 @@ unsigned long free_mem_end_ptr; + extern unsigned char __image_begin, __image_end; + + /* debug interfaces */ ++#ifdef CONFIG_DEBUG_ZBOOT + extern void puts(const char *s); + extern void puthex(unsigned long long val); ++#else ++#define puts(s) ++#define puthex(val) ++#endif + + void error(char *x) + { +diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script +index 5a33409..de04ac9 100644 +--- a/arch/mips/boot/compressed/ld.script ++++ b/arch/mips/boot/compressed/ld.script +@@ -49,5 +49,6 @@ SECTIONS + *(.reginfo) + *(.comment) + *(.note) ++ *(.gnu.attributes) + } + } +diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h +index a0ee0cb..4e18add 100644 +--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h ++++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h +@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo); + /* GPIO : I/O SPACE; REG : 32BITS */ + #define GPIOL_OUT_VAL 0x00 + #define GPIOL_OUT_EN 0x04 ++#define GPIOL_OUT_AUX1_SEL 0x10 ++/* SMB : I/O SPACE, REG : 8BITS WIDTH */ ++#define SMB_SDA 0x00 ++#define SMB_STS 0x01 ++#define SMB_STS_SLVSTP (1 << 7) ++#define SMB_STS_SDAST (1 << 6) ++#define SMB_STS_BER (1 << 5) ++#define SMB_STS_NEGACK (1 << 4) ++#define SMB_STS_STASTR (1 << 3) ++#define SMB_STS_NMATCH (1 << 2) ++#define SMB_STS_MASTER (1 << 1) ++#define SMB_STS_XMIT (1 << 0) ++#define SMB_CTRL_STS 0x02 ++#define SMB_CSTS_TGSTL (1 << 5) ++#define SMB_CSTS_TSDA (1 << 4) ++#define SMB_CSTS_GCMTCH (1 << 3) ++#define SMB_CSTS_MATCH (1 << 2) ++#define SMB_CSTS_BB (1 << 1) ++#define SMB_CSTS_BUSY (1 << 0) ++#define SMB_CTRL1 0x03 ++#define SMB_CTRL1_STASTRE (1 << 7) ++#define SMB_CTRL1_NMINTE (1 << 6) ++#define SMB_CTRL1_GCMEN (1 << 5) ++#define SMB_CTRL1_ACK (1 << 4) ++#define SMB_CTRL1_RSVD (1 << 3) ++#define SMB_CTRL1_INTEN (1 << 2) ++#define SMB_CTRL1_STOP (1 << 1) ++#define SMB_CTRL1_START (1 << 0) ++#define SMB_ADDR 0x04 ++#define SMB_ADDR_SAEN (1 << 7) ++#define SMB_CONTROLLER_ADDR (0xef << 0) ++#define SMB_CTRL2 0x05 ++#define SMB_FREQ (0x20 << 1) ++#define SMB_ENABLE (0x01 << 0) ++#define SMB_CTRL3 0x06 + + #endif /* _CS5536_H */ +diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h +index 021d017..50aafca 100644 +--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h ++++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h +@@ -28,8 +28,19 @@ static inline void __maybe_unused enable_mfgpt0_counter(void) + #define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ) + + #define MFGPT_BASE mfgpt_base ++#define MFGPT0_CMP1 (MFGPT_BASE + 0) + #define MFGPT0_CMP2 (MFGPT_BASE + 2) + #define MFGPT0_CNT (MFGPT_BASE + 4) + #define MFGPT0_SETUP (MFGPT_BASE + 6) + ++#define MFGPT1_CMP1 (MFGPT_BASE + 0x08) ++#define MFGPT1_CMP2 (MFGPT_BASE + 0x0A) ++#define MFGPT1_CNT (MFGPT_BASE + 0x0C) ++#define MFGPT1_SETUP (MFGPT_BASE + 0x0E) ++ ++#define MFGPT2_CMP1 (MFGPT_BASE + 0x10) ++#define MFGPT2_CMP2 (MFGPT_BASE + 0x12) ++#define MFGPT2_CNT (MFGPT_BASE + 0x14) ++#define MFGPT2_SETUP (MFGPT_BASE + 0x16) ++ + #endif /*!_CS5536_MFGPT_H */ +diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h +index 5459ac0..14e82d9 100644 +--- a/arch/mips/include/asm/mach-loongson/loongson.h ++++ b/arch/mips/include/asm/mach-loongson/loongson.h +@@ -46,6 +46,12 @@ static inline void prom_init_uart_base(void) + #endif + } + ++/* ++ * Copy kernel command line from arcs_cmdline ++ */ ++#include ++extern char loongson_cmdline[COMMAND_LINE_SIZE]; ++ + /* irq operation functions */ + extern void bonito_irqdispatch(void); + extern void __init bonito_irq_init(void); +diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h +index cb2b602..78fcd38 100644 +--- a/arch/mips/include/asm/mach-loongson/machine.h ++++ b/arch/mips/include/asm/mach-loongson/machine.h +@@ -24,6 +24,12 @@ + + #endif + ++#ifdef CONFIG_DEXXON_GDIUM ++ ++#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10 ++ ++#endif ++ + #ifdef CONFIG_LOONGSON_MACH3X + + #define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC +diff --git a/arch/mips/include/asm/mach-loongson1/clock.h b/arch/mips/include/asm/mach-loongson1/clock.h +new file mode 100644 +index 0000000..dd1afdb +--- /dev/null ++++ b/arch/mips/include/asm/mach-loongson1/clock.h +@@ -0,0 +1,53 @@ ++#ifndef __ASM_MACH_LOONGSON1_CLOCK_H ++#define __ASM_MACH_LOONGSON1_CLOCK_H ++ ++#include ++#include ++#include ++#include ++ ++extern void (*cpu_wait) (void); ++ ++struct clk; ++ ++struct clk_ops { ++ void (*init) (struct clk *clk); ++ void (*enable) (struct clk *clk); ++ void (*disable) (struct clk *clk); ++ void (*recalc) (struct clk *clk); ++ int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id); ++ long (*round_rate) (struct clk *clk, unsigned long rate); ++}; ++ ++struct clk { ++ struct list_head node; ++ const char *name; ++ int id; ++ struct module *owner; ++ ++ struct clk *parent; ++ struct clk_ops *ops; ++ ++ struct kref kref; ++ ++ unsigned long rate; ++ unsigned long flags; ++}; ++ ++#define CLK_ALWAYS_ENABLED (1 << 0) ++#define CLK_RATE_PROPAGATES (1 << 1) ++ ++/* Should be defined by processor-specific code */ ++void arch_init_clk_ops(struct clk_ops **, int type); ++ ++int clk_init(void); ++ ++int __clk_enable(struct clk *); ++void __clk_disable(struct clk *); ++ ++void clk_recalc_rate(struct clk *); ++ ++int clk_register(struct clk *); ++void clk_unregister(struct clk *); ++ ++#endif /* __ASM_MIPS_CLOCK_H */ +diff --git a/arch/mips/include/asm/mach-loongson1/regs-intc.h b/arch/mips/include/asm/mach-loongson1/regs-intc.h +new file mode 100644 +index 0000000..6d5db23 +--- /dev/null ++++ b/arch/mips/include/asm/mach-loongson1/regs-intc.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (c) 2011 Zhang, Keguang ++ * ++ * Loongson1 Interrupt register definitions. ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_LOONGSON1_REGS_INTC_H ++#define __ASM_MACH_LOONGSON1_REGS_INTC_H ++ ++#define LS1X_INTC_REG(n, x) \ ++ (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4)) ++ ++#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) ++#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) ++#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) ++#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) ++#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) ++#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) ++ ++#endif /* __ASM_MACH_LOONGSON1_REGS_INTC_H */ +diff --git a/arch/mips/include/asm/sparsemem.h b/arch/mips/include/asm/sparsemem.h +index b1071c1..8b8e551 100644 +--- a/arch/mips/include/asm/sparsemem.h ++++ b/arch/mips/include/asm/sparsemem.h +@@ -11,7 +11,11 @@ + #else + # define SECTION_SIZE_BITS 28 + #endif +-#define MAX_PHYSMEM_BITS 48 ++#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit c461731836 broke Loongson2. */ ++# define MAX_PHYSMEM_BITS 48 ++#else ++# define MAX_PHYSMEM_BITS 35 ++#endif + + #endif /* CONFIG_SPARSEMEM */ + #endif /* _MIPS_SPARSEMEM_H */ +diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h +index b05bb70..44c9a69 100644 +--- a/arch/mips/include/asm/timex.h ++++ b/arch/mips/include/asm/timex.h +@@ -11,6 +11,10 @@ + + #ifdef __KERNEL__ + ++#ifdef CONFIG_CSRC_R4K ++#define ARCH_HAS_PREPARED_LPJ ++#endif ++ + #include + + #include +diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h +index fc0cf5a..99e6430 100644 +--- a/arch/mips/include/uapi/asm/inst.h ++++ b/arch/mips/include/uapi/asm/inst.h +@@ -65,6 +65,8 @@ enum spec_op { + enum spec2_op { + madd_op, maddu_op, mul_op, spec2_3_unused_op, + msub_op, msubu_op, /* more unused ops */ ++ loongson_madd_op = 0x18, loongson_msub_op, ++ loongson_nmadd_op, loongson_nmsub_op, + clz_op = 0x20, clo_op, + dclz_op = 0x24, dclo_op, + sdbpp_op = 0x3f +@@ -151,7 +153,7 @@ enum cop0_com_func { + */ + enum cop1_fmt { + s_fmt, d_fmt, e_fmt, q_fmt, +- w_fmt, l_fmt ++ w_fmt, l_fmt, ps_fmt + }; + + /* +@@ -180,7 +182,8 @@ enum cop1_sdw_func { + enum cop1x_func { + lwxc1_op = 0x00, ldxc1_op = 0x01, + swxc1_op = 0x08, sdxc1_op = 0x09, +- pfetch_op = 0x0f, madd_s_op = 0x20, ++ pfetch_op = 0x0f, ++ prefx_op = 0x17, madd_s_op = 0x20, + madd_d_op = 0x21, madd_e_op = 0x22, + msub_s_op = 0x28, msub_d_op = 0x29, + msub_e_op = 0x2a, nmadd_s_op = 0x30, +diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S +index d07b210..69996f2 100644 +--- a/arch/mips/kernel/scall64-o32.S ++++ b/arch/mips/kernel/scall64-o32.S +@@ -26,6 +26,18 @@ + + .align 5 + NESTED(handle_sys, PT_SIZE, sp) ++#ifdef CONFIG_MIPS_USER_RDTSC ++ MFC0 k0, CP0_EPC ++ lw k1, 0(k0) ++ sltiu k1, k1, 0x1c ++ bne k1, zero, 1f # Normal syscall code: 0x0c < 0x1c ++ nop ++ mfc0 v0, CP0_COUNT # Get TSC ++ PTR_ADDIU k0, 4 # ret from syscall ++ MTC0 k0, CP0_EPC ++ eret ++1: ++#endif /* CONFIG_MIPS_USER_RDTSC */ + .set noat + SAVE_SOME + TRACE_IRQS_ON_RELOAD +diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c +index 8d01709..9cd25da 100644 +--- a/arch/mips/kernel/time.c ++++ b/arch/mips/kernel/time.c +@@ -119,6 +119,11 @@ static __init int cpu_has_mfc0_count_bug(void) + + void __init time_init(void) + { ++#ifdef CONFIG_HR_SCHED_CLOCK ++ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) ++ write_c0_count(0); ++#endif ++ + plat_time_init(); + + /* +diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile +index 1e9e900..36fcccc 100644 +--- a/arch/mips/lib/Makefile ++++ b/arch/mips/lib/Makefile +@@ -2,10 +2,14 @@ + # Makefile for MIPS-specific library files.. + # + +-lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ ++lib-y += bitops.o csum_partial.o memcpy.o memset.o \ + mips-atomic.o strlen_user.o strncpy_user.o \ + strnlen_user.o uncached.o + ++ifndef CONFIG_CSRC_R4K ++lib-y += delay.o ++endif ++ + obj-y += iomap.o + obj-$(CONFIG_PCI) += iomap-pci.o + lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y)) +diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig +index 156de85..0a433e6 100644 +--- a/arch/mips/loongson/Kconfig ++++ b/arch/mips/loongson/Kconfig +@@ -32,12 +32,12 @@ config LEMOTE_FULOONG2E + + config LEMOTE_MACH2F + bool "Lemote Loongson 2F family machines" +- select ARCH_SPARSEMEM_ENABLE ++ select ARCH_SPARSEMEM_ENABLE if HIBERNATION + select BOARD_SCACHE + select BOOT_ELF32 + select CEVT_R4K if ! MIPS_EXTERNAL_TIMER + select CPU_HAS_WB +- select CS5536 ++ select CS5536 if PCI + select CSRC_R4K if ! MIPS_EXTERNAL_TIMER + select DMA_NONCOHERENT + select GENERIC_ISA_DMA_SUPPORT_BROKEN +@@ -45,14 +45,13 @@ config LEMOTE_MACH2F + select HW_HAS_PCI + select I8259 + select IRQ_CPU +- select ISA + select SYS_HAS_CPU_LOONGSON2F + select SYS_HAS_EARLY_PRINTK + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL +- select SYS_SUPPORTS_HIGHMEM ++ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED + select SYS_SUPPORTS_LITTLE_ENDIAN +- select LOONGSON_MC146818 ++ select LOONGSON_MC146818 if RTC_DRV_CMOS + help + Lemote Loongson 2F family machines utilize the 2F revision of + Loongson processor and the AMD CS5536 south bridge. +@@ -60,6 +59,31 @@ config LEMOTE_MACH2F + These family machines include fuloong2f mini PC, yeeloong2f notebook, + LingLoong allinone PC and so forth. + ++config DEXXON_GDIUM ++ bool "Dexxon Gdium Netbook" ++ select ARCH_SPARSEMEM_ENABLE ++ select BOARD_SCACHE ++ select BOOT_ELF32 ++ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER ++ select CPU_HAS_WB ++ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER ++ select DMA_NONCOHERENT ++ select GENERIC_ISA_DMA_SUPPORT_BROKEN ++ select HW_HAS_PCI ++ select I8259 ++ select IRQ_CPU ++ select ISA ++ select SYS_HAS_CPU_LOONGSON2F ++ select SYS_HAS_EARLY_PRINTK ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_64BIT_KERNEL ++ select SYS_SUPPORTS_HIGHMEM ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select ARCH_REQUIRE_GPIOLIB ++ select HAVE_PWM if MFD_SM501 ++ help ++ Dexxon gdium netbook based on Loongson 2F and SM502. ++ + config LOONGSON_MACH3X + bool "Generic Loongson 3 family machines" + select ARCH_SPARSEMEM_ENABLE +@@ -152,6 +176,24 @@ config LOONGSON_MC146818 + bool + default n + ++config GDIUM_PWM_CLOCK ++ tristate "Gdium PWM Timer" ++ default n ++ depends on HAVE_PWM && EXPERIMENTAL && BROKEN ++ select MIPS_EXTERNAL_TIMER ++ help ++ This options enables the experimental sm501-pwm based clock. With it, ++ you may be possible to use the loongson2f cpufreq driver. ++ ++config GDIUM_VERSION ++ int "Configure Gdium Version" ++ depends on DEXXON_GDIUM ++ default "3" ++ help ++ I have no information about how to determine which version your board ++ is, If the default config doesn't work for it, please change it to ++ smaller ones. ++ + config LEFI_FIRMWARE_INTERFACE + bool + +diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile +index 7429994..63214c8 100644 +--- a/arch/mips/loongson/Makefile ++++ b/arch/mips/loongson/Makefile +@@ -17,6 +17,12 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ + obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ + + # ++# Dexxon gdium netbook, based on loongson 2F and SM502 ++# ++ ++obj-$(CONFIG_DEXXON_GDIUM) += gdium/ ++ ++# + # All Loongson-3 family machines + # + +diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform +index 0ac20eb..cd957dd 100644 +--- a/arch/mips/loongson/Platform ++++ b/arch/mips/loongson/Platform +@@ -30,4 +30,5 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/ + cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely + load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 + load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 ++load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000 + load-$(CONFIG_LOONGSON_MACH3X) += 0xffffffff80200000 +diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c +index 72fed00..96d5919 100644 +--- a/arch/mips/loongson/common/cmdline.c ++++ b/arch/mips/loongson/common/cmdline.c +@@ -17,10 +17,15 @@ + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ ++#include + #include + + #include + ++/* the kernel command line copied from arcs_cmdline */ ++char loongson_cmdline[COMMAND_LINE_SIZE]; ++EXPORT_SYMBOL(loongson_cmdline); ++ + void __init prom_init_cmdline(void) + { + int prom_argc; +@@ -45,4 +50,31 @@ void __init prom_init_cmdline(void) + } + + prom_init_machtype(); ++ ++ /* append machine specific command line */ ++ switch (mips_machtype) { ++ case MACH_LEMOTE_LL2F: ++ if ((strstr(arcs_cmdline, "video=")) == NULL) ++ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60"); ++ break; ++ case MACH_LEMOTE_FL2F: ++ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL) ++ strcat(arcs_cmdline, " ide_core.ignore_cable=0"); ++ break; ++ case MACH_LEMOTE_ML2F7: ++ /* Mengloong-2F has a 800x480 screen */ ++ if ((strstr(arcs_cmdline, "vga=")) == NULL) ++ strcat(arcs_cmdline, " vga=0x313"); ++ break; ++ case MACH_DEXXON_GDIUM2F10: ++ /* gdium has a 1024x600 screen */ ++ if ((strstr(arcs_cmdline, "video=")) == NULL) ++ strcat(arcs_cmdline, " video=sm501fb:1024x600@60"); ++ break; ++ default: ++ break; ++ } ++ ++ /* copy arcs_cmdline into loongson_cmdline */ ++ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE); + } +diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c +index 045ea3d..1d1db80 100644 +--- a/arch/mips/loongson/common/env.c ++++ b/arch/mips/loongson/common/env.c +@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap; + struct loongson_system_configuration loongson_sysconf; + + u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; ++EXPORT_SYMBOL_GPL(loongson_chipcfg); + u64 loongson_freqctrl[MAX_PACKAGES]; + + unsigned long long smp_group[4]; +diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile +new file mode 100644 +index 0000000..f3f4f51 +--- /dev/null ++++ b/arch/mips/loongson/gdium/Makefile +@@ -0,0 +1,6 @@ ++# Makefile for gdium ++ ++obj-y += irq.o reset.o platform.o ++ ++obj-$(CONFIG_MFD_SM501) += sm501-pwm.o ++obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o +diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c +new file mode 100644 +index 0000000..fdbf42a +--- /dev/null ++++ b/arch/mips/loongson/gdium/gdium-clock.c +@@ -0,0 +1,234 @@ ++/* ++ * Doesn't work really well. When used, the clocksource is producing ++ * bad timings and the clockevent can't be used (don't have one shot feature ++ * thus can't switch on the fly and the pwm is initialised too late to be able ++ * to use it at boot time). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define CLOCK_PWM 1 ++#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */ ++#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ) ++#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */ ++#define CLOCK_PWM_DUTY 50 ++#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4) ++ ++static const char drv_name[] = "gdium-clock"; ++ ++static struct pwm_device *clock_pwm; ++ ++static DEFINE_SPINLOCK(clock_pwm_lock); ++static uint64_t clock_tick; ++ ++static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *cd = dev_id; ++ unsigned long flag; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ clock_tick++; ++ /* wait intn2 to finish */ ++ do { ++ LOONGSON_INTENCLR = (1 << 13); ++ } while (LOONGSON_INTISR & (1 << 13)); ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ ++ if (cd && cd->event_handler) ++ cd->event_handler(cd); ++ ++ return IRQ_HANDLED; ++} ++ ++static cycle_t gdium_pwm_clock_read(struct clocksource *cs) ++{ ++ unsigned long flag; ++ uint32_t jifs; ++ uint64_t ticks; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ jifs = jiffies; ++ ticks = clock_tick; ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ /* return (cycle_t)ticks; */ ++ return (cycle_t)(CLOCK_LATCH * jifs); ++} ++ ++static struct clocksource gdium_pwm_clock_clocksource = { ++ .name = "gdium_csrc", ++ .read = gdium_pwm_clock_read, ++ .mask = CLOCKSOURCE_MASK(64), ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, ++ .shift = 20, ++}; ++ ++/* Debug fs */ ++static int gdium_pwm_clock_show(struct seq_file *s, void *p) ++{ ++ unsigned long flag; ++ uint64_t ticks; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ ticks = clock_tick; ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ seq_printf(s, "%lld\n", ticks); ++ return 0; ++} ++ ++static int gdium_pwm_clock_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, gdium_pwm_clock_show, inode->i_private); ++} ++ ++static const struct file_operations gdium_pwm_clock_fops = { ++ .open = gdium_pwm_clock_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++static struct dentry *debugfs_file; ++ ++static void gdium_pwm_clock_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ /* Nothing to do ... */ ++} ++ ++static struct clock_event_device gdium_pwm_clock_cevt = { ++ .name = "gdium_cevt", ++ .features = CLOCK_EVT_FEAT_PERIODIC, ++ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ ++ .rating = 299, ++ .irq = CLOCK_PWM_IRQ, ++ .set_mode = gdium_pwm_clock_set_mode, ++}; ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "gdium-pwmclk", ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver gdium_pwm_clock_driver = { ++ .driver = { ++ .name = drv_name, ++ .owner = THIS_MODULE, ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int gdium_pwm_clock_drvinit(void) ++{ ++ int ret; ++ struct clocksource *cs = &gdium_pwm_clock_clocksource; ++ struct clock_event_device *cd = &gdium_pwm_clock_cevt; ++ unsigned int cpu = smp_processor_id(); ++ ++ clock_tick = 0; ++ ++ clock_pwm = pwm_request(CLOCK_PWM, drv_name); ++ if (clock_pwm == NULL) { ++ pr_err("unable to request PWM for Gdium clock\n"); ++ return -EBUSY; ++ } ++ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD); ++ if (ret) { ++ pr_err("unable to configure PWM for Gdium clock\n"); ++ goto err_pwm_request; ++ } ++ ret = pwm_enable(clock_pwm); ++ if (ret) { ++ pr_err("unable to enable PWM for Gdium clock\n"); ++ goto err_pwm_request; ++ } ++ ++ cd->cpumask = cpumask_of(cpu); ++ ++ cd->shift = 22; ++ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift); ++ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd); ++ cd->min_delta_ns = clockevent_delta2ns(0xF, cd); ++ clockevents_register_device(&gdium_pwm_clock_cevt); ++ ++ /* SM501 PWM1 connected to intn2 <->ip4 */ ++ LOONGSON_INTPOL = (1 << 13); ++ LOONGSON_INTEDGE &= ~(1 << 13); ++ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt); ++ if (ret) { ++ pr_err("Can't claim irq\n"); ++ goto err_pwm_disable; ++ } ++ ++ cs->rating = 200; ++ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift); ++ ret = clocksource_register(&gdium_pwm_clock_clocksource); ++ if (ret) { ++ pr_err("Can't register clocksource\n"); ++ goto err_irq; ++ } ++ pr_info("Clocksource registered with shift %d and mult %d\n", ++ cs->shift, cs->mult); ++ ++ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO, ++ NULL, NULL, &gdium_pwm_clock_fops); ++ ++ return 0; ++ ++err_irq: ++ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); ++err_pwm_disable: ++ pwm_disable(clock_pwm); ++err_pwm_request: ++ pwm_free(clock_pwm); ++ return ret; ++} ++ ++static void gdium_pwm_clock_drvexit(void) ++{ ++ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); ++ pwm_disable(clock_pwm); ++ pwm_free(clock_pwm); ++} ++ ++ ++static int __devinit gdium_pwm_clock_init(void) ++{ ++ int ret = gdium_pwm_clock_drvinit(); ++ ++ if (ret) { ++ pr_err("Fail to register gdium clock driver\n"); ++ return ret; ++ } ++ ++ return platform_driver_register(&gdium_pwm_clock_driver); ++} ++ ++static void __exit gdium_pwm_clock_cleanup(void) ++{ ++ gdium_pwm_clock_drvexit(); ++ platform_driver_unregister(&gdium_pwm_clock_driver); ++} ++ ++module_init(gdium_pwm_clock_init); ++module_exit(gdium_pwm_clock_cleanup); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("Gdium PWM clock driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:gdium-pwmclk"); +diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c +new file mode 100644 +index 0000000..2415d20 +--- /dev/null ++++ b/arch/mips/loongson/gdium/irq.c +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2007 Lemote Inc. ++ * Author: Fuxin Zhang, zhangfx@lemote.com ++ * ++ * Copyright (c) 2010 yajin ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */ ++#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */ ++#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */ ++ ++void mach_irq_dispatch(unsigned int pending) ++{ ++ if (pending & CAUSEF_IP7) ++ do_IRQ(LOONGSON_TIMER_IRQ); ++ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ ++ do_perfcnt_IRQ(); ++ bonito_irqdispatch(); ++ } else if (pending & CAUSEF_IP3) /* CPU UART */ ++ do_IRQ(LOONGSON_UART_IRQ); ++#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE) ++ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 4); ++#endif ++ else ++ spurious_interrupt(); ++} ++ ++static irqreturn_t ip6_action(int cpl, void *dev_id) ++{ ++ return IRQ_HANDLED; ++} ++ ++struct irqaction ip6_irqaction = { ++ .handler = ip6_action, ++ .name = "cascade", ++ .flags = IRQF_SHARED, ++}; ++ ++void __init mach_init_irq(void) ++{ ++ /* setup north bridge irq (bonito) */ ++ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction); ++} +diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c +new file mode 100644 +index 0000000..ffafba4 +--- /dev/null ++++ b/arch/mips/loongson/gdium/platform.c +@@ -0,0 +1,135 @@ ++/* ++ * Copyright (c) 2009 Philippe Vachon ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define GDIUM_GPIO_BASE 224 ++ ++static struct i2c_board_info __initdata sm502dev_i2c_devices[] = { ++ { ++ I2C_BOARD_INFO("lm75", 0x48), ++ }, ++ { ++ I2C_BOARD_INFO("m41t83", 0x68), ++ }, ++ { ++ I2C_BOARD_INFO("gdium-laptop", 0x40), ++ }, ++}; ++ ++static int sm502dev_backlight_init(struct device *dev) ++{ ++ /* Add gpio request stuff here */ ++ return 0; ++} ++ ++static void sm502dev_backlight_exit(struct device *dev) ++{ ++ /* Add gpio free stuff here */ ++} ++ ++static struct platform_pwm_backlight_data backlight_data = { ++ .pwm_id = 0, ++ .max_brightness = 15, ++ .dft_brightness = 8, ++ .pwm_period_ns = 50000, /* 20 kHz */ ++ .init = sm502dev_backlight_init, ++ .exit = sm502dev_backlight_exit, ++}; ++ ++static struct platform_device backlight = { ++ .name = "pwm-backlight", ++ .dev = { ++ .platform_data = &backlight_data, ++ }, ++ .id = -1, ++}; ++ ++/* ++ * Warning this stunt is very dangerous ++ * as the sm501 gpio have dynamic numbers... ++ */ ++/* bus 0 is the one for the ST7, DS75 etc... */ ++static struct i2c_gpio_platform_data i2c_gpio0_data = { ++#if CONFIG_GDIUM_VERSION > 2 ++ .sda_pin = GDIUM_GPIO_BASE + 13, ++ .scl_pin = GDIUM_GPIO_BASE + 6, ++#else ++ .sda_pin = 192+15, ++ .scl_pin = 192+14, ++#endif ++ .udelay = 5, ++ .timeout = HZ / 10, ++ .sda_is_open_drain = 0, ++ .scl_is_open_drain = 0, ++}; ++ ++static struct platform_device i2c_gpio0_device = { ++ .name = "i2c-gpio", ++ .id = 0, ++ .dev = { .platform_data = &i2c_gpio0_data, }, ++}; ++ ++/* bus 1 is for the CRT/VGA external screen */ ++static struct i2c_gpio_platform_data i2c_gpio1_data = { ++ .sda_pin = GDIUM_GPIO_BASE + 10, ++ .scl_pin = GDIUM_GPIO_BASE + 9, ++ .udelay = 5, ++ .timeout = HZ / 10, ++ .sda_is_open_drain = 0, ++ .scl_is_open_drain = 0, ++}; ++ ++static struct platform_device i2c_gpio1_device = { ++ .name = "i2c-gpio", ++ .id = 1, ++ .dev = { .platform_data = &i2c_gpio1_data, }, ++}; ++ ++static struct platform_device gdium_clock = { ++ .name = "gdium-pwmclk", ++ .id = -1, ++}; ++ ++static struct platform_device *devices[] __initdata = { ++ &i2c_gpio0_device, ++ &i2c_gpio1_device, ++ &backlight, ++ &gdium_clock, ++}; ++ ++static int __init gdium_platform_devices_setup(void) ++{ ++ int ret; ++ ++ pr_info("Registering gdium platform devices\n"); ++ ++ ret = i2c_register_board_info(0, sm502dev_i2c_devices, ++ ARRAY_SIZE(sm502dev_i2c_devices)); ++ ++ if (ret != 0) { ++ pr_info("Error while registering platform devices: %d\n", ret); ++ return ret; ++ } ++ ++ platform_add_devices(devices, ARRAY_SIZE(devices)); ++ ++ return 0; ++} ++ ++/* ++ * some devices are on the pwm stuff which is behind the mfd which is ++ * behind the pci bus so arch_initcall can't work because too early ++ */ ++late_initcall(gdium_platform_devices_setup); +diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c +new file mode 100644 +index 0000000..8289f95 +--- /dev/null ++++ b/arch/mips/loongson/gdium/reset.c +@@ -0,0 +1,22 @@ ++/* Board-specific reboot/shutdown routines ++ * ++ * Copyright (C) 2010 yajin ++ * ++ * 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. ++ */ ++#include ++ ++void mach_prepare_shutdown(void) ++{ ++ LOONGSON_GPIOIE &= ~(1<<1); ++ LOONGSON_GPIODATA |= (1<<1); ++} ++ ++void mach_prepare_reboot(void) ++{ ++ LOONGSON_GPIOIE &= ~(1<<2); ++ LOONGSON_GPIODATA &= ~(1<<2); ++} +diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c +new file mode 100644 +index 0000000..5af3b23 +--- /dev/null ++++ b/arch/mips/loongson/gdium/sm501-pwm.c +@@ -0,0 +1,465 @@ ++/* ++ * SM501 PWM clock ++ * Copyright (C) 2009-2010 Arnaud Patard ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const char drv_name[] = "sm501-pwm"; ++ ++#define INPUT_CLOCK 96 /* MHz */ ++#define PWM_COUNT 3 ++ ++#define SM501PWM_HIGH_COUNTER (1<<20) ++#define SM501PWM_LOW_COUNTER (1<<8) ++#define SM501PWM_CLOCK_DIVIDE (1>>4) ++#define SM501PWM_IP (1<<3) ++#define SM501PWM_I (1<<2) ++#define SM501PWM_E (1<<0) ++ ++struct pwm_device { ++ struct list_head node; ++ struct device *dev; ++ void __iomem *regs; ++ int duty_ns; ++ int period_ns; ++ char enabled; ++ void (*handler)(struct pwm_device *pwm); ++ ++ const char *label; ++ unsigned int use_count; ++ unsigned int pwm_id; ++}; ++ ++struct sm501pwm_info { ++ void __iomem *regs; ++ int irq; ++ struct resource *res; ++ struct device *dev; ++ struct dentry *debugfs; ++ ++ struct pwm_device pwm[3]; ++}; ++ ++int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) ++{ ++ unsigned int high, low, divider; ++ int divider1, divider2; ++ unsigned long long delay; ++ ++ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns) ++ return -EINVAL; ++ ++ /* Get delay ++ * We're loosing some precision but multiplying then dividing ++ * will overflow ++ */ ++ if (period_ns > 1000) { ++ delay = period_ns / 1000; ++ delay *= INPUT_CLOCK; ++ } else { ++ delay = period_ns * 96; ++ delay /= 1000; ++ } ++ ++ /* Get the number of clock low and high */ ++ high = delay * duty_ns / period_ns; ++ low = delay - high; ++ ++ /* Get divider to make 'low' and 'high' fit into 12 bits */ ++ /* No need to say that the divider must be >= 0 */ ++ divider1 = fls(low)-12; ++ divider2 = fls(high)-12; ++ ++ if (divider1 < 0) ++ divider1 = 0; ++ if (divider2 < 0) ++ divider2 = 0; ++ ++ divider = max(divider1, divider2); ++ ++ low >>= divider; ++ high >>= divider; ++ ++ pwm->duty_ns = duty_ns; ++ pwm->period_ns = period_ns; ++ ++ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_config); ++ ++int pwm_enable(struct pwm_device *pwm) ++{ ++ u32 reg; ++ ++ if (!pwm) ++ return -EINVAL; ++ ++ switch (pwm->pwm_id) { ++ case 0: ++ sm501_configure_gpio(pwm->dev->parent, 29, 1); ++ break; ++ case 1: ++ sm501_configure_gpio(pwm->dev->parent, 30, 1); ++ break; ++ case 2: ++ sm501_configure_gpio(pwm->dev->parent, 31, 1); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ reg = readl(pwm->regs); ++ reg |= (SM501PWM_IP | SM501PWM_E); ++ writel(reg, pwm->regs); ++ pwm->enabled = 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(pwm_enable); ++ ++void pwm_disable(struct pwm_device *pwm) ++{ ++ u32 reg; ++ ++ if (!pwm) ++ return; ++ ++ reg = readl(pwm->regs); ++ reg &= ~(SM501PWM_IP | SM501PWM_E); ++ writel(reg, pwm->regs); ++ ++ switch (pwm->pwm_id) { ++ case 0: ++ sm501_configure_gpio(pwm->dev->parent, 29, 0); ++ break; ++ case 1: ++ sm501_configure_gpio(pwm->dev->parent, 30, 0); ++ break; ++ case 2: ++ sm501_configure_gpio(pwm->dev->parent, 31, 0); ++ break; ++ default: ++ break; ++ } ++ pwm->enabled = 0; ++} ++EXPORT_SYMBOL(pwm_disable); ++ ++static DEFINE_MUTEX(pwm_lock); ++static LIST_HEAD(pwm_list); ++ ++struct pwm_device *pwm_request(int pwm_id, const char *label) ++{ ++ struct pwm_device *pwm; ++ int found = 0; ++ ++ mutex_lock(&pwm_lock); ++ ++ list_for_each_entry(pwm, &pwm_list, node) { ++ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) { ++ pwm->use_count++; ++ pwm->label = label; ++ found = 1; ++ break; ++ } ++ } ++ ++ mutex_unlock(&pwm_lock); ++ ++ return (found) ? pwm : NULL; ++} ++EXPORT_SYMBOL(pwm_request); ++ ++void pwm_free(struct pwm_device *pwm) ++{ ++ mutex_lock(&pwm_lock); ++ ++ if (pwm->use_count) { ++ pwm->use_count--; ++ pwm->label = NULL; ++ } else ++ dev_warn(pwm->dev, "PWM device already freed\n"); ++ ++ mutex_unlock(&pwm_lock); ++} ++EXPORT_SYMBOL(pwm_free); ++ ++int pwm_int_enable(struct pwm_device *pwm) ++{ ++ unsigned long conf; ++ ++ if (!pwm || !pwm->regs || !pwm->handler) ++ return -EINVAL; ++ ++ conf = readl(pwm->regs); ++ conf |= SM501PWM_I; ++ writel(conf, pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_int_enable); ++ ++int pwm_int_disable(struct pwm_device *pwm) ++{ ++ unsigned long conf; ++ ++ if (!pwm || !pwm->regs || !pwm->handler) ++ return -EINVAL; ++ ++ conf = readl(pwm->regs); ++ conf &= ~SM501PWM_I; ++ writel(conf, pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_int_disable); ++ ++int pwm_set_handler(struct pwm_device *pwm, ++ void (*handler)(struct pwm_device *pwm)) ++{ ++ if (!pwm || !handler) ++ return -EINVAL; ++ pwm->handler = handler; ++ return 0; ++} ++EXPORT_SYMBOL(pwm_set_handler); ++ ++static irqreturn_t sm501pwm_irq(int irq, void *dev_id) ++{ ++ unsigned long value; ++ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id; ++ struct pwm_device *pwm; ++ int i; ++ ++ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0); ++ ++ /* Check is the interrupt is for us */ ++ if (value & (1<<22)) { ++ for (i = 0 ; i < PWM_COUNT ; i++) { ++ /* ++ * Find which pwm triggered the interrupt ++ * and ack ++ */ ++ value = readl(info->regs + i*4); ++ if (value & SM501PWM_IP) ++ writel(value | SM501PWM_IP, info->regs + i*4); ++ ++ pwm = &info->pwm[i]; ++ if (pwm->handler) ++ pwm->handler(pwm); ++ } ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static void add_pwm(int id, struct sm501pwm_info *info) ++{ ++ struct pwm_device *pwm = &info->pwm[id]; ++ ++ pwm->use_count = 0; ++ pwm->pwm_id = id; ++ pwm->dev = info->dev; ++ pwm->regs = info->regs + id * 4; ++ ++ mutex_lock(&pwm_lock); ++ list_add_tail(&pwm->node, &pwm_list); ++ mutex_unlock(&pwm_lock); ++} ++ ++static void del_pwm(int id, struct sm501pwm_info *info) ++{ ++ struct pwm_device *pwm = &info->pwm[id]; ++ ++ pwm->use_count = 0; ++ pwm->pwm_id = -1; ++ mutex_lock(&pwm_lock); ++ list_del(&pwm->node); ++ mutex_unlock(&pwm_lock); ++} ++ ++/* Debug fs */ ++static int sm501pwm_show(struct seq_file *s, void *p) ++{ ++ struct pwm_device *pwm; ++ ++ mutex_lock(&pwm_lock); ++ list_for_each_entry(pwm, &pwm_list, node) { ++ if (pwm->use_count) { ++ seq_printf(s, "pwm-%d (%12s) %d %d %s\n", ++ pwm->pwm_id, pwm->label, ++ pwm->duty_ns, pwm->period_ns, ++ pwm->enabled ? "on" : "off"); ++ seq_printf(s, " %08x\n", readl(pwm->regs)); ++ } ++ } ++ mutex_unlock(&pwm_lock); ++ ++ return 0; ++} ++ ++static int sm501pwm_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, sm501pwm_show, inode->i_private); ++} ++ ++static const struct file_operations sm501pwm_fops = { ++ .open = sm501pwm_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init sm501pwm_probe(struct platform_device *pdev) ++{ ++ struct sm501pwm_info *info; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ int ret = 0; ++ int res_len; ++ int i; ++ ++ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL); ++ if (!info) { ++ dev_err(dev, "Allocation failure\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ info->dev = dev; ++ platform_set_drvdata(pdev, info); ++ ++ /* Get irq number */ ++ info->irq = platform_get_irq(pdev, 0); ++ if (!info->irq) { ++ dev_err(dev, "no irq found\n"); ++ ret = -ENODEV; ++ goto err_alloc; ++ } ++ ++ /* Get regs address */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(dev, "No memory resource found\n"); ++ ret = -ENODEV; ++ goto err_alloc; ++ } ++ info->res = res; ++ res_len = (res->end - res->start)+1; ++ ++ if (!request_mem_region(res->start, res_len, drv_name)) { ++ dev_err(dev, "Can't request iomem resource\n"); ++ ret = -EBUSY; ++ goto err_alloc; ++ } ++ ++ info->regs = ioremap(res->start, res_len); ++ if (!info->regs) { ++ dev_err(dev, "ioremap failed\n"); ++ ret = -ENOMEM; ++ goto err_mem; ++ } ++ ++ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info); ++ if (ret != 0) { ++ dev_err(dev, "can't get irq\n"); ++ goto err_map; ++ } ++ ++ ++ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1); ++ ++ for (i = 0; i < 3; i++) ++ add_pwm(i, info); ++ ++ dev_info(dev, "SM501 PWM Found at %lx irq %d\n", ++ (unsigned long)info->res->start, info->irq); ++ ++ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO, ++ NULL, info, &sm501pwm_fops); ++ ++ ++ return 0; ++ ++err_map: ++ iounmap(info->regs); ++ ++err_mem: ++ release_mem_region(res->start, res_len); ++ ++err_alloc: ++ kfree(info); ++ platform_set_drvdata(pdev, NULL); ++err: ++ return ret; ++} ++ ++static int sm501pwm_remove(struct platform_device *pdev) ++{ ++ struct sm501pwm_info *info = platform_get_drvdata(pdev); ++ int i; ++ ++ if (info->debugfs) ++ debugfs_remove(info->debugfs); ++ ++ for (i = 0; i < 3; i++) { ++ pwm_disable(&info->pwm[i]); ++ del_pwm(i, info); ++ } ++ ++ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0); ++ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22); ++ ++ free_irq(info->irq, info); ++ iounmap(info->regs); ++ release_mem_region(info->res->start, ++ (info->res->end - info->res->start)+1); ++ kfree(info); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static struct platform_driver sm501pwm_driver = { ++ .probe = sm501pwm_probe, ++ .remove = sm501pwm_remove, ++ .driver = { ++ .name = drv_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __devinit sm501pwm_init(void) ++{ ++ return platform_driver_register(&sm501pwm_driver); ++} ++ ++static void __exit sm501pwm_cleanup(void) ++{ ++ platform_driver_unregister(&sm501pwm_driver); ++} ++ ++module_init(sm501pwm_init); ++module_exit(sm501pwm_cleanup); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("SM501 PWM driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:sm501-pwm"); +diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile +index 4f9eaa3..f945bd7a 100644 +--- a/arch/mips/loongson/lemote-2f/Makefile ++++ b/arch/mips/loongson/lemote-2f/Makefile +@@ -2,7 +2,7 @@ + # Makefile for lemote loongson2f family machines + # + +-obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o ++obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o platform.o + + # + # Suspend Support +diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c +new file mode 100644 +index 0000000..5316360 +--- /dev/null ++++ b/arch/mips/loongson/lemote-2f/platform.c +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++ ++static struct platform_device yeeloong_pdev = { ++ .name = "yeeloong_laptop", ++ .id = -1, ++}; ++ ++static struct platform_device lynloong_pdev = { ++ .name = "lynloong_pc", ++ .id = -1, ++}; ++ ++static int __init lemote2f_platform_init(void) ++{ ++ struct platform_device *pdev = NULL; ++ ++ switch (mips_machtype) { ++ case MACH_LEMOTE_YL2F89: ++ pdev = &yeeloong_pdev; ++ break; ++ case MACH_LEMOTE_LL2F: ++ pdev = &lynloong_pdev; ++ break; ++ default: ++ break; ++ ++ } ++ ++ if (pdev != NULL) ++ return platform_device_register(pdev); ++ ++ return -ENODEV; ++} ++ ++arch_initcall(lemote2f_platform_init); +diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c +index b30bf65..c0177cb 100644 +--- a/arch/mips/math-emu/cp1emu.c ++++ b/arch/mips/math-emu/cp1emu.c +@@ -7,6 +7,9 @@ + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. + * ++ * Loongson instruction support ++ * Copyright (C) 2011 Mark H Weaver ++ * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. +@@ -60,6 +63,11 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, + static int fpux_emu(struct pt_regs *, + struct mips_fpu_struct *, mips_instruction, void *__user *); + ++#ifdef CONFIG_MACH_LOONGSON ++static int loongson_spec2_emu(struct pt_regs *, ++ struct mips_fpu_struct *, mips_instruction, void *__user *); ++#endif ++ + /* Control registers */ + + #define FPCREG_RID 0 /* $0 = revision id */ +@@ -842,6 +850,14 @@ do { \ + #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) + #define DPTOREG(dp, x) DITOREG((dp).bits, x) + ++/* Support for Loongson paired single floating-point format */ ++#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \ ++ (si1) = (u32)di; (si2) = (u32)(di >> 32); }) ++#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x) ++ ++#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x) ++#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x) ++ + /* + * Emulate the single floating point instruction pointed at by EPC. + * Two instructions if the instruction is in a branch delay slot. +@@ -1235,6 +1251,16 @@ emul: + xcp->regs[MIPSInst_RD(ir)] = + xcp->regs[MIPSInst_RS(ir)]; + break; ++ ++#ifdef CONFIG_MACH_LOONGSON ++ case spec2_op:{ ++ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr); ++ if (sig) ++ return sig; ++ break; ++ } ++#endif ++ + default: + sigill: + return SIGILL; +@@ -1312,6 +1338,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); + DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); + DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); + ++#ifdef CONFIG_MACH_LOONGSON ++static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ++ mips_instruction ir, void *__user *fault_addr) ++{ ++ int rfmt; /* resulting format */ ++ unsigned rcsr = 0; /* resulting csr */ ++ union { ++ union ieee754dp d; ++ struct { ++ union ieee754sp s; ++ union ieee754sp s2; ++ }; ++ } rv; /* resulting value */ ++ ++ /* XXX maybe add a counter for loongson spec2 fp instructions? */ ++ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */ ++ ++ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { ++ case s_fmt:{ ++ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); ++ union ieee754sp fd, fs, ft; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_sp_madd; ++ goto scoptop; ++ case loongson_msub_op: ++ handler = fpemu_sp_msub; ++ goto scoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_sp_nmadd; ++ goto scoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_sp_nmsub; ++ goto scoptop; ++ ++ scoptop: ++ SPFROMREG(fd, MIPSInst_FD(ir)); ++ SPFROMREG(fs, MIPSInst_FS(ir)); ++ SPFROMREG(ft, MIPSInst_FT(ir)); ++ rv.s = (*handler) (fd, fs, ft); ++ ++ copcsr: ++ if (ieee754_cxtest(IEEE754_INEXACT)) ++ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; ++ if (ieee754_cxtest(IEEE754_UNDERFLOW)) ++ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; ++ if (ieee754_cxtest(IEEE754_OVERFLOW)) ++ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; ++ if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) ++ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; ++ ++ break; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ case d_fmt:{ ++ union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); ++ union ieee754dp fd, fs, ft; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_dp_madd; ++ goto dcoptop; ++ case loongson_msub_op: ++ handler = fpemu_dp_msub; ++ goto dcoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_dp_nmadd; ++ goto dcoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_dp_nmsub; ++ goto dcoptop; ++ ++ dcoptop: ++ DPFROMREG(fd, MIPSInst_FD(ir)); ++ DPFROMREG(fs, MIPSInst_FS(ir)); ++ DPFROMREG(ft, MIPSInst_FT(ir)); ++ rv.d = (*handler) (fd, fs, ft); ++ goto copcsr; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ case ps_fmt:{ ++ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fd1, fs1, ft1; ++ union ieee754sp fd2, fs2, ft2; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_sp_madd; ++ goto pscoptop; ++ case loongson_msub_op: ++ handler = fpemu_sp_msub; ++ goto pscoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_sp_nmadd; ++ goto pscoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_sp_nmsub; ++ goto pscoptop; ++ ++ pscoptop: ++ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir)); ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); ++ rv.s = (*handler) (fd1, fs1, ft1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler) (fd2, fs2, ft2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ default: ++ return SIGILL; ++ } ++ ++ /* ++ * Update the fpu CSR register for this operation. ++ * If an exception is required, generate a tidy SIGFPE exception, ++ * without updating the result register. ++ * Note: cause exception bits do not accumulate, they are rewritten ++ * for each op; only the flag/sticky bits accumulate. ++ */ ++ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; ++ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { ++ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ ++ return SIGFPE; ++ } ++ ++ /* ++ * Now we can safely write the result back to the register file. ++ */ ++ switch (rfmt) { ++ case d_fmt: ++ DPTOREG(rv.d, MIPSInst_FD(ir)); ++ break; ++ case s_fmt: ++ SPTOREG(rv.s, MIPSInst_FD(ir)); ++ break; ++ case ps_fmt: ++ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); ++ break; ++ default: ++ return SIGILL; ++ } ++ ++ return 0; ++} ++#endif ++ + static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + mips_instruction ir, void *__user *fault_addr) + { +@@ -1413,7 +1605,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + break; + + default: +- return SIGILL; ++ goto SIGILL_unless_prefx_op; + } + break; + } +@@ -1483,7 +1675,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + goto copcsr; + + default: +- return SIGILL; ++ goto SIGILL_unless_prefx_op; + } + break; + } +@@ -1496,6 +1688,11 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + break; + + default: ++ SIGILL_unless_prefx_op: ++ if (MIPSInst_FUNC(ir) == prefx_op) { ++ /* ignore prefx operation */ ++ break; ++ } + return SIGILL; + } + +@@ -1517,7 +1714,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + unsigned cond; + union { + union ieee754dp d; +- union ieee754sp s; ++ struct { ++ union ieee754sp s; ++#ifdef CONFIG_MACH_LOONGSON ++ union ieee754sp s2; /* for Loongson paired singles */ ++#endif ++ }; + int w; + s64 l; + } rv; /* resulting value */ +@@ -1614,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + case fmov_op: + /* an easy one */ + SPFROMREG(rv.s, MIPSInst_FS(ir)); +- goto copcsr; ++ break; + + /* binary op on handler */ + scopbop: +@@ -1811,7 +2013,7 @@ copcsr: + case fmov_op: + /* an easy one */ + DPFROMREG(rv.d, MIPSInst_FS(ir)); +- goto copcsr; ++ break; + + /* binary op on handler */ + dcopbop: +@@ -1928,6 +2130,83 @@ dcopuop: + break; + } + ++#ifdef CONFIG_MACH_LOONGSON ++ case ps_fmt:{ /* 6 */ ++ /* Support for Loongson paired single fp instructions */ ++ union { ++ union ieee754sp(*b) (union ieee754sp, union ieee754sp); ++ union ieee754sp(*u) (union ieee754sp); ++ } handler; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ /* binary ops */ ++ case fadd_op: ++ handler.b = ieee754sp_add; ++ goto pscopbop; ++ case fsub_op: ++ handler.b = ieee754sp_sub; ++ goto pscopbop; ++ case fmul_op: ++ handler.b = ieee754sp_mul; ++ goto pscopbop; ++ ++ /* unary ops */ ++ case fabs_op: ++ handler.u = ieee754sp_abs; ++ goto pscopuop; ++ case fneg_op: ++ handler.u = ieee754sp_neg; ++ goto pscopuop; ++ case fmov_op: ++ /* an easy one */ ++ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir)); ++ break; ++ ++ pscopbop: /* paired binary op handler */ ++ { ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fs1, ft1; ++ union ieee754sp fs2, ft2; ++ ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); ++ rv.s = (*handler.b) (fs1, ft1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler.b) (fs2, ft2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ } ++ pscopuop: /* paired unary op handler */ ++ { ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fs1; ++ union ieee754sp fs2; ++ ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ rv.s = (*handler.u) (fs1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler.u) (fs2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ } ++ break; ++ ++ default: ++ if (MIPSInst_FUNC(ir) >= fcmp_op) { ++ /* Loongson fp hardware handles all ++ cases of fp compare insns, so we ++ shouldn't have to */ ++ printk ("Loongson paired-single fp compare" ++ " unimplemented in cp1emu.c\n"); ++ } ++ return SIGILL; ++ } ++ break; ++ } ++#endif ++ + case l_fmt: + + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) +@@ -1999,6 +2278,11 @@ dcopuop: + + DITOREG(rv.l, MIPSInst_FD(ir)); + break; ++#ifdef CONFIG_MACH_LOONGSON ++ case ps_fmt: ++ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); ++ break; ++#endif + default: + return SIGILL; + } +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index 300591c..ed272e2 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o + obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o + obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o + obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o ++obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o + obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3.o + obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o + obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o +diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c +new file mode 100644 +index 0000000..b296220 +--- /dev/null ++++ b/arch/mips/pci/fixup-gdium.c +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (C) 2010 yajin ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++/* ++ * http://www.pcidatabase.com ++ * GDIUM has different PCI mapping ++ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI ++ * slog 14 (0x126f/0x0501) -> sm501 ++ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers ++ * plus Single EHCI controller ++ * slot 16 (0x10ec/0x8139) -> Realtek 8139c ++ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller ++ */ ++ ++#undef INT_IRQA ++#undef INT_IRQB ++#undef INT_IRQC ++#undef INT_IRQD ++#define INT_IRQA 36 ++#define INT_IRQB 37 ++#define INT_IRQC 38 ++#define INT_IRQD 39 ++ ++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ int irq = 0; ++ ++ switch (slot) { ++ case 13: ++ irq = INT_IRQC + ((pin - 1) & 3); ++ break; ++ case 14: ++ irq = INT_IRQA; ++ break; ++ case 15: ++#if CONFIG_GDIUM_VERSION > 2 ++ irq = INT_IRQB; ++#else ++ irq = INT_IRQA + ((pin - 1) & 3); ++#endif ++ break; ++ case 16: ++ irq = INT_IRQD; ++ break; ++#if CONFIG_GDIUM_VERSION > 2 ++ case 17: ++ irq = INT_IRQC; ++ break; ++#endif ++ default: ++ pr_info(" strange pci slot number %d on gdium.\n", slot); ++ break; ++ } ++ return irq; ++} ++ ++/* Do platform specific device initialization at pci_enable_device() time */ ++int pcibios_plat_dev_init(struct pci_dev *dev) ++{ ++ return 0; ++} ++ ++/* Fixups for the USB host controllers */ ++static void __init gdium_usb_host_fixup(struct pci_dev *dev) ++{ ++ unsigned int val; ++ pci_read_config_dword(dev, 0xe0, &val); ++#if CONFIG_GDIUM_VERSION > 2 ++ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3); ++#else ++ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5); ++ pci_write_config_dword(dev, 0xe4, 1<<5); ++#endif ++} ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, ++ gdium_usb_host_fixup); ++#if CONFIG_GDIUM_VERSION > 2 ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550, ++ gdium_usb_host_fixup); ++#endif +diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S +index e7567c8..498e42d 100644 +--- a/arch/mips/power/hibernate.S ++++ b/arch/mips/power/hibernate.S +@@ -30,8 +30,10 @@ LEAF(swsusp_arch_suspend) + END(swsusp_arch_suspend) + + LEAF(swsusp_arch_resume) ++#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit 771004298d broke Loongson2. */ + /* Avoid TLB mismatch during and after kernel resume */ + jal local_flush_tlb_all ++#endif + PTR_L t0, restore_pblist + 0: + PTR_L t1, PBE_ADDRESS(t0) /* source */ +diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c +index fc897ba..ac60f6b 100644 +--- a/drivers/cpufreq/loongson2_cpufreq.c ++++ b/drivers/cpufreq/loongson2_cpufreq.c +@@ -161,20 +161,32 @@ static int __init cpufreq_init(void) + /* Register platform stuff */ + ret = platform_driver_register(&platform_driver); + if (ret) +- return ret; ++ goto err_return; + + pr_info("cpufreq: Loongson-2F CPU frequency driver.\n"); + +- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, +- CPUFREQ_TRANSITION_NOTIFIER); ++ ret = cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ if (ret) ++ goto err_platform_driver_unregister; + + ret = cpufreq_register_driver(&loongson2_cpufreq_driver); ++ if (ret) ++ goto err_cpufreq_unregister_notifier; + +- if (!ret && !nowait) { ++ if (!nowait) { + saved_cpu_wait = cpu_wait; + cpu_wait = loongson2_cpu_wait; + } + ++ return 0; ++ ++ err_cpufreq_unregister_notifier: ++ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ err_platform_driver_unregister: ++ platform_driver_unregister(&platform_driver); ++ err_return: + return ret; + } + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 152b006..767d8de 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -871,6 +871,13 @@ config HID_ZYDACRON + ---help--- + Support for Zydacron remote control. + ++config HID_GDIUM ++ bool "Gdium Fn keys support" if EMBEDDED ++ depends on USB_HID && DEXXON_GDIUM ++ default !EMBEDDED ++ ---help--- ++ Support for Functions keys available on Gdiums. ++ + config HID_SENSOR_HUB + tristate "HID Sensors framework support" + depends on HID && HAS_IOMEM +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 6f19958..2740ff0 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -99,6 +99,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o + wacom-objs := wacom_wac.o wacom_sys.o + obj-$(CONFIG_HID_WACOM) += wacom.o + obj-$(CONFIG_HID_WALTOP) += hid-waltop.o ++obj-$(CONFIG_HID_GDIUM) += hid-gdium.o + obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o + obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o + +diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c +new file mode 100644 +index 0000000..67cc095 +--- /dev/null ++++ b/drivers/hid/hid-gdium.c +@@ -0,0 +1,210 @@ ++/* ++ * hid-gdium -- Gdium laptop function keys ++ * ++ * Arnaud Patard ++ * ++ * Based on hid-apple.c ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++#define GDIUM_FN_ON 1 ++ ++static int fnmode = GDIUM_FN_ON; ++module_param(fnmode, int, 0644); ++MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)"); ++ ++struct gdium_data { ++ unsigned int fn_on; ++}; ++ ++ ++struct gdium_key_translation { ++ u16 from; ++ u16 to; ++}; ++ ++static struct gdium_key_translation gdium_fn_keys[] = { ++ { KEY_F1, KEY_CAMERA }, ++ { KEY_F2, KEY_CONNECT }, ++ { KEY_F3, KEY_MUTE }, ++ { KEY_F4, KEY_VOLUMEUP}, ++ { KEY_F5, KEY_VOLUMEDOWN }, ++ { KEY_F6, KEY_SWITCHVIDEOMODE }, ++ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */ ++ { KEY_F8, KEY_BRIGHTNESSUP }, ++ { KEY_F9, KEY_BRIGHTNESSDOWN }, ++ { KEY_F10, KEY_SLEEP }, ++ { KEY_F11, KEY_PROG1 }, ++ { KEY_F12, KEY_PROG2 }, ++ { KEY_UP, KEY_PAGEUP }, ++ { KEY_DOWN, KEY_PAGEDOWN }, ++ { KEY_INSERT, KEY_NUMLOCK }, ++ { KEY_DELETE, KEY_SCROLLLOCK }, ++ { KEY_T, KEY_STOPCD }, ++ { KEY_F, KEY_PREVIOUSSONG }, ++ { KEY_H, KEY_NEXTSONG }, ++ { KEY_G, KEY_PLAYPAUSE }, ++ { } ++}; ++ ++static struct gdium_key_translation *gdium_find_translation( ++ struct gdium_key_translation *table, u16 from) ++{ ++ struct gdium_key_translation *trans; ++ ++ /* Look for the translation */ ++ for (trans = table; trans->from; trans++) ++ if (trans->from == from) ++ return trans; ++ return NULL; ++} ++ ++static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input, ++ struct hid_usage *usage, __s32 value) ++{ ++ struct gdium_data *data = hid_get_drvdata(hid); ++ struct gdium_key_translation *trans; ++ int do_translate; ++ ++ if (usage->type != EV_KEY) ++ return 0; ++ ++ if ((usage->code == KEY_FN)) { ++ data->fn_on = !!value; ++ input_event(input, usage->type, usage->code, value); ++ return 1; ++ } ++ ++ if (fnmode) { ++ trans = gdium_find_translation(gdium_fn_keys, usage->code); ++ if (trans) { ++ do_translate = data->fn_on; ++ if (do_translate) { ++ input_event(input, usage->type, trans->to, value); ++ return 1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int gdium_input_event(struct hid_device *hdev, struct hid_field *field, ++ struct hid_usage *usage, __s32 value) ++{ ++ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type) ++ return 0; ++ ++ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value)) ++ return 1; ++ ++ return 0; ++} ++ ++ ++static void gdium_input_setup(struct input_dev *input) ++{ ++ struct gdium_key_translation *trans; ++ ++ set_bit(KEY_NUMLOCK, input->keybit); ++ ++ /* Enable all needed keys */ ++ for (trans = gdium_fn_keys; trans->from; trans++) ++ set_bit(trans->to, input->keybit); ++} ++ ++static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) ++ && ((usage->hid & HID_USAGE) == 0x82)) { ++ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); ++ gdium_input_setup(hi->input); ++ return 1; ++ } ++ return 0; ++} ++ ++static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ struct gdium_data *data; ++ int ret; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) { ++ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n"); ++ return -ENOMEM; ++ } ++ ++ hid_set_drvdata(hdev, data); ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ dev_err(&hdev->dev, "parse failed\n"); ++ goto err_free; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ++ if (ret) { ++ dev_err(&hdev->dev, "hw start failed\n"); ++ goto err_free; ++ } ++ ++ return 0; ++err_free: ++ kfree(data); ++ return ret; ++} ++static void gdium_input_remove(struct hid_device *hdev) ++{ ++ hid_hw_stop(hdev); ++ kfree(hid_get_drvdata(hdev)); ++} ++ ++static const struct hid_device_id gdium_input_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) }, ++ {} ++}; ++MODULE_DEVICE_TABLE(hid, gdium_input_devices); ++ ++static struct hid_driver gdium_input_driver = { ++ .name = "gdium-fnkeys", ++ .id_table = gdium_input_devices, ++ .probe = gdium_input_probe, ++ .remove = gdium_input_remove, ++ .event = gdium_input_event, ++ .input_mapping = gdium_input_mapping, ++}; ++ ++static int gdium_input_init(void) ++{ ++ int ret; ++ ++ ret = hid_register_driver(&gdium_input_driver); ++ if (ret) ++ pr_err("can't register gdium keyboard driver\n"); ++ ++ return ret; ++} ++static void gdium_input_exit(void) ++{ ++ hid_unregister_driver(&gdium_input_driver); ++} ++ ++module_init(gdium_input_init); ++module_exit(gdium_input_exit); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 7fe5590..3087a7f 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -1025,6 +1025,9 @@ + #define USB_VENDOR_ID_ZYTRONIC 0x14c8 + #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 + ++#define USB_VENDOR_ID_GDIUM 0x04B4 ++#define USB_DEVICE_ID_GDIUM 0xe001 ++ + #define USB_VENDOR_ID_PRIMAX 0x0461 + #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 + +diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c +index 376f2dc..b576801 100644 +--- a/drivers/ide/ide-iops.c ++++ b/drivers/ide/ide-iops.c +@@ -27,6 +27,10 @@ + #include + #include + ++#ifdef CONFIG_LEMOTE_MACH2F ++#include ++#endif ++ + void SELECT_MASK(ide_drive_t *drive, int mask) + { + const struct ide_port_ops *port_ops = drive->hwif->port_ops; +@@ -300,6 +304,11 @@ void ide_check_nien_quirk_list(ide_drive_t *drive) + { + const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; + ++#ifdef CONFIG_LEMOTE_MACH2F ++ if (mips_machtype != MACH_LEMOTE_YL2F89) ++ return; ++#endif ++ + for (list = nien_quirk_list; *list != NULL; list++) + if (strstr(m, *list) != NULL) { + drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; +diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c +index 91077ef..2cfd9ff 100644 +--- a/drivers/mfd/sm501.c ++++ b/drivers/mfd/sm501.c +@@ -58,7 +58,7 @@ struct sm501_gpio { + struct sm501_gpio { + /* no gpio support, empty definition for sm501_devdata. */ + }; +-#endif ++#endif /* CONFIG_MFD_SM501_GPIO */ + + struct sm501_devdata { + spinlock_t reg_lock; +@@ -1124,6 +1124,22 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) + { + return sm->gpio.registered; + } ++ ++void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned ++ char mode) ++{ ++ unsigned long set, reg, offset = gpio; ++ ++ if (offset >= 32) { ++ reg = SM501_GPIO63_32_CONTROL; ++ offset = gpio - 32; ++ } else ++ reg = SM501_GPIO31_0_CONTROL; ++ ++ set = mode ? 1 << offset : 0; ++ ++ sm501_modify_reg(dev, reg, set, 0); ++} + #else + static inline int sm501_register_gpio(struct sm501_devdata *sm) + { +@@ -1143,7 +1159,13 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) + { + return 0; + } +-#endif ++ ++void sm501_configure_gpio(struct device *dev, unsigned int gpio, ++ unsigned char mode) ++{ ++} ++#endif /* CONFIG_MFD_SM501_GPIO */ ++EXPORT_SYMBOL_GPL(sm501_configure_gpio); + + static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, + struct sm501_platdata_gpio_i2c *iic) +@@ -1198,6 +1220,20 @@ static int sm501_register_gpio_i2c(struct sm501_devdata *sm, + return 0; + } + ++/* register sm501 PWM device */ ++static int sm501_register_pwm(struct sm501_devdata *sm) ++{ ++ struct platform_device *pdev; ++ ++ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0); ++ if (!pdev) ++ return -ENOMEM; ++ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC); ++ sm501_create_irq(sm, &pdev->resource[1]); ++ ++ return sm501_register_device(sm, pdev); ++} ++ + /* sm501_dbg_regs + * + * Debug attribute to attach to parent device to show core registers +@@ -1356,6 +1392,8 @@ static int sm501_init_dev(struct sm501_devdata *sm) + sm501_register_uart(sm, idata->devices); + if (idata->devices & SM501_USE_GPIO) + sm501_register_gpio(sm); ++ if (idata->devices & SM501_USE_PWM) ++ sm501_register_pwm(sm); + } + + if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { +@@ -1542,10 +1580,15 @@ static struct sm501_initdata sm501_pci_initdata = { + .devices = SM501_USE_ALL, + + /* Errata AB-3 says that 72MHz is the fastest available +- * for 33MHZ PCI with proper bus-mastering operation */ +- ++ * for 33MHZ PCI with proper bus-mastering operation ++ * For gdium, it works under 84&112M clock freq.*/ ++#ifdef CONFIG_DEXXON_GDIUM ++ .mclk = 84 * MHZ, ++ .m1xclk = 112 * MHZ, ++#else + .mclk = 72 * MHZ, + .m1xclk = 144 * MHZ, ++#endif + }; + + static struct sm501_platdata_fbsub sm501_pdata_fbsub = { +diff --git a/drivers/net/titan_ge.c b/drivers/net/titan_ge.c +new file mode 100644 +index 0000000..dc137bf8 +--- /dev/null ++++ b/drivers/net/titan_ge.c +@@ -0,0 +1,2069 @@ ++/* ++ * drivers/net/titan_ge.c - Driver for Titan ethernet ports ++ * ++ * Copyright (C) 2003 PMC-Sierra Inc. ++ * Author : Manish Lachwani (lachwani@pmc-sierra.com) ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * The MAC unit of the Titan consists of the following: ++ * ++ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO ++ * -> FIFO is where the incoming and outgoing data is placed ++ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes ++ * the data into the FIFO for Rx ++ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. ++ * -> AFX is the address filtering block ++ * -> GMII block to communicate with the PHY ++ * ++ * Rx will look like the following: ++ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory ++ * ++ * Tx will look like the following: ++ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII ++ * ++ * The Titan driver has support for the following performance features: ++ * -> Rx side checksumming ++ * -> Jumbo Frames ++ * -> Interrupt Coalscing ++ * -> Rx NAPI ++ * -> SKB Recycling ++ * -> Transmit/Receive descriptors in SRAM ++ * -> Fast routing for IP forwarding ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* For MII specifc registers, titan_mdio.h should be included */ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "titan_ge.h" ++#include "titan_mdio.h" ++ ++/* Static Function Declarations */ ++static int titan_ge_eth_open(struct net_device *); ++static void titan_ge_eth_stop(struct net_device *); ++static struct net_device_stats *titan_ge_get_stats(struct net_device *); ++static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int, ++ unsigned long, unsigned long, ++ unsigned long); ++static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int, ++ unsigned long, unsigned long); ++ ++static int titan_ge_open(struct net_device *); ++static int titan_ge_start_xmit(struct sk_buff *, struct net_device *); ++static int titan_ge_stop(struct net_device *); ++ ++static unsigned long titan_ge_tx_coal(unsigned long, int); ++ ++static void titan_ge_port_reset(unsigned int); ++static int titan_ge_free_tx_queue(titan_ge_port_info *); ++static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *); ++static int titan_ge_port_start(struct net_device *, titan_ge_port_info *); ++ ++static int titan_ge_return_tx_desc(titan_ge_port_info *, int); ++ ++/* ++ * Some configuration for the FIFO and the XDMA channel needs ++ * to be done only once for all the ports. This flag controls ++ * that ++ */ ++static unsigned long config_done; ++ ++/* ++ * One time out of memory flag ++ */ ++static unsigned int oom_flag; ++ ++static int titan_ge_poll(struct net_device *netdev, int *budget); ++ ++static int titan_ge_receive_queue(struct net_device *, unsigned int); ++ ++static struct platform_device *titan_ge_device[3]; ++ ++/* MAC Address */ ++extern unsigned char titan_ge_mac_addr_base[6]; ++ ++unsigned long titan_ge_base; ++static unsigned long titan_ge_sram; ++ ++static char titan_string[] = "titan"; ++ ++/* ++ * The Titan GE has two alignment requirements: ++ * -> skb->data to be cacheline aligned (32 byte) ++ * -> IP header alignment to 16 bytes ++ * ++ * The latter is not implemented. So, that results in an extra copy on ++ * the Rx. This is a big performance hog. For the former case, the ++ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size ++ * requested is calculated: ++ * ++ * Ethernet Frame Size : 1518 ++ * Ethernet Header : 14 ++ * Future Titan change for IP header alignment : 2 ++ * ++ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header ++ * alignment, we use skb_reserve(). ++ */ ++ ++#define ALIGNED_RX_SKB_ADDR(addr) \ ++ ((((unsigned long)(addr) + (64UL - 1UL)) \ ++ & ~(64UL - 1UL)) - (unsigned long)(addr)) ++ ++#define titan_ge_alloc_skb(__length, __gfp_flags) \ ++({ struct sk_buff *__skb; \ ++ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \ ++ if(__skb) { \ ++ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \ ++ if(__offset) \ ++ skb_reserve(__skb, __offset); \ ++ } \ ++ __skb; \ ++}) ++ ++/* ++ * Configure the GMII block of the Titan based on what the PHY tells us ++ */ ++static void titan_ge_gmii_config(int port_num) ++{ ++ unsigned int reg_data = 0, phy_reg; ++ int err; ++ ++ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); ++ ++ if (err == TITAN_GE_MDIO_ERROR) { ++ printk(KERN_ERR ++ "Could not read PHY control register 0x11 \n"); ++ printk(KERN_ERR ++ "Setting speed to 1000 Mbps and Duplex to Full \n"); ++ ++ return; ++ } ++ ++ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0); ++ ++ if (phy_reg & 0x8000) { ++ if (phy_reg & 0x2000) { ++ /* Full Duplex and 1000 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x201); ++ } else { ++ /* Half Duplex and 1000 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x2201); ++ } ++ } ++ if (phy_reg & 0x4000) { ++ if (phy_reg & 0x2000) { ++ /* Full Duplex and 100 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x100); ++ } else { ++ /* Half Duplex and 100 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x2100); ++ } ++ } ++ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL + ++ (port_num << 12)); ++ reg_data |= 0x3; ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL + ++ (port_num << 12)), reg_data); ++} ++ ++/* ++ * Enable the TMAC if it is not ++ */ ++static void titan_ge_enable_tx(unsigned int port_num) ++{ ++ unsigned long reg_data; ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); ++ if (!(reg_data & 0x8000)) { ++ printk("TMAC disabled for port %d!! \n", port_num); ++ ++ reg_data |= 0x0001; /* Enable TMAC */ ++ reg_data |= 0x4000; /* CRC Check Enable */ ++ reg_data |= 0x2000; /* Padding enable */ ++ reg_data |= 0x0800; /* CRC Add enable */ ++ reg_data |= 0x0080; /* PAUSE frame */ ++ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ } ++} ++ ++/* ++ * Tx Timeout function ++ */ ++static void titan_ge_tx_timeout(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ printk(KERN_INFO "%s: TX timeout ", netdev->name); ++ printk(KERN_INFO "Resetting card \n"); ++ ++ /* Do the reset outside of interrupt context */ ++ schedule_work(&titan_ge_eth->tx_timeout_task); ++} ++ ++/* ++ * Update the AFX tables for UC and MC for slice 0 only ++ */ ++static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth) ++{ ++ int port = titan_ge_eth->port_num; ++ unsigned int i; ++ volatile unsigned long reg_data = 0; ++ u8 p_addr[6]; ++ ++ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6); ++ ++ /* Set the MAC address here for TMAC and RMAC */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1); ++ /* Configure the eight address filters */ ++ for (i = 0; i < 8; i++) { ++ /* Select each of the eight filters */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 + ++ (port << 12)), i); ++ ++ /* Configure the match */ ++ reg_data = 0x9; /* Forward Enable Bit */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 + ++ (port << 12)), reg_data); ++ ++ /* Finally, AFX Exact Match Address Registers */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ ++ /* VLAN id set to 0 */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + ++ (port << 12)), 0); ++ } ++} ++ ++/* ++ * Actual Routine to reset the adapter when the timeout occurred ++ */ ++static void titan_ge_tx_timeout_task(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ int port = titan_ge_eth->port_num; ++ ++ printk("Titan GE: Transmit timed out. Resetting ... \n"); ++ ++ /* Dump debug info */ ++ printk(KERN_ERR "TRTG cause : %x \n", ++ TITAN_GE_READ(0x100c + (port << 12))); ++ ++ /* Fix this for the other ports */ ++ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c)); ++ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040)); ++ printk(KERN_ERR "XDMA GDI ERROR : %x \n", ++ TITAN_GE_READ(0x5008 + (port << 8))); ++ printk(KERN_ERR "CHANNEL ERROR: %x \n", ++ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT ++ + (port << 8))); ++ ++ netif_device_detach(netdev); ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ titan_ge_port_start(netdev, titan_ge_eth); ++ netif_device_attach(netdev); ++} ++ ++/* ++ * Change the MTU of the Ethernet Device ++ */ ++static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned long flags; ++ ++ if ((new_mtu > 9500) || (new_mtu < 64)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ netdev->mtu = new_mtu; ++ ++ /* Now we have to reopen the interface so that SKBs with the new ++ * size will be allocated */ ++ ++ if (netif_running(netdev)) { ++ titan_ge_eth_stop(netdev); ++ ++ if (titan_ge_eth_open(netdev) != TITAN_OK) { ++ printk(KERN_ERR ++ "%s: Fatal error on opening device\n", ++ netdev->name); ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ return -1; ++ } ++ } ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ return 0; ++} ++ ++/* ++ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line ++ * only. Once an interrupt is triggered, figure out the port and then check ++ * the channel. ++ */ ++static irqreturn_t titan_ge_int_handler(int irq, void *dev_id) ++{ ++ struct net_device *netdev = (struct net_device *) dev_id; ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int reg_data; ++ unsigned int eth_int_cause_error = 0, is; ++ unsigned long eth_int_cause1; ++ int err = 0; ++#ifdef CONFIG_SMP ++ unsigned long eth_int_cause2; ++#endif ++ ++ /* Ack the CPU interrupt */ ++ switch (port_num) { ++ case 0: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is); ++#endif ++ break; ++ ++ case 1: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is); ++#endif ++ break; ++ ++ case 2: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is); ++#endif ++ } ++ ++ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); ++#ifdef CONFIG_SMP ++ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B); ++#endif ++ ++ /* Spurious interrupt */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) { ++#else ++ if (eth_int_cause1 == 0) { ++#endif ++ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT + ++ (port_num << 8)); ++ ++ if (eth_int_cause_error == 0) ++ return IRQ_NONE; ++ } ++ ++ /* Handle Tx first. No need to ack interrupts */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 & 0x20202) || ++ (eth_int_cause2 & 0x20202) ) ++#else ++ if (eth_int_cause1 & 0x20202) ++#endif ++ titan_ge_free_tx_queue(titan_ge_eth); ++ ++ /* Handle the Rx next */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 & 0x10101) || ++ (eth_int_cause2 & 0x10101)) { ++#else ++ if (eth_int_cause1 & 0x10101) { ++#endif ++ if (netif_rx_schedule_prep(netdev)) { ++ unsigned int ack; ++ ++ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ /* Disable Tx and Rx both */ ++ if (port_num == 0) ++ ack &= ~(0x3); ++ if (port_num == 1) ++ ack &= ~(0x300); ++ ++ if (port_num == 2) ++ ack &= ~(0x30000); ++ ++ /* Interrupts have been disabled */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack); ++ ++ __netif_rx_schedule(netdev); ++ } ++ } ++ ++ /* Handle error interrupts */ ++ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) { ++ printk(KERN_ERR ++ "XDMA Channel Error : %x on port %d\n", ++ eth_int_cause_error, port_num); ++ ++ printk(KERN_ERR ++ "XDMA GDI Hardware error : %x on port %d\n", ++ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num); ++ ++ printk(KERN_ERR ++ "XDMA currently has %d Rx descriptors \n", ++ TITAN_GE_READ(0x5048 + (port_num << 8))); ++ ++ printk(KERN_ERR ++ "XDMA currently has prefetcted %d Rx descriptors \n", ++ TITAN_GE_READ(0x505c + (port_num << 8))); ++ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + ++ (port_num << 8)), eth_int_cause_error); ++ } ++ ++ /* ++ * PHY interrupt to inform abt the changes. Reading the ++ * PHY Status register will clear the interrupt ++ */ ++ if ((!(eth_int_cause1 & 0x30303)) && ++ (eth_int_cause_error == 0)) { ++ err = ++ titan_ge_mdio_read(port_num, ++ TITAN_GE_MDIO_PHY_IS, ®_data); ++ ++ if (reg_data & 0x0400) { ++ /* Link status change */ ++ titan_ge_mdio_read(port_num, ++ TITAN_GE_MDIO_PHY_STATUS, ®_data); ++ if (!(reg_data & 0x0400)) { ++ /* Link is down */ ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ } else { ++ /* Link is up */ ++ netif_carrier_on(netdev); ++ netif_wake_queue(netdev); ++ ++ /* Enable the queue */ ++ titan_ge_enable_tx(port_num); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Multicast and Promiscuous mode set. The ++ * set_multi entry point is called whenever the ++ * multicast address list or the network interface ++ * flags are updated. ++ */ ++static void titan_ge_set_multi(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned long reg_data; ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + ++ (port_num << 12)); ++ ++ if (netdev->flags & IFF_PROMISC) { ++ reg_data |= 0x2; ++ } ++ else if (netdev->flags & IFF_ALLMULTI) { ++ reg_data |= 0x01; ++ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */ ++ } ++ else { ++ reg_data = 0x2; ++ } ++ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + ++ (port_num << 12)), reg_data); ++ if (reg_data & 0x01) { ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI + ++ (port_num << 12)), 0xffff); ++ } ++} ++ ++/* ++ * Open the network device ++ */ ++static int titan_ge_open(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num; ++ int retval; ++ ++ retval = request_irq(irq, titan_ge_int_handler, ++ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev); ++ ++ if (retval != 0) { ++ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n"); ++ return -1; ++ } ++ ++ netdev->irq = irq; ++ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num); ++ ++ spin_lock_irq(&(titan_ge_eth->lock)); ++ ++ if (titan_ge_eth_open(netdev) != TITAN_OK) { ++ spin_unlock_irq(&(titan_ge_eth->lock)); ++ printk("%s: Error opening interface \n", netdev->name); ++ free_irq(netdev->irq, netdev); ++ return -EBUSY; ++ } ++ ++ spin_unlock_irq(&(titan_ge_eth->lock)); ++ ++ return 0; ++} ++ ++/* ++ * Allocate the SKBs for the Rx ring. Also used ++ * for refilling the queue ++ */ ++static int titan_ge_rx_task(struct net_device *netdev, ++ titan_ge_port_info *titan_ge_port) ++{ ++ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev; ++ volatile titan_ge_rx_desc *rx_desc; ++ struct sk_buff *skb; ++ int rx_used_desc; ++ int count = 0; ++ ++ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) { ++ ++ /* First try to get the skb from the recycler */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC); ++#else ++ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC); ++#endif ++ if (unlikely(!skb)) { ++ /* OOM, set the flag */ ++ printk("OOM \n"); ++ oom_flag = 1; ++ break; ++ } ++ count++; ++ skb->dev = netdev; ++ ++ titan_ge_port->rx_ring_skbs++; ++ ++ rx_used_desc = titan_ge_port->rx_used_desc_q; ++ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]); ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ rx_desc->buffer_addr = dma_map_single(device, skb->data, ++ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE); ++#else ++ rx_desc->buffer_addr = dma_map_single(device, skb->data, ++ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE); ++#endif ++ ++ titan_ge_port->rx_skb[rx_used_desc] = skb; ++ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED; ++ ++ titan_ge_port->rx_used_desc_q = ++ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE; ++ } ++ ++ return count; ++} ++ ++/* ++ * Actual init of the Tital GE port. There is one register for ++ * the channel configuration ++ */ ++static void titan_port_init(struct net_device *netdev, ++ titan_ge_port_info * titan_ge_eth) ++{ ++ unsigned long reg_data; ++ ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ ++ /* First reset the TMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data |= 0x80000000; ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ udelay(30); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data &= ~(0xc0000000); ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ /* Now reset the RMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data |= 0x00080000; ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ udelay(30); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data &= ~(0x000c0000); ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++} ++ ++/* ++ * Start the port. All the hardware specific configuration ++ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX ++ * go here ++ */ ++static int titan_ge_port_start(struct net_device *netdev, ++ titan_ge_port_info * titan_port) ++{ ++ volatile unsigned long reg_data, reg_data1; ++ int port_num = titan_port->port_num; ++ int count = 0; ++ unsigned long reg_data_1; ++ ++ if (config_done == 0) { ++ reg_data = TITAN_GE_READ(0x0004); ++ reg_data |= 0x100; ++ TITAN_GE_WRITE(0x0004, reg_data); ++ ++ reg_data &= ~(0x100); ++ TITAN_GE_WRITE(0x0004, reg_data); ++ ++ /* Turn on GMII/MII mode and turn off TBI mode */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1); ++ reg_data |= 0x00000700; ++ reg_data &= ~(0x00800000); /* Fencing */ ++ ++ TITAN_GE_WRITE(0x000c, 0x00001100); ++ ++ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data); ++ ++ /* Set the CPU Resource Limit register */ ++ TITAN_GE_WRITE(0x00f8, 0x8); ++ ++ /* Be conservative when using the BIU buffers */ ++ TITAN_GE_WRITE(0x0068, 0x4); ++ } ++ ++ titan_port->tx_threshold = 0; ++ titan_port->rx_threshold = 0; ++ ++ /* We need to write the descriptors for Tx and Rx */ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)), ++ (unsigned long) titan_port->tx_dma); ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)), ++ (unsigned long) titan_port->rx_dma); ++ ++ if (config_done == 0) { ++ /* Step 1: XDMA config */ ++ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG); ++ reg_data &= ~(0x80000000); /* clear reset */ ++ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */ ++ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */ ++ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */ ++ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */ ++ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data); ++ } ++ ++ /* IR register for the XDMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)); ++ reg_data |= 0x80068000; /* No Rx_OOD */ ++ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data); ++ ++ /* Start the Tx and Rx XDMA controller */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)); ++ reg_data &= 0x4fffffff; /* Clear tx reset */ ++ reg_data &= 0xfff4ffff; /* Clear rx reset */ ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ reg_data |= 0xa0 | 0x30030000; ++#else ++ reg_data |= 0x40 | 0x20030000; ++#endif ++ ++#ifndef CONFIG_SMP ++ reg_data &= ~(0x10); ++ reg_data |= 0x0f; /* All of the packet */ ++#endif ++ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data); ++ ++ /* Rx desc count */ ++ count = titan_ge_rx_task(netdev, titan_port); ++ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count); ++ count = TITAN_GE_READ(0x5048 + (port_num << 8)); ++ ++ udelay(30); ++ ++ /* ++ * Step 2: Configure the SDQPF, i.e. FIFO ++ */ ++ if (config_done == 0) { ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); ++ reg_data = 0x1; ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ reg_data &= ~(0x1); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); ++ reg_data = 0x1; ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ reg_data &= ~(0x1); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ } ++ /* ++ * Enable RX FIFO 0, 4 and 8 ++ */ ++ if (port_num == 0) { ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10); ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4844); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x4844, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ reg_data |= (0xff << 10); ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4944); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x4944, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ } ++ ++ if (port_num == 1) { ++ reg_data = TITAN_GE_READ(0x4870); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (0xff + 1); ++ ++ TITAN_GE_WRITE(0x4870, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4874); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x4874, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4870, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x494c); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x494c, reg_data); ++ reg_data |= (0xff << 10) | (0xff + 1); ++ TITAN_GE_WRITE(0x494c, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4950); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x4950, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x494c, reg_data); ++ } ++ ++ /* ++ * Titan 1.2 revision does support port #2 ++ */ ++ if (port_num == 2) { ++ /* ++ * Put the descriptors in the SRAM ++ */ ++ reg_data = TITAN_GE_READ(0x48a0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x48a4); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x48a4, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x4958); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ TITAN_GE_WRITE(0x4958, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x495c); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x495c, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ } ++ ++ if (port_num == 2) { ++ reg_data = TITAN_GE_READ(0x48a0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x48a4); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x48a4, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x4958); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ TITAN_GE_WRITE(0x4958, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x495c); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x495c, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ } ++ ++ /* ++ * Step 3: TRTG block enable ++ */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12)); ++ ++ /* ++ * This is the 1.2 revision of the chip. It has fix for the ++ * IP header alignment. Now, the IP header begins at an ++ * aligned address and this wont need an extra copy in the ++ * driver. This performance drawback existed in the previous ++ * versions of the silicon ++ */ ++ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12)); ++ reg_data_1 |= 0x40000000; ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ reg_data_1 |= 0x04000000; ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ mdelay(5); ++ ++ reg_data_1 &= ~(0x04000000); ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ mdelay(5); ++ ++ reg_data |= 0x0001; ++ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data); ++ ++ /* ++ * Step 4: Start the Tx activity ++ */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197); ++#ifdef TITAN_GE_JUMBO_FRAMES ++ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000); ++#endif ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); ++ reg_data |= 0x0001; /* Enable TMAC */ ++ reg_data |= 0x6c70; /* PAUSE also set */ ++ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ udelay(30); ++ ++ /* Destination Address drop bit */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)); ++ reg_data |= 0x218; /* DA_DROP bit and pause */ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data); ++ ++ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3); ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000); ++#endif ++ /* Start the Rx activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); ++ reg_data |= 0x0001; /* RMAC Enable */ ++ reg_data |= 0x0010; /* CRC Check enable */ ++ reg_data |= 0x0040; /* Min Frame check enable */ ++ reg_data |= 0x4400; /* Max Frame check enable */ ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ udelay(30); ++ ++ /* ++ * Enable the Interrupts for Tx and Rx ++ */ ++ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ ++ if (port_num == 0) { ++ reg_data1 |= 0x3; ++#ifdef CONFIG_SMP ++ TITAN_GE_WRITE(0x0038, 0x003); ++#else ++ TITAN_GE_WRITE(0x0038, 0x303); ++#endif ++ } ++ ++ if (port_num == 1) { ++ reg_data1 |= 0x300; ++ } ++ ++ if (port_num == 2) ++ reg_data1 |= 0x30000; ++ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1); ++ TITAN_GE_WRITE(0x003c, 0x300); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */ ++ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */ ++ } ++ ++ /* Priority */ ++ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12)); ++ reg_data &= ~(0x00f00000); ++ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data); ++ ++ /* Step 5: GMII config */ ++ titan_ge_gmii_config(port_num); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(0x1a80, 0); ++ config_done = 1; ++ } ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Function to queue the packet for the Ethernet device ++ */ ++static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth, ++ struct sk_buff * skb) ++{ ++ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev; ++ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q; ++ volatile titan_ge_tx_desc *tx_curr; ++ int port_num = titan_ge_eth->port_num; ++ ++ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]); ++ tx_curr->buffer_addr = ++ dma_map_single(device, skb->data, skb_headlen(skb), ++ DMA_TO_DEVICE); ++ ++ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb; ++ tx_curr->buffer_len = skb_headlen(skb); ++ ++ /* Last descriptor enables interrupt and changes ownership */ ++ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5); ++ ++ /* Kick the XDMA to start the transfer from memory to the FIFO */ ++ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1); ++ ++ /* Current descriptor updated */ ++ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE; ++ ++ /* Prefetch the next descriptor */ ++ prefetch((const void *) ++ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]); ++} ++ ++/* ++ * Actually does the open of the Ethernet device ++ */ ++static int titan_ge_eth_open(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ struct device *device = &titan_ge_device[port_num]->dev; ++ unsigned long reg_data; ++ unsigned int phy_reg; ++ int err = 0; ++ ++ /* Stop the Rx activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ /* Clear the port interrupts */ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0); ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0); ++ } ++ ++ /* Set the MAC Address */ ++ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); ++ ++ if (config_done == 0) ++ titan_port_init(netdev, titan_ge_eth); ++ ++ titan_ge_update_afx(titan_ge_eth); ++ ++ /* Allocate the Tx ring now */ ++ titan_ge_eth->tx_ring_skbs = 0; ++ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE; ++ ++ /* Allocate space in the SRAM for the descriptors */ ++ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *) ++ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num); ++ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num; ++ ++ if (!titan_ge_eth->tx_desc_area) { ++ printk(KERN_ERR ++ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n", ++ netdev->name, TITAN_TX_RING_BYTES, port_num); ++ return -ENOMEM; ++ } ++ ++ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size); ++ ++ /* Now initialize the Tx descriptor ring */ ++ titan_ge_init_tx_desc_ring(titan_ge_eth, ++ titan_ge_eth->tx_ring_size, ++ (unsigned long) titan_ge_eth->tx_desc_area, ++ (unsigned long) titan_ge_eth->tx_dma); ++ ++ /* Allocate the Rx ring now */ ++ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE; ++ titan_ge_eth->rx_ring_skbs = 0; ++ ++ titan_ge_eth->rx_desc_area = ++ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num); ++ ++ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num; ++ ++ if (!titan_ge_eth->rx_desc_area) { ++ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", ++ netdev->name, TITAN_RX_RING_BYTES); ++ ++ printk(KERN_ERR "%s: Freeing previously allocated TX queues...", ++ netdev->name); ++ ++ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size, ++ (void *) titan_ge_eth->tx_desc_area, ++ titan_ge_eth->tx_dma); ++ ++ return -ENOMEM; ++ } ++ ++ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size); ++ ++ /* Now initialize the Rx ring */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ if ((titan_ge_init_rx_desc_ring ++ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE, ++ (unsigned long) titan_ge_eth->rx_desc_area, 0, ++ (unsigned long) titan_ge_eth->rx_dma)) == 0) ++#else ++ if ((titan_ge_init_rx_desc_ring ++ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE, ++ (unsigned long) titan_ge_eth->rx_desc_area, 0, ++ (unsigned long) titan_ge_eth->rx_dma)) == 0) ++#endif ++ panic("%s: Error initializing RX Ring\n", netdev->name); ++ ++ /* Fill the Rx ring with the SKBs */ ++ titan_ge_port_start(netdev, titan_ge_eth); ++ ++ /* ++ * Check if Interrupt Coalscing needs to be turned on. The ++ * values specified in the register is multiplied by ++ * (8 x 64 nanoseconds) to determine when an interrupt should ++ * be sent to the CPU. ++ */ ++ ++ if (TITAN_GE_TX_COAL) { ++ titan_ge_eth->tx_int_coal = ++ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num); ++ } ++ ++ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); ++ if (err == TITAN_GE_MDIO_ERROR) { ++ printk(KERN_ERR ++ "Could not read PHY control register 0x11 \n"); ++ return TITAN_ERROR; ++ } ++ if (!(phy_reg & 0x0400)) { ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ return TITAN_ERROR; ++ } else { ++ netif_carrier_on(netdev); ++ netif_start_queue(netdev); ++ } ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Queue the packet for Tx. Currently no support for zero copy, ++ * checksum offload and Scatter Gather. The chip does support ++ * Scatter Gather only. But, that wont help here since zero copy ++ * requires support for Tx checksumming also. ++ */ ++int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned long flags; ++ struct net_device_stats *stats; ++//printk("titan_ge_start_xmit\n"); ++ ++ stats = &titan_ge_eth->stats; ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <= ++ (skb_shinfo(skb)->nr_frags + 1)) { ++ netif_stop_queue(netdev); ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ printk(KERN_ERR "Tx OOD \n"); ++ return 1; ++ } ++ ++ titan_ge_tx_queue(titan_ge_eth, skb); ++ titan_ge_eth->tx_ring_skbs++; ++ ++ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) { ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ titan_ge_free_tx_queue(titan_ge_eth); ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ } ++ ++ stats->tx_bytes += skb->len; ++ stats->tx_packets++; ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ netdev->trans_start = jiffies; ++ ++ return 0; ++} ++ ++/* ++ * Actually does the Rx. Rx side checksumming supported. ++ */ ++static int titan_ge_rx(struct net_device *netdev, int port_num, ++ titan_ge_port_info * titan_ge_port, ++ titan_ge_packet * packet) ++{ ++ int rx_curr_desc, rx_used_desc; ++ volatile titan_ge_rx_desc *rx_desc; ++ ++ rx_curr_desc = titan_ge_port->rx_curr_desc_q; ++ rx_used_desc = titan_ge_port->rx_used_desc_q; ++ ++ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) ++ return TITAN_ERROR; ++ ++ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]); ++ ++ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) ++ return TITAN_ERROR; ++ ++ packet->skb = titan_ge_port->rx_skb[rx_curr_desc]; ++ packet->len = (rx_desc->cmd_sts & 0x7fff); ++ ++ /* ++ * At this point, we dont know if the checksumming ++ * actually helps relieve CPU. So, keep it for ++ * port 0 only ++ */ ++ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16); ++ packet->cmd_sts = rx_desc->cmd_sts; ++ ++ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE; ++ ++ /* Prefetch the next descriptor */ ++ prefetch((const void *) ++ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Free the Tx queue of the used SKBs ++ */ ++static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth) ++{ ++ unsigned long flags; ++ ++ /* Take the lock */ ++ spin_lock_irqsave(&(titan_ge_eth->lock), flags); ++ ++ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) ++ if (titan_ge_eth->tx_ring_skbs != 1) ++ titan_ge_eth->tx_ring_skbs--; ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Threshold beyond which we do the cleaning of ++ * Tx queue and new allocation for the Rx ++ * queue ++ */ ++#define TX_THRESHOLD 4 ++#define RX_THRESHOLD 10 ++ ++/* ++ * Receive the packets and send it to the kernel. ++ */ ++static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ titan_ge_packet packet; ++ struct net_device_stats *stats; ++ struct sk_buff *skb; ++ unsigned long received_packets = 0; ++ unsigned int ack; ++ ++ stats = &titan_ge_eth->stats; ++ ++ while ((--max) ++ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) { ++ skb = (struct sk_buff *) packet.skb; ++ ++ titan_ge_eth->rx_ring_skbs--; ++ ++ if (--titan_ge_eth->rx_work_limit < 0) ++ break; ++ received_packets++; ++ ++ stats->rx_packets++; ++ stats->rx_bytes += packet.len; ++ ++ if ((packet.cmd_sts & TITAN_GE_RX_PERR) || ++ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) || ++ (packet.cmd_sts & TITAN_GE_RX_TRUNC) || ++ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) { ++ stats->rx_dropped++; ++ dev_kfree_skb_any(skb); ++ ++ continue; ++ } ++ /* ++ * Either support fast path or slow path. Decision ++ * making can really slow down the performance. The ++ * idea is to cut down the number of checks and improve ++ * the fastpath. ++ */ ++ ++ skb_put(skb, packet.len - 2); ++ ++ /* ++ * Increment data pointer by two since thats where ++ * the MAC starts ++ */ ++ skb_reserve(skb, 2); ++ skb->protocol = eth_type_trans(skb, netdev); ++ netif_receive_skb(skb); ++ ++ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) { ++ ack = titan_ge_rx_task(netdev, titan_ge_eth); ++ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack); ++ titan_ge_eth->rx_threshold = 0; ++ } else ++ titan_ge_eth->rx_threshold++; ++ ++ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) { ++ titan_ge_eth->tx_threshold = 0; ++ titan_ge_free_tx_queue(titan_ge_eth); ++ } ++ else ++ titan_ge_eth->tx_threshold++; ++ ++ } ++ return received_packets; ++} ++ ++ ++/* ++ * Enable the Rx side interrupts ++ */ ++static void titan_ge_enable_int(unsigned int port_num, ++ titan_ge_port_info *titan_ge_eth, ++ struct net_device *netdev) ++{ ++ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ ++ if (port_num == 0) ++ reg_data |= 0x3; ++ if (port_num == 1) ++ reg_data |= 0x300; ++ if (port_num == 2) ++ reg_data |= 0x30000; ++ ++ /* Re-enable interrupts */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data); ++} ++ ++/* ++ * Main function to handle the polling for Rx side NAPI. ++ * Receive interrupts have been disabled at this point. ++ * The poll schedules the transmit followed by receive. ++ */ ++static int titan_ge_poll(struct net_device *netdev, int *budget) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ int port_num = titan_ge_eth->port_num; ++ int work_done = 0; ++ unsigned long flags, status; ++ ++ titan_ge_eth->rx_work_limit = *budget; ++ if (titan_ge_eth->rx_work_limit > netdev->quota) ++ titan_ge_eth->rx_work_limit = netdev->quota; ++ ++ do { ++ /* Do the transmit cleaning work here */ ++ titan_ge_free_tx_queue(titan_ge_eth); ++ ++ /* Ack the Rx interrupts */ ++ if (port_num == 0) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3); ++ if (port_num == 1) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300); ++ if (port_num == 2) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000); ++ ++ work_done += titan_ge_receive_queue(netdev, 0); ++ ++ /* Out of quota and there is work to be done */ ++ if (titan_ge_eth->rx_work_limit < 0) ++ goto not_done; ++ ++ /* Receive alloc_skb could lead to OOM */ ++ if (oom_flag == 1) { ++ oom_flag = 0; ++ goto oom; ++ } ++ ++ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); ++ } while (status & 0x30300); ++ ++ /* If we are here, then no more interrupts to process */ ++ goto done; ++ ++not_done: ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ return 1; ++ ++oom: ++ printk(KERN_ERR "OOM \n"); ++ netif_rx_complete(netdev); ++ return 0; ++ ++done: ++ /* ++ * No more packets on the poll list. Turn the interrupts ++ * back on and we should be able to catch the new ++ * packets in the interrupt handler ++ */ ++ if (!work_done) ++ work_done = 1; ++ ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ /* Remove us from the poll list */ ++ netif_rx_complete(netdev); ++ ++ /* Re-enable interrupts */ ++ titan_ge_enable_int(port_num, titan_ge_eth, netdev); ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * Close the network device ++ */ ++int titan_ge_stop(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ spin_lock_irq(&(titan_ge_eth->lock)); ++ titan_ge_eth_stop(netdev); ++ free_irq(netdev->irq, netdev); ++ spin_unlock_irq(&titan_ge_eth->lock); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Free the Tx ring ++ */ ++static void titan_ge_free_tx_rings(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int curr; ++ unsigned long reg_data; ++ ++ /* Stop the Tx DMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)); ++ reg_data |= 0xc0000000; ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)), reg_data); ++ ++ /* Disable the TMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ for (curr = 0; ++ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE); ++ curr++) { ++ if (titan_ge_eth->tx_skb[curr]) { ++ dev_kfree_skb(titan_ge_eth->tx_skb[curr]); ++ titan_ge_eth->tx_ring_skbs--; ++ } ++ } ++ ++ if (titan_ge_eth->tx_ring_skbs != 0) ++ printk ++ ("%s: Error on Tx descriptor free - could not free %d" ++ " descriptors\n", netdev->name, ++ titan_ge_eth->tx_ring_skbs); ++ ++#ifndef TITAN_RX_RING_IN_SRAM ++ dma_free_coherent(&titan_ge_device[port_num]->dev, ++ titan_ge_eth->tx_desc_area_size, ++ (void *) titan_ge_eth->tx_desc_area, ++ titan_ge_eth->tx_dma); ++#endif ++} ++ ++/* ++ * Free the Rx ring ++ */ ++static void titan_ge_free_rx_rings(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int curr; ++ unsigned long reg_data; ++ ++ /* Stop the Rx DMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)); ++ reg_data |= 0x000c0000; ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)), reg_data); ++ ++ /* Disable the RMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ for (curr = 0; ++ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE); ++ curr++) { ++ if (titan_ge_eth->rx_skb[curr]) { ++ dev_kfree_skb(titan_ge_eth->rx_skb[curr]); ++ titan_ge_eth->rx_ring_skbs--; ++ } ++ } ++ ++ if (titan_ge_eth->rx_ring_skbs != 0) ++ printk(KERN_ERR ++ "%s: Error in freeing Rx Ring. %d skb's still" ++ " stuck in RX Ring - ignoring them\n", netdev->name, ++ titan_ge_eth->rx_ring_skbs); ++ ++#ifndef TITAN_RX_RING_IN_SRAM ++ dma_free_coherent(&titan_ge_device[port_num]->dev, ++ titan_ge_eth->rx_desc_area_size, ++ (void *) titan_ge_eth->rx_desc_area, ++ titan_ge_eth->rx_dma); ++#endif ++} ++ ++/* ++ * Actually does the stop of the Ethernet device ++ */ ++static void titan_ge_eth_stop(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ netif_stop_queue(netdev); ++ ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ ++ titan_ge_free_tx_rings(netdev); ++ titan_ge_free_rx_rings(netdev); ++ ++ /* Disable the Tx and Rx Interrupts for all channels */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0); ++} ++ ++/* ++ * Update the MAC address. Note that we have to write the ++ * address in three station registers, 16 bits each. And this ++ * has to be done for TMAC and RMAC ++ */ ++static void titan_ge_update_mac_address(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ u8 p_addr[6]; ++ ++ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); ++ memcpy(p_addr, netdev->dev_addr, 6); ++ ++ /* Update the Address Filtering Match tables */ ++ titan_ge_update_afx(titan_ge_eth); ++ ++ printk("Station MAC : %d %d %d %d %d %d \n", ++ p_addr[5], p_addr[4], p_addr[3], ++ p_addr[2], p_addr[1], p_addr[0]); ++ ++ /* Set the MAC address here for TMAC and RMAC */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++} ++ ++/* ++ * Set the MAC address of the Ethernet device ++ */ ++static int titan_ge_set_mac_address(struct net_device *dev, void *addr) ++{ ++ titan_ge_port_info *tp = netdev_priv(dev); ++ struct sockaddr *sa = addr; ++ ++ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); ++ ++ spin_lock_irq(&tp->lock); ++ titan_ge_update_mac_address(dev); ++ spin_unlock_irq(&tp->lock); ++ ++ return 0; ++} ++ ++/* ++ * Get the Ethernet device stats ++ */ ++static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ return &titan_ge_eth->stats; ++} ++ ++/* ++ * Initialize the Rx descriptor ring for the Titan Ge ++ */ ++static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port, ++ int rx_desc_num, ++ int rx_buff_size, ++ unsigned long rx_desc_base_addr, ++ unsigned long rx_buff_base_addr, ++ unsigned long rx_dma) ++{ ++ volatile titan_ge_rx_desc *rx_desc; ++ unsigned long buffer_addr; ++ int index; ++ unsigned long titan_ge_rx_desc_bus = rx_dma; ++ ++ buffer_addr = rx_buff_base_addr; ++ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr; ++ ++ /* Check alignment */ ++ if (rx_buff_base_addr & 0xF) ++ return 0; ++ ++ /* Check Rx buffer size */ ++ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER)) ++ return 0; ++ ++ /* 64-bit alignment ++ if ((rx_buff_base_addr + rx_buff_size) & 0x7) ++ return 0; */ ++ ++ /* Initialize the Rx desc ring */ ++ for (index = 0; index < rx_desc_num; index++) { ++ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc); ++ rx_desc[index].cmd_sts = 0; ++ rx_desc[index].buffer_addr = buffer_addr; ++ titan_eth_port->rx_skb[index] = NULL; ++ buffer_addr += rx_buff_size; ++ } ++ ++ titan_eth_port->rx_curr_desc_q = 0; ++ titan_eth_port->rx_used_desc_q = 0; ++ ++ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr; ++ titan_eth_port->rx_desc_area_size = ++ rx_desc_num * sizeof(titan_ge_rx_desc); ++ ++ titan_eth_port->rx_dma = rx_dma; ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Initialize the Tx descriptor ring. Descriptors in the SRAM ++ */ ++static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port, ++ int tx_desc_num, ++ unsigned long tx_desc_base_addr, ++ unsigned long tx_dma) ++{ ++ titan_ge_tx_desc *tx_desc; ++ int index; ++ unsigned long titan_ge_tx_desc_bus = tx_dma; ++ ++ if (tx_desc_base_addr & 0xF) ++ return 0; ++ ++ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr; ++ ++ for (index = 0; index < tx_desc_num; index++) { ++ titan_ge_port->tx_dma_array[index] = ++ (dma_addr_t) titan_ge_tx_desc_bus; ++ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc); ++ tx_desc[index].cmd_sts = 0x0000; ++ tx_desc[index].buffer_len = 0; ++ tx_desc[index].buffer_addr = 0x00000000; ++ titan_ge_port->tx_skb[index] = NULL; ++ } ++ ++ titan_ge_port->tx_curr_desc_q = 0; ++ titan_ge_port->tx_used_desc_q = 0; ++ ++ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr; ++ titan_ge_port->tx_desc_area_size = ++ tx_desc_num * sizeof(titan_ge_tx_desc); ++ ++ titan_ge_port->tx_dma = tx_dma; ++ return TITAN_OK; ++} ++ ++/* ++ * Initialize the device as an Ethernet device ++ */ ++static int __init titan_ge_probe(struct device *device) ++{ ++ titan_ge_port_info *titan_ge_eth; ++ struct net_device *netdev; ++ int port = to_platform_device(device)->id; ++ int err; ++ ++ netdev = alloc_etherdev(sizeof(titan_ge_port_info)); ++ if (!netdev) { ++ err = -ENODEV; ++ goto out; ++ } ++ ++ netdev->open = titan_ge_open; ++ netdev->stop = titan_ge_stop; ++ netdev->hard_start_xmit = titan_ge_start_xmit; ++ netdev->get_stats = titan_ge_get_stats; ++ netdev->set_multicast_list = titan_ge_set_multi; ++ netdev->set_mac_address = titan_ge_set_mac_address; ++ ++ /* Tx timeout */ ++ netdev->tx_timeout = titan_ge_tx_timeout; ++ netdev->watchdog_timeo = 2 * HZ; ++ ++ /* Set these to very high values */ ++ netdev->poll = titan_ge_poll; ++ netdev->weight = 64; ++ ++ netdev->tx_queue_len = TITAN_GE_TX_QUEUE; ++ netif_carrier_off(netdev); ++ netdev->base_addr = 0; ++ ++ netdev->change_mtu = titan_ge_change_mtu; ++ ++ titan_ge_eth = netdev_priv(netdev); ++ /* Allocation of memory for the driver structures */ ++ ++ titan_ge_eth->port_num = port; ++ ++ /* Configure the Tx timeout handler */ ++ INIT_WORK(&titan_ge_eth->tx_timeout_task, ++ (void (*)(void *)) titan_ge_tx_timeout_task, netdev); ++ ++ spin_lock_init(&titan_ge_eth->lock); ++ ++ /* set MAC addresses */ ++ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6); ++ netdev->dev_addr[5] += port; ++ ++ err = register_netdev(netdev); ++ ++ if (err) ++ goto out_free_netdev; ++ ++ printk(KERN_NOTICE ++ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", ++ netdev->name, port, netdev->dev_addr[0], ++ netdev->dev_addr[1], netdev->dev_addr[2], ++ netdev->dev_addr[3], netdev->dev_addr[4], ++ netdev->dev_addr[5]); ++ ++ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n"); ++ ++ return 0; ++ ++out_free_netdev: ++ kfree(netdev); ++ ++out: ++ return err; ++} ++ ++static void __devexit titan_device_remove(struct device *device) ++{ ++} ++ ++/* ++ * Reset the Ethernet port ++ */ ++static void titan_ge_port_reset(unsigned int port_num) ++{ ++ unsigned int reg_data; ++ ++ /* Stop the Tx port activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x0001); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ /* Stop the Rx port activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x0001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ return; ++} ++ ++/* ++ * Return the Tx desc after use by the XDMA ++ */ ++static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port) ++{ ++ int tx_desc_used; ++ struct sk_buff *skb; ++ ++ tx_desc_used = titan_ge_eth->tx_used_desc_q; ++ ++ /* return right away */ ++ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q) ++ return TITAN_ERROR; ++ ++ /* Now the critical stuff */ ++ skb = titan_ge_eth->tx_skb[tx_desc_used]; ++ ++ dev_kfree_skb_any(skb); ++ ++ titan_ge_eth->tx_skb[tx_desc_used] = NULL; ++ titan_ge_eth->tx_used_desc_q = ++ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE; ++ ++ return 0; ++} ++ ++/* ++ * Coalescing for the Tx path ++ */ ++static unsigned long titan_ge_tx_coal(unsigned long delay, int port) ++{ ++ unsigned long rx_delay; ++ ++ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING); ++ delay = (delay << 16) | rx_delay; ++ ++ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay); ++ TITAN_GE_WRITE(0x5038, delay); ++ ++ return delay; ++} ++ ++static struct device_driver titan_soc_driver = { ++ .name = titan_string, ++ .bus = &platform_bus_type, ++ .probe = titan_ge_probe, ++ .remove = __devexit_p(titan_device_remove), ++}; ++ ++static void titan_platform_release (struct device *device) ++{ ++ struct platform_device *pldev; ++ ++ /* free device */ ++ pldev = to_platform_device (device); ++ kfree (pldev); ++} ++ ++/* ++ * Register the Titan GE with the kernel ++ */ ++static int __init titan_ge_init_module(void) ++{ ++ struct platform_device *pldev; ++ unsigned int version, device; ++ int i; ++ ++ printk(KERN_NOTICE ++ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n"); ++ ++ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE); ++ if (!titan_ge_base) { ++ printk("Mapping Titan GE failed\n"); ++ goto out; ++ } ++ ++ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID); ++ version = (device & 0x000f0000) >> 16; ++ device &= 0x0000ffff; ++ ++ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version); ++ ++#ifdef TITAN_RX_RING_IN_SRAM ++ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE, ++ TITAN_SRAM_SIZE); ++ if (!titan_ge_sram) { ++ printk("Mapping Titan SRAM failed\n"); ++ goto out_unmap_ge; ++ } ++#endif ++ ++ if (driver_register(&titan_soc_driver)) { ++ printk(KERN_ERR "Driver registration failed\n"); ++ goto out_unmap_sram; ++ } ++ ++ for (i = 0; i < 3; i++) { ++ titan_ge_device[i] = NULL; ++ ++ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) ++ continue; ++ ++ memset (pldev, 0, sizeof (*pldev)); ++ pldev->name = titan_string; ++ pldev->id = i; ++ pldev->dev.release = titan_platform_release; ++ titan_ge_device[i] = pldev; ++ ++ if (platform_device_register (pldev)) { ++ kfree (pldev); ++ titan_ge_device[i] = NULL; ++ continue; ++ } ++ ++ if (!pldev->dev.driver) { ++ /* ++ * The driver was not bound to this device, there was ++ * no hardware at this address. Unregister it, as the ++ * release fuction will take care of freeing the ++ * allocated structure ++ */ ++ titan_ge_device[i] = NULL; ++ platform_device_unregister (pldev); ++ } ++ } ++ ++ return 0; ++ ++out_unmap_sram: ++ iounmap((void *)titan_ge_sram); ++ ++out_unmap_ge: ++ iounmap((void *)titan_ge_base); ++ ++out: ++ return -ENOMEM; ++} ++ ++/* ++ * Unregister the Titan GE from the kernel ++ */ ++static void __exit titan_ge_cleanup_module(void) ++{ ++ int i; ++ ++ driver_unregister(&titan_soc_driver); ++ ++ for (i = 0; i < 3; i++) { ++ if (titan_ge_device[i]) { ++ platform_device_unregister (titan_ge_device[i]); ++ titan_ge_device[i] = NULL; ++ } ++ } ++ ++ iounmap((void *)titan_ge_sram); ++ iounmap((void *)titan_ge_base); ++} ++ ++MODULE_AUTHOR("Manish Lachwani "); ++MODULE_DESCRIPTION("Titan GE Ethernet driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(titan_ge_init_module); ++module_exit(titan_ge_cleanup_module); +diff --git a/drivers/net/titan_ge.h b/drivers/net/titan_ge.h +new file mode 100644 +index 0000000..3719f78 +--- /dev/null ++++ b/drivers/net/titan_ge.h +@@ -0,0 +1,415 @@ ++#ifndef _TITAN_GE_H_ ++#define _TITAN_GE_H_ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * These functions should be later moved to a more generic location since there ++ * will be others accessing it also ++ */ ++ ++/* ++ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in ++ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 ++ * register. ++ */ ++ ++#define TITAN_GE_BASE 0xfe000000UL ++#define TITAN_GE_SIZE 0x10000UL ++ ++extern unsigned long titan_ge_base; ++ ++#define TITAN_GE_WRITE(offset, data) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) = (data) ++ ++#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset)) ++ ++#ifndef msec_delay ++#define msec_delay(x) do { if(in_interrupt()) { \ ++ /* Don't mdelay in interrupt context! */ \ ++ BUG(); \ ++ } else { \ ++ set_current_state(TASK_UNINTERRUPTIBLE); \ ++ schedule_timeout((x * HZ)/1000); \ ++ } } while(0) ++#endif ++ ++#define TITAN_GE_PORT_0 ++ ++#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4) ++#define TITAN_SRAM_SIZE 0x2000UL ++ ++/* ++ * We may need these constants ++ */ ++#define TITAN_BIT0 0x00000001 ++#define TITAN_BIT1 0x00000002 ++#define TITAN_BIT2 0x00000004 ++#define TITAN_BIT3 0x00000008 ++#define TITAN_BIT4 0x00000010 ++#define TITAN_BIT5 0x00000020 ++#define TITAN_BIT6 0x00000040 ++#define TITAN_BIT7 0x00000080 ++#define TITAN_BIT8 0x00000100 ++#define TITAN_BIT9 0x00000200 ++#define TITAN_BIT10 0x00000400 ++#define TITAN_BIT11 0x00000800 ++#define TITAN_BIT12 0x00001000 ++#define TITAN_BIT13 0x00002000 ++#define TITAN_BIT14 0x00004000 ++#define TITAN_BIT15 0x00008000 ++#define TITAN_BIT16 0x00010000 ++#define TITAN_BIT17 0x00020000 ++#define TITAN_BIT18 0x00040000 ++#define TITAN_BIT19 0x00080000 ++#define TITAN_BIT20 0x00100000 ++#define TITAN_BIT21 0x00200000 ++#define TITAN_BIT22 0x00400000 ++#define TITAN_BIT23 0x00800000 ++#define TITAN_BIT24 0x01000000 ++#define TITAN_BIT25 0x02000000 ++#define TITAN_BIT26 0x04000000 ++#define TITAN_BIT27 0x08000000 ++#define TITAN_BIT28 0x10000000 ++#define TITAN_BIT29 0x20000000 ++#define TITAN_BIT30 0x40000000 ++#define TITAN_BIT31 0x80000000 ++ ++/* Flow Control */ ++#define TITAN_GE_FC_NONE 0x0 ++#define TITAN_GE_FC_FULL 0x1 ++#define TITAN_GE_FC_TX_PAUSE 0x2 ++#define TITAN_GE_FC_RX_PAUSE 0x3 ++ ++/* Duplex Settings */ ++#define TITAN_GE_FULL_DUPLEX 0x1 ++#define TITAN_GE_HALF_DUPLEX 0x2 ++ ++/* Speed settings */ ++#define TITAN_GE_SPEED_1000 0x1 ++#define TITAN_GE_SPEED_100 0x2 ++#define TITAN_GE_SPEED_10 0x3 ++ ++/* Debugging info only */ ++#undef TITAN_DEBUG ++ ++/* Keep the rings in the Titan's SSRAM */ ++#define TITAN_RX_RING_IN_SRAM ++ ++#ifdef CONFIG_64BIT ++#define TITAN_GE_IE_MASK 0xfffffffffb001b64 ++#define TITAN_GE_IE_STATUS 0xfffffffffb001b60 ++#else ++#define TITAN_GE_IE_MASK 0xfb001b64 ++#define TITAN_GE_IE_STATUS 0xfb001b60 ++#endif ++ ++/* Support for Jumbo Frames */ ++#undef TITAN_GE_JUMBO_FRAMES ++ ++/* Rx buffer size */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++#define TITAN_GE_JUMBO_BUFSIZE 9080 ++#else ++#define TITAN_GE_STD_BUFSIZE 1580 ++#endif ++ ++/* ++ * Tx and Rx Interrupt Coalescing parameter. These values are ++ * for 1 Ghz processor. Rx coalescing can be taken care of ++ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing ++ * is not adaptive. Hence, these values need to be adjusted ++ * based on load, CPU speed etc. ++ */ ++#define TITAN_GE_RX_COAL 150 ++#define TITAN_GE_TX_COAL 300 ++ ++#if defined(__BIG_ENDIAN) ++ ++/* Define the Rx descriptor */ ++typedef struct eth_rx_desc { ++ u32 reserved; /* Unused */ ++ u32 buffer_addr; /* CPU buffer address */ ++ u32 cmd_sts; /* Command and Status */ ++ u32 buffer; /* XDMA buffer address */ ++} titan_ge_rx_desc; ++ ++/* Define the Tx descriptor */ ++typedef struct eth_tx_desc { ++ u16 cmd_sts; /* Command, Status and Buffer count */ ++ u16 buffer_len; /* Length of the buffer */ ++ u32 buffer_addr; /* Physical address of the buffer */ ++} titan_ge_tx_desc; ++ ++#elif defined(__LITTLE_ENDIAN) ++ ++/* Define the Rx descriptor */ ++typedef struct eth_rx_desc { ++ u32 buffer_addr; /* CPU buffer address */ ++ u32 reserved; /* Unused */ ++ u32 buffer; /* XDMA buffer address */ ++ u32 cmd_sts; /* Command and Status */ ++} titan_ge_rx_desc; ++ ++/* Define the Tx descriptor */ ++typedef struct eth_tx_desc { ++ u32 buffer_addr; /* Physical address of the buffer */ ++ u16 buffer_len; /* Length of the buffer */ ++ u16 cmd_sts; /* Command, Status and Buffer count */ ++} titan_ge_tx_desc; ++#endif ++ ++/* Default Tx Queue Size */ ++#define TITAN_GE_TX_QUEUE 128 ++#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc)) ++ ++/* Default Rx Queue Size */ ++#define TITAN_GE_RX_QUEUE 64 ++#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc)) ++ ++/* Packet Structure */ ++typedef struct _pkt_info { ++ unsigned int len; ++ unsigned int cmd_sts; ++ unsigned int buffer; ++ struct sk_buff *skb; ++ unsigned int checksum; ++} titan_ge_packet; ++ ++ ++#define PHYS_CNT 3 ++ ++/* Titan Port specific data structure */ ++typedef struct _eth_port_ctrl { ++ unsigned int port_num; ++ u8 port_mac_addr[6]; ++ ++ /* Rx descriptor pointers */ ++ int rx_curr_desc_q, rx_used_desc_q; ++ ++ /* Tx descriptor pointers */ ++ int tx_curr_desc_q, tx_used_desc_q; ++ ++ /* Rx descriptor area */ ++ volatile titan_ge_rx_desc *rx_desc_area; ++ unsigned int rx_desc_area_size; ++ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE]; ++ ++ /* Tx Descriptor area */ ++ volatile titan_ge_tx_desc *tx_desc_area; ++ unsigned int tx_desc_area_size; ++ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE]; ++ ++ /* Timeout task */ ++ struct work_struct tx_timeout_task; ++ ++ /* DMA structures and handles */ ++ dma_addr_t tx_dma; ++ dma_addr_t rx_dma; ++ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE]; ++ ++ /* Device lock */ ++ spinlock_t lock; ++ ++ unsigned int tx_ring_skbs; ++ unsigned int rx_ring_size; ++ unsigned int tx_ring_size; ++ unsigned int rx_ring_skbs; ++ ++ struct net_device_stats stats; ++ ++ /* Tx and Rx coalescing */ ++ unsigned long rx_int_coal; ++ unsigned long tx_int_coal; ++ ++ /* Threshold for replenishing the Rx and Tx rings */ ++ unsigned int tx_threshold; ++ unsigned int rx_threshold; ++ ++ /* NAPI work limit */ ++ unsigned int rx_work_limit; ++} titan_ge_port_info; ++ ++/* Titan specific constants */ ++#define TITAN_ETH_PORT_IRQ 3 ++ ++/* Max Rx buffer */ ++#define TITAN_GE_MAX_RX_BUFFER 65536 ++ ++/* Tx and Rx Error */ ++#define TITAN_GE_ERROR ++ ++/* Rx Descriptor Command and Status */ ++ ++#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */ ++#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */ ++#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */ ++#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */ ++#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */ ++#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */ ++#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */ ++#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */ ++#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */ ++#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */ ++ ++/* Tx Descriptor Command */ ++#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */ ++#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */ ++ ++/* Return Status */ ++#define TITAN_OK 0x1 /* Good Status */ ++#define TITAN_ERROR 0x2 /* Error Status */ ++ ++/* MIB specific register offset */ ++#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */ ++#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */ ++#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */ ++#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */ ++#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */ ++ ++/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */ ++#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040 ++#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050 ++#define TITAN_GE_MSTATX_RXFRAMES 0x0060 ++#define TITAN_GE_MSTATX_RXOCTETS 0x0070 ++#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080 ++#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090 ++#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0 ++#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0 ++#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0 ++#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0 ++#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0 ++#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0 ++#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100 ++#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110 ++#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120 ++#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130 ++#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140 ++#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150 ++#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160 ++#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170 ++#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180 ++#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190 ++#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0 ++#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0 ++#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0 ++#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0 ++#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0 ++#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0 ++#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200 ++#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210 ++#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220 ++#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230 ++#define TITAN_GE_MSTATX_HASHFILTERED 0x0240 ++#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250 ++#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260 ++#define TITAN_GE_MSTATX_TXOCTETS 0x0270 ++#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280 ++#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290 ++#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0 ++#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0 ++#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0 ++#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0 ++#define TITAN_GE_MSTATX_TXMACERROR 0x02E0 ++#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0 ++#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300 ++#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310 ++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320 ++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330 ++#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340 ++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350 ++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360 ++#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370 ++#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380 ++#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390 ++#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0 ++#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0 ++#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0 ++#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0 ++#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0 ++#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0 ++#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400 ++#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410 ++#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420 ++#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430 ++#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440 ++ ++/* Interrupt specific defines */ ++#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */ ++#define TITAN_GE_RESET 0x0004 /* Reset reg */ ++#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */ ++#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */ ++#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */ ++#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/ ++#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/ ++#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */ ++#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */ ++#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/ ++#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */ ++#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/ ++#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */ ++#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */ ++#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */ ++#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */ ++#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */ ++#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */ ++#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */ ++#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */ ++ ++/* Rx MAC defines */ ++#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */ ++#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */ ++#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */ ++#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */ ++#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */ ++#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */ ++#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */ ++ ++/* Tx MAC defines */ ++#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */ ++#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */ ++#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */ ++#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */ ++#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */ ++#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */ ++#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */ ++#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */ ++#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */ ++#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */ ++ ++/* GMII register */ ++#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */ ++#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */ ++#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */ ++ ++/* Tx and Rx XDMA defines */ ++#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */ ++#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */ ++#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */ ++#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */ ++#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */ ++#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */ ++#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */ ++#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */ ++ ++/* AFX (Address Filter Exact) register offsets for Slice 0 */ ++#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/ ++#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/ ++#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */ ++#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */ ++#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */ ++#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */ ++#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */ ++#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */ ++ ++/* Traffic Groomer block */ ++#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */ ++ ++#endif /* _TITAN_GE_H_ */ ++ +diff --git a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c +new file mode 100644 +index 0000000..8a8785b +--- /dev/null ++++ b/drivers/net/titan_mdio.c +@@ -0,0 +1,217 @@ ++/* ++ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports ++ * ++ * Copyright (C) 2003 PMC-Sierra Inc. ++ * Author : Manish Lachwani (lachwani@pmc-sierra.com) ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY ++ * on the Titan. No support for the TBI as yet. ++ * ++ */ ++ ++#include "titan_mdio.h" ++ ++#define MDIO_DEBUG ++ ++/* ++ * Local constants ++ */ ++#define MAX_CLKA 1023 ++#define MAX_PHY_DEV 31 ++#define MAX_PHY_REG 31 ++#define WRITEADDRS_OPCODE 0x0 ++#define READ_OPCODE 0x2 ++#define WRITE_OPCODE 0x1 ++#define MAX_MDIO_POLL 100 ++ ++/* ++ * Titan MDIO and SCMB registers ++ */ ++#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */ ++#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */ ++#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */ ++#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */ ++#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */ ++#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */ ++ ++/* ++ * Function to poll the MDIO ++ */ ++static int titan_ge_mdio_poll(void) ++{ ++ int i, val; ++ ++ for (i = 0; i < MAX_MDIO_POLL; i++) { ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ ++ if (!(val & 0x8000)) ++ return TITAN_GE_MDIO_GOOD; ++ } ++ ++ return TITAN_GE_MDIO_ERROR; ++} ++ ++ ++/* ++ * Initialize and configure the MDIO ++ */ ++int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio) ++{ ++ unsigned long val; ++ ++ /* Reset the SCMB and program into MDIO mode*/ ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000); ++ ++ /* CLK A */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA); ++ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val); ++ ++ /* Preamble Suppresion */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ /* MDIO mode */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Set the PHY address in indirect mode ++ */ ++int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr) ++{ ++ volatile unsigned long val; ++ ++ /* Setup the PHY device */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ /* Write the new address */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Read the MDIO register. This is what the individual parametes mean: ++ * ++ * dev_addr : PHY ID ++ * reg_addr : register offset ++ * ++ * See the spec for the Titan MAC. We operate in the Direct Mode. ++ */ ++ ++#define MAX_RETRIES 2 ++ ++int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata) ++{ ++ volatile unsigned long val; ++ int retries = 0; ++ ++ /* Setup the PHY device */ ++ ++again: ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ val |= 0x4000; ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ udelay(30); ++ ++ /* Issue the read command */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ udelay(30); ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA); ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); ++ ++ udelay(30); ++ ++ if (val & 0x2) { ++ if (retries == MAX_RETRIES) ++ return TITAN_GE_MDIO_ERROR; ++ else { ++ retries++; ++ goto again; ++ } ++ } ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Write to the MDIO register ++ * ++ * dev_addr : PHY ID ++ * reg_addr : register that needs to be written to ++ * ++ */ ++int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data) ++{ ++ volatile unsigned long val; ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ /* Setup the PHY device */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ val |= 0x4000; ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ udelay(30); ++ ++ /* Setup the data to write */ ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data); ++ ++ udelay(30); ++ ++ /* Issue the write command */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ udelay(30); ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); ++ if (val & 0x2) ++ return TITAN_GE_MDIO_ERROR; ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ +diff --git a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h +new file mode 100644 +index 0000000..5d23344 +--- /dev/null ++++ b/drivers/net/titan_mdio.h +@@ -0,0 +1,56 @@ ++/* ++ * MDIO used to interact with the PHY when using GMII/MII ++ */ ++#ifndef _TITAN_MDIO_H ++#define _TITAN_MDIO_H ++ ++#include ++#include ++#include ++#include "titan_ge.h" ++ ++ ++#define TITAN_GE_MDIO_ERROR (-9000) ++#define TITAN_GE_MDIO_GOOD 0 ++ ++#define TITAN_GE_MDIO_BASE titan_ge_base ++ ++#define TITAN_GE_MDIO_READ(offset) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) ++ ++#define TITAN_GE_MDIO_WRITE(offset, data) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) = (data) ++ ++ ++/* GMII specific registers */ ++#define TITAN_GE_MARVEL_PHY_ID 0x00 ++#define TITAN_PHY_AUTONEG_ADV 0x04 ++#define TITAN_PHY_LP_ABILITY 0x05 ++#define TITAN_GE_MDIO_MII_CTRL 0x09 ++#define TITAN_GE_MDIO_MII_EXTENDED 0x0f ++#define TITAN_GE_MDIO_PHY_CTRL 0x10 ++#define TITAN_GE_MDIO_PHY_STATUS 0x11 ++#define TITAN_GE_MDIO_PHY_IE 0x12 ++#define TITAN_GE_MDIO_PHY_IS 0x13 ++#define TITAN_GE_MDIO_PHY_LED 0x18 ++#define TITAN_GE_MDIO_PHY_LED_OVER 0x19 ++#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */ ++ ++/* ++ * MDIO Config Structure ++ */ ++typedef struct { ++ unsigned int clka; ++ int mdio_spre; ++ int mdio_mode; ++} titan_ge_mdio_config; ++ ++/* ++ * Function Prototypes ++ */ ++int titan_ge_mdio_setup(titan_ge_mdio_config *); ++int titan_ge_mdio_inaddrs(int, int); ++int titan_ge_mdio_read(int, int, unsigned int *); ++int titan_ge_mdio_write(int, int, unsigned int); ++ ++#endif /* _TITAN_MDIO_H */ +diff --git a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c +index 3411671..4d252c1 100644 +--- a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c ++++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c +@@ -22,6 +22,10 @@ + + static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) + { ++#ifdef CONFIG_LEMOTE_MACH2F ++ /* Allow users to activate rfkill through only the /sys interface */ ++ return 1; ++#else + u8 gpio; + + gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); +@@ -29,6 +33,7 @@ static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) + gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); + + return gpio & priv->rfkill_mask; ++#endif + } + + void rtl8187_rfkill_init(struct ieee80211_hw *hw) +diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig +index 09fde58..eacabd1 100644 +--- a/drivers/platform/Kconfig ++++ b/drivers/platform/Kconfig +@@ -4,5 +4,8 @@ endif + if GOLDFISH + source "drivers/platform/goldfish/Kconfig" + endif ++if MIPS ++source "drivers/platform/mips/Kconfig" ++endif + + source "drivers/platform/chrome/Kconfig" +diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile +index 3656b7b..ca26925 100644 +--- a/drivers/platform/Makefile ++++ b/drivers/platform/Makefile +@@ -3,6 +3,7 @@ + # + + obj-$(CONFIG_X86) += x86/ ++obj-$(CONFIG_MIPS) += mips/ + obj-$(CONFIG_OLPC) += olpc/ + obj-$(CONFIG_GOLDFISH) += goldfish/ + obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ +diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig +new file mode 100644 +index 0000000..722d690 +--- /dev/null ++++ b/drivers/platform/mips/Kconfig +@@ -0,0 +1,60 @@ ++# ++# MIPS Platform Specific Drivers ++# ++ ++menuconfig MIPS_PLATFORM_DEVICES ++ bool "MIPS Platform Specific Device Drivers" ++ default y ++ help ++ Say Y here to get to see options for device drivers of various ++ MIPS platforms, including vendor-specific netbook/laptop/pc extension ++ drivers. This option alone does not add any kernel code. ++ ++ If you say N, all options in this submenu will be skipped and disabled. ++ ++if MIPS_PLATFORM_DEVICES ++ ++config LEMOTE_YEELOONG2F ++ tristate "Lemote YeeLoong Laptop" ++ depends on LEMOTE_MACH2F ++ select BACKLIGHT_LCD_SUPPORT ++ select LCD_CLASS_DEVICE ++ select BACKLIGHT_CLASS_DEVICE ++ select POWER_SUPPLY ++ select HWMON ++ select VIDEO_OUTPUT_CONTROL ++ select INPUT_SPARSEKMAP ++ select INPUT_EVDEV ++ depends on INPUT ++ default m ++ help ++ YeeLoong netbook is a mini laptop made by Lemote, which is basically ++ compatible to FuLoong2F mini PC, but it has an extra Embedded ++ Controller(kb3310b) for battery, hotkey, backlight, temperature and ++ fan management. ++ ++config LEMOTE_LYNLOONG2F ++ tristate "Lemote LynLoong PC" ++ depends on LEMOTE_MACH2F ++ select BACKLIGHT_LCD_SUPPORT ++ select BACKLIGHT_CLASS_DEVICE ++ select VIDEO_OUTPUT_CONTROL ++ default m ++ help ++ LynLoong PC is an AllINONE machine made by Lemote, which is basically ++ compatible to FuLoong2F Mini PC, the only difference is that it has a ++ size-fixed screen: 1360x768 with sisfb video driver. and also, it has ++ its own specific suspend support. ++ ++config GDIUM_LAPTOP ++ tristate "GDIUM laptop extras" ++ depends on DEXXON_GDIUM ++ select POWER_SUPPLY ++ select I2C ++ select INPUT_POLLDEV ++ default m ++ help ++ This mini-driver drives the ST7 chipset present in the Gdium laptops. ++ This gives battery support, wlan rfkill. ++ ++endif # MIPS_PLATFORM_DEVICES +diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile +new file mode 100644 +index 0000000..f013e78 +--- /dev/null ++++ b/drivers/platform/mips/Makefile +@@ -0,0 +1,9 @@ ++# ++# Makefile for MIPS Platform-Specific Drivers ++# ++ ++obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o # yeeloong_ecrom.o ++CFLAGS_yeeloong_laptop.o = -I$(srctree)/arch/mips/loongson/lemote-2f ++ ++obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o ++obj-$(CONFIG_GDIUM_LAPTOP) += gdium_laptop.o +diff --git a/drivers/platform/mips/gdium_laptop.c b/drivers/platform/mips/gdium_laptop.c +new file mode 100644 +index 0000000..41a65ad +--- /dev/null ++++ b/drivers/platform/mips/gdium_laptop.c +@@ -0,0 +1,927 @@ ++/* ++ * gdium_laptop -- Gdium laptop extras ++ * ++ * Arnaud Patard ++ * ++ * 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. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* For input device */ ++#define SCAN_INTERVAL 150 ++ ++/* For battery status */ ++#define BAT_SCAN_INTERVAL 500 ++ ++#define EC_FIRM_VERSION 0 ++ ++#if CONFIG_GDIUM_VERSION > 2 ++#define EC_REG_BASE 1 ++#else ++#define EC_REG_BASE 0 ++#endif ++ ++#define EC_STATUS (EC_REG_BASE+0) ++#define EC_STATUS_LID (1<<0) ++#define EC_STATUS_PWRBUT (1<<1) ++#define EC_STATUS_BATID (1<<2) /* this bit has no real meaning on v2. */ ++ /* Same as EC_STATUS_ADAPT */ ++ /* but on v3 it's BATID which mean bat present */ ++#define EC_STATUS_SYS_POWER (1<<3) ++#define EC_STATUS_WLAN (1<<4) ++#define EC_STATUS_ADAPT (1<<5) ++ ++#define EC_CTRL (EC_REG_BASE+1) ++#define EC_CTRL_DDR_CLK (1<<0) ++#define EC_CTRL_CHARGE_LED (1<<1) ++#define EC_CTRL_BEEP (1<<2) ++#define EC_CTRL_SUSB (1<<3) /* memory power */ ++#define EC_CTRL_TRICKLE (1<<4) ++#define EC_CTRL_WLAN_EN (1<<5) ++#define EC_CTRL_SUSC (1<<6) /* main power */ ++#define EC_CTRL_CHARGE_EN (1<<7) ++ ++#define EC_BAT_LOW (EC_REG_BASE+2) ++#define EC_BAT_HIGH (EC_REG_BASE+3) ++ ++#define EC_SIGN (EC_REG_BASE+4) ++#define EC_SIGN_OS 0xAE /* write 0xae to control pm stuff */ ++#define EC_SIGN_EC 0x00 /* write 0x00 to let the st7 manage pm stuff */ ++ ++#if 0 ++#define EC_TEST (EC_REG_BASE+5) /* Depending on firmware version this register */ ++ /* may be the programmation register so don't play */ ++ /* with it */ ++#endif ++ ++#define BAT_VOLT_PRESENT 500000 /* Min voltage to consider battery present uV */ ++#define BAT_MIN 7000000 /* Min battery voltage in uV */ ++#define BAT_MIN_MV 7000 /* Min battery voltage in mV */ ++#define BAT_TRICKLE_EN 8000000 /* Charging at 1.4A before 8.0V and then charging at 0.25A */ ++#define BAT_MAX 7950000 /* Max battery voltage ~8V in V */ ++#define BAT_MAX_MV 7950 /* Max battery voltage ~8V in V */ ++#define BAT_READ_ERROR 300000 /* battery read error of 0.3V */ ++#define BAT_READ_ERROR_MV 300 /* battery read error of 0.3V */ ++ ++#define SM502_WLAN_ON (224+16)/* SM502 GPIO16 may be used on gdium v2 (v3?) as wlan_on */ ++ /* when R422 is connected */ ++ ++static unsigned char verbose; ++static unsigned char gpio16; ++static unsigned char ec; ++module_param(verbose, byte, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(verbose, "Add some debugging messages"); ++module_param(gpio16, byte, S_IRUGO); ++MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502"); ++module_param(ec, byte, S_IRUGO); ++MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)"); ++ ++struct gdium_laptop_data { ++ struct i2c_client *client; ++ struct input_polled_dev *input_polldev; ++ struct dentry *debugfs; ++ struct mutex mutex; ++ struct platform_device *bat_pdev; ++ struct power_supply gdium_ac; ++ struct power_supply gdium_battery; ++ struct workqueue_struct *workqueue; ++ struct delayed_work work; ++ char charge_cmd; ++ /* important registers value */ ++ char status; ++ char ctrl; ++ /* mV */ ++ int battery_level; ++ char version; ++}; ++ ++/**********************************************************************/ ++/* Low level I2C functions */ ++/* All are supposed to be called with mutex held */ ++/**********************************************************************/ ++/* ++ * Return battery voltage in mV ++ * >= 0 battery voltage ++ * < 0 error ++ */ ++static s32 ec_read_battery(struct i2c_client *client) ++{ ++ unsigned char bat_low, bat_high; ++ s32 data; ++ unsigned int ret; ++ ++ /* ++ * a = battery high ++ * b = battery low ++ * bat = a << 2 | b & 0x03; ++ * battery voltage = (bat / 1024) * 5 * 2 ++ */ ++ data = i2c_smbus_read_byte_data(client, EC_BAT_LOW); ++ if (data < 0) { ++ dev_err(&client->dev, "ec_read_bat: read bat_low failed\n"); ++ return data; ++ } ++ bat_low = data & 0xff; ++ if (verbose) ++ dev_info(&client->dev, "bat_low %x\n", bat_low); ++ ++ data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH); ++ if (data < 0) { ++ dev_err(&client->dev, "ec_read_bat: read bat_high failed\n"); ++ return data; ++ } ++ bat_high = data & 0xff; ++ if (verbose) ++ dev_info(&client->dev, "bat_high %x\n", bat_high); ++ ++ ret = (bat_high << 2) | (bat_low & 3); ++ /* ++ * mV ++ */ ++ ret = (ret * 5 * 2) * 1000 / 1024; ++ ++ return ret; ++} ++ ++static s32 ec_read_version(struct i2c_client *client) ++{ ++#if CONFIG_GDIUM_VERSION > 2 ++ return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION); ++#else ++ return 0; ++#endif ++} ++ ++static s32 ec_read_status(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_STATUS); ++} ++ ++static s32 ec_read_ctrl(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_CTRL); ++} ++ ++static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue) ++{ ++ return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue); ++} ++ ++static s32 ec_read_sign(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_SIGN); ++} ++ ++static s32 ec_write_sign(struct i2c_client *client, unsigned char sign) ++{ ++ unsigned char value; ++ s32 ret; ++ ++ ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign); ++ if (ret < 0) { ++ dev_err(&client->dev, "ec_set_control: write failed\n"); ++ return ret; ++ } ++ ++ value = ec_read_sign(client); ++ if (value != sign) { ++ dev_err(&client->dev, "Failed to set control to %s\n", ++ sign == EC_SIGN_OS ? "OS" : "EC"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++#if 0 ++static int ec_power_off(struct i2c_client *client) ++{ ++ char value; ++ int ret; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) { ++ dev_err(&client->dev, "ec_power_off: read failed\n"); ++ return value; ++ } ++ value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC); ++ ret = ec_write_ctrl(client, value); ++ if (ret < 0) { ++ dev_err(&client->dev, "ec_power_off: write failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++static s32 ec_wlan_status(struct i2c_client *client) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ return (value & EC_CTRL_WLAN_EN) ? 1 : 0; ++} ++ ++static s32 ec_wlan_en(struct i2c_client *client, int on) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ value &= ~EC_CTRL_WLAN_EN; ++ if (on) ++ value |= EC_CTRL_WLAN_EN; ++ ++ return ec_write_ctrl(client, value&0xff); ++} ++ ++#if 0 ++static s32 ec_led_status(struct i2c_client *client) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ return (value & EC_CTRL_CHARGE_LED) ? 1 : 0; ++} ++#endif ++ ++/* Changing the charging led status has never worked */ ++static s32 ec_led_en(struct i2c_client *client, int on) ++{ ++#if 0 ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ value &= ~EC_CTRL_CHARGE_LED; ++ if (on) ++ value |= EC_CTRL_CHARGE_LED; ++ return ec_write_ctrl(client, value&0xff); ++#else ++ return 0; ++#endif ++} ++ ++static s32 ec_charge_en(struct i2c_client *client, int on, int trickle) ++{ ++ s32 value; ++ s32 set = 0; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ if (on) ++ set |= EC_CTRL_CHARGE_EN; ++ if (trickle) ++ set |= EC_CTRL_TRICKLE; ++ ++ /* Be clever : don't change values if you don't need to */ ++ if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set) ++ return 0; ++ ++ value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE); ++ value |= set; ++ ec_led_en(client, on); ++ return ec_write_ctrl(client, (unsigned char)(value&0xff)); ++ ++} ++ ++/**********************************************************************/ ++/* Input functions */ ++/**********************************************************************/ ++struct gdium_keys { ++ int last_state; ++ int key_code; ++ int mask; ++ int type; ++}; ++ ++static struct gdium_keys gkeys[] = { ++ { ++ .key_code = KEY_WLAN, ++ .mask = EC_STATUS_WLAN, ++ .type = EV_KEY, ++ }, ++ { ++ .key_code = KEY_POWER, ++ .mask = EC_STATUS_PWRBUT, ++ .type = EV_KEY, /*EV_PWR,*/ ++ }, ++ { ++ .key_code = SW_LID, ++ .mask = EC_STATUS_LID, ++ .type = EV_SW, ++ }, ++}; ++ ++static void gdium_laptop_keys_poll(struct input_polled_dev *dev) ++{ ++ int state, i; ++ struct gdium_laptop_data *data = dev->private; ++ struct i2c_client *client = data->client; ++ struct input_dev *input = dev->input; ++ s32 status; ++ ++ mutex_lock(&data->mutex); ++ status = ec_read_status(client); ++ mutex_unlock(&data->mutex); ++ ++ if (status < 0) { ++ /* ++ * Don't know exactly which version of the firmware ++ * has this bug but when the power button is pressed ++ * there are i2c read errors :( ++ */ ++ if ((data->version >= 0x13) && !gkeys[1].last_state) { ++ input_event(input, EV_KEY, KEY_POWER, 1); ++ input_sync(input); ++ gkeys[1].last_state = 1; ++ } ++ return; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(gkeys); i++) { ++ state = status & gkeys[i].mask; ++ if (state != gkeys[i].last_state) { ++ gkeys[i].last_state = state; ++ /* for power key, we want power & key press/release event */ ++ if (gkeys[i].type == EV_PWR) { ++ input_event(input, EV_KEY, gkeys[i].key_code, !!state); ++ input_sync(input); ++ } ++ /* Disable wifi on key press but not key release */ ++ /* ++ * On firmware >= 0x13 the EC_STATUS_WLAN has it's ++ * original meaning of Wifi status and no more the ++ * wifi button status so we have to ignore the event ++ * on theses versions ++ */ ++ if (state && (gkeys[i].key_code == KEY_WLAN) && (data->version < 0x13)) { ++ mutex_lock(&data->mutex); ++ ec_wlan_en(client, !ec_wlan_status(client)); ++ if (gpio16) ++ gpio_set_value(SM502_WLAN_ON, !ec_wlan_status(client)); ++ mutex_unlock(&data->mutex); ++ } ++ ++ input_event(input, gkeys[i].type, gkeys[i].key_code, !!state); ++ input_sync(input); ++ } ++ } ++} ++ ++static int gdium_laptop_input_init(struct gdium_laptop_data *data) ++{ ++ struct i2c_client *client = data->client; ++ struct input_dev *input; ++ int ret, i; ++ ++ data->input_polldev = input_allocate_polled_device(); ++ if (!data->input_polldev) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ input = data->input_polldev->input; ++ input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW); ++ data->input_polldev->poll = gdium_laptop_keys_poll; ++ data->input_polldev->poll_interval = SCAN_INTERVAL; ++ data->input_polldev->private = data; ++ input->name = "gdium-keys"; ++ input->dev.parent = &client->dev; ++ ++ input->id.bustype = BUS_HOST; ++ input->id.vendor = 0x0001; ++ input->id.product = 0x0001; ++ input->id.version = 0x0100; ++ ++ for (i = 0; i < ARRAY_SIZE(gkeys); i++) ++ input_set_capability(input, gkeys[i].type, gkeys[i].key_code); ++ ++ ret = input_register_polled_device(data->input_polldev); ++ if (ret) { ++ dev_err(&client->dev, "Unable to register button device\n"); ++ goto err_poll_dev; ++ } ++ ++ return 0; ++ ++err_poll_dev: ++ input_free_polled_device(data->input_polldev); ++err: ++ return ret; ++} ++ ++static void gdium_laptop_input_exit(struct gdium_laptop_data *data) ++{ ++ input_unregister_polled_device(data->input_polldev); ++ input_free_polled_device(data->input_polldev); ++} ++ ++/**********************************************************************/ ++/* Battery management */ ++/**********************************************************************/ ++static int gdium_ac_get_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ char status; ++ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_ac); ++ int ret = 0; ++ ++ if (!data) { ++ pr_err("gdium-ac: gdium_laptop_data not found\n"); ++ return -EINVAL; ++ } ++ ++ status = data->status; ++ switch (psp) { ++ case POWER_SUPPLY_PROP_ONLINE: ++ val->intval = !!(status & EC_STATUS_ADAPT); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#undef RET ++#define RET (val->intval) ++ ++static int gdium_battery_get_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ char status, ctrl; ++ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_battery); ++ int percentage_capacity = 0, charge_now = 0, time_to_empty = 0; ++ int ret = 0, tmp; ++ ++ if (!data) { ++ pr_err("gdium-battery: gdium_laptop_data not found\n"); ++ return -EINVAL; ++ } ++ ++ status = data->status; ++ ctrl = data->ctrl; ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ++ /* uAh */ ++ RET = 5000000; ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ++ /* This formula is gotten by gnuplot with the statistic data */ ++ time_to_empty = (data->battery_level - BAT_MIN_MV + BAT_READ_ERROR_MV) * 113 - 29870; ++ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) { ++ /* seconds */ ++ RET = time_to_empty / 10; ++ break; ++ } ++ /* fall through */ ++ case POWER_SUPPLY_PROP_CHARGE_NOW: ++ case POWER_SUPPLY_PROP_CAPACITY: { ++ tmp = data->battery_level * 1000; ++ /* > BAT_MIN to avoid negative values */ ++ percentage_capacity = 0; ++ if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN)) ++ percentage_capacity = (tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN); ++ ++ if (percentage_capacity > 100) ++ percentage_capacity = 100; ++ ++ if (psp == POWER_SUPPLY_PROP_CAPACITY) { ++ RET = percentage_capacity; ++ break; ++ } ++ charge_now = 50000 * percentage_capacity; ++ if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) { ++ /* uAh */ ++ RET = charge_now; ++ break; ++ } ++ } /* fall through */ ++ case POWER_SUPPLY_PROP_STATUS: { ++ if (status & EC_STATUS_ADAPT) ++ if (ctrl & EC_CTRL_CHARGE_EN) ++ RET = POWER_SUPPLY_STATUS_CHARGING; ++ else ++ RET = POWER_SUPPLY_STATUS_NOT_CHARGING; ++ else ++ RET = POWER_SUPPLY_STATUS_DISCHARGING; ++ ++ if (psp == POWER_SUPPLY_PROP_STATUS) ++ break; ++ /* mAh -> µA */ ++ switch (RET) { ++ case POWER_SUPPLY_STATUS_CHARGING: ++ RET = -(data->charge_cmd == 2) ? 1400000 : 250000; ++ break; ++ case POWER_SUPPLY_STATUS_DISCHARGING: ++ RET = charge_now / time_to_empty * 36000; ++ break; ++ case POWER_SUPPLY_STATUS_NOT_CHARGING: ++ default: ++ RET = 0; ++ break; ++ } ++ } break; ++ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: ++ RET = BAT_MAX+BAT_READ_ERROR; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: ++ RET = BAT_MIN-BAT_READ_ERROR; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ /* mV -> uV */ ++ RET = data->battery_level * 1000; ++ break; ++ case POWER_SUPPLY_PROP_PRESENT: ++#if CONFIG_GDIUM_VERSION > 2 ++ RET = !!(status & EC_STATUS_BATID); ++#else ++ RET = !!(data->battery_level > BAT_VOLT_PRESENT); ++#endif ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: ++ tmp = data->battery_level * 1000; ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ if (status & EC_STATUS_BATID) { ++ if (tmp >= BAT_MAX) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; ++ if (tmp >= BAT_MAX+BAT_READ_ERROR) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; ++ } else if (tmp <= BAT_MIN+BAT_READ_ERROR) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; ++ if (tmp <= BAT_MIN) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; ++ } else ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; ++ } ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_TYPE: ++ if (ctrl & EC_CTRL_TRICKLE) ++ RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; ++ else if (ctrl & EC_CTRL_CHARGE_EN) ++ RET = POWER_SUPPLY_CHARGE_TYPE_FAST; ++ else ++ RET = POWER_SUPPLY_CHARGE_TYPE_NONE; ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_MAX: ++ /* 1.4A ? */ ++ RET = 1400000; ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++#undef RET ++ ++static enum power_supply_property gdium_ac_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++}; ++ ++static enum power_supply_property gdium_battery_props[] = { ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_NOW, ++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, ++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_CURRENT_MAX, ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_CAPACITY_LEVEL, ++ POWER_SUPPLY_PROP_CHARGE_TYPE, ++}; ++ ++static void gdium_laptop_battery_work(struct work_struct *work) ++{ ++ struct gdium_laptop_data *data = container_of(work, struct gdium_laptop_data, work.work); ++ struct i2c_client *client; ++ int ret; ++ char old_status, old_charge_cmd; ++ char present; ++ s32 status; ++ ++ mutex_lock(&data->mutex); ++ client = data->client; ++ status = ec_read_status(client); ++ ret = ec_read_battery(client); ++ ++ if ((status < 0) || (ret < 0)) ++ goto i2c_read_error; ++ ++ old_status = data->status; ++ old_charge_cmd = data->charge_cmd; ++ data->status = status; ++ ++ /* ++ * Charge only if : ++ * - battery present ++ * - ac adapter plugged in ++ * - battery not fully charged ++ */ ++#if CONFIG_GDIUM_VERSION > 2 ++ present = !!(data->status & EC_STATUS_BATID); ++#else ++ present = !!(ret > BAT_VOLT_PRESENT); ++#endif ++ data->battery_level = 0; ++ if (present) { ++ data->battery_level = (unsigned int)ret; ++ if (data->status & EC_STATUS_ADAPT) ++ data->battery_level -= BAT_READ_ERROR_MV; ++ } ++ ++ data->charge_cmd = 0; ++ if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level <= BAT_MAX_MV)) ++ data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3; ++ ++ ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1); ++ ++ /* ++ * data->ctrl must be set _after_ calling ec_charge_en as this will change the ++ * control register content ++ */ ++ data->ctrl = ec_read_ctrl(client); ++ ++ if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) { ++ power_supply_changed(&data->gdium_ac); ++ /* Send charging/discharging state change */ ++ power_supply_changed(&data->gdium_battery); ++ } else if ((data->status & EC_STATUS_ADAPT) && ++ ((old_charge_cmd&2) != (data->charge_cmd&2))) ++ power_supply_changed(&data->gdium_battery); ++ ++i2c_read_error: ++ mutex_unlock(&data->mutex); ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++} ++ ++static int gdium_laptop_battery_init(struct gdium_laptop_data *data) ++{ ++ int ret; ++ ++ data->bat_pdev = platform_device_register_simple("gdium-battery", 0, NULL, 0); ++ if (IS_ERR(data->bat_pdev)) ++ return PTR_ERR(data->bat_pdev); ++ ++ data->gdium_battery.name = data->bat_pdev->name; ++ data->gdium_battery.properties = gdium_battery_props; ++ data->gdium_battery.num_properties = ARRAY_SIZE(gdium_battery_props); ++ data->gdium_battery.get_property = gdium_battery_get_props; ++ data->gdium_battery.use_for_apm = 1; ++ ++ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery); ++ if (ret) ++ goto err_platform; ++ ++ data->gdium_ac.name = "gdium-ac"; ++ data->gdium_ac.type = POWER_SUPPLY_TYPE_MAINS; ++ data->gdium_ac.properties = gdium_ac_props; ++ data->gdium_ac.num_properties = ARRAY_SIZE(gdium_ac_props); ++ data->gdium_ac.get_property = gdium_ac_get_props; ++/* data->gdium_ac.use_for_apm_ac = 1, */ ++ ++ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac); ++ if (ret) ++ goto err_battery; ++ ++ if (!ec) { ++ INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work); ++ data->workqueue = create_singlethread_workqueue("gdium-battery-work"); ++ if (!data->workqueue) { ++ ret = -ESRCH; ++ goto err_work; ++ } ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++ } ++ ++ return 0; ++ ++err_work: ++err_battery: ++ power_supply_unregister(&data->gdium_battery); ++err_platform: ++ platform_device_unregister(data->bat_pdev); ++ ++ return ret; ++} ++static void gdium_laptop_battery_exit(struct gdium_laptop_data *data) ++{ ++ if (!ec) { ++ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); ++ destroy_workqueue(data->workqueue); ++ } ++ power_supply_unregister(&data->gdium_battery); ++ power_supply_unregister(&data->gdium_ac); ++ platform_device_unregister(data->bat_pdev); ++} ++ ++/* Debug fs */ ++static int gdium_laptop_regs_show(struct seq_file *s, void *p) ++{ ++ struct gdium_laptop_data *data = s->private; ++ struct i2c_client *client = data->client; ++ ++ mutex_lock(&data->mutex); ++ seq_printf(s, "Version : 0x%02x\n", (unsigned char)ec_read_version(client)); ++ seq_printf(s, "Status : 0x%02x\n", (unsigned char)ec_read_status(client)); ++ seq_printf(s, "Ctrl : 0x%02x\n", (unsigned char)ec_read_ctrl(client)); ++ seq_printf(s, "Sign : 0x%02x\n", (unsigned char)ec_read_sign(client)); ++ seq_printf(s, "Bat Lo : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_LOW)); ++ seq_printf(s, "Bat Hi : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH)); ++ seq_printf(s, "Battery : %d uV\n", (unsigned int)ec_read_battery(client) * 1000); ++ seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", data->charge_cmd & 1 ? "T" : " "); ++ ++ mutex_unlock(&data->mutex); ++ return 0; ++} ++ ++static int gdium_laptop_regs_open(struct inode *inode, ++ struct file *file) ++{ ++ return single_open(file, gdium_laptop_regs_show, inode->i_private); ++} ++ ++static const struct file_operations gdium_laptop_regs_fops = { ++ .open = gdium_laptop_regs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++ ++static int gdium_laptop_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ struct gdium_laptop_data *data; ++ int ret; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&client->dev, ++ "%s: no smbus_byte support !\n", __func__); ++ return -ENODEV; ++ } ++ ++ data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(client, data); ++ data->client = client; ++ mutex_init(&data->mutex); ++ ++ ret = ec_read_version(client); ++ if (ret < 0) ++ goto err_alloc; ++ ++ data->version = (unsigned char)ret; ++ ++ ret = gdium_laptop_input_init(data); ++ if (ret) ++ goto err_alloc; ++ ++ ret = gdium_laptop_battery_init(data); ++ if (ret) ++ goto err_input; ++ ++ ++ if (!ec) { ++ ret = ec_write_sign(client, EC_SIGN_OS); ++ if (ret) ++ goto err_sign; ++ } ++ ++ if (gpio16) { ++ ret = gpio_request(SM502_WLAN_ON, "wlan-on"); ++ if (ret < 0) ++ goto err_sign; ++ gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client)); ++ gpio_direction_output(SM502_WLAN_ON, 1); ++ } ++ ++ dev_info(&client->dev, "Found firmware 0x%02x\n", data->version); ++ data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO, ++ NULL, data, &gdium_laptop_regs_fops); ++ ++ return 0; ++ ++err_sign: ++ gdium_laptop_battery_exit(data); ++err_input: ++ gdium_laptop_input_exit(data); ++err_alloc: ++ kfree(data); ++ return ret; ++} ++ ++static int gdium_laptop_remove(struct i2c_client *client) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (gpio16) ++ gpio_free(SM502_WLAN_ON); ++ ec_write_sign(client, EC_SIGN_EC); ++ if (data->debugfs) ++ debugfs_remove(data->debugfs); ++ ++ gdium_laptop_battery_exit(data); ++ gdium_laptop_input_exit(data); ++ ++ kfree(data); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (!ec) ++ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); ++ return 0; ++} ++ ++static int gdium_laptop_resume(struct i2c_client *client) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (!ec) ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++ return 0; ++} ++#else ++#define gdium_laptop_suspend NULL ++#define gdium_laptop_resume NULL ++#endif ++static const struct i2c_device_id gdium_id[] = { ++ { "gdium-laptop" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(i2c, gdium_id); ++ ++static struct i2c_driver gdium_laptop_driver = { ++ .driver = { ++ .name = "gdium-laptop", ++ .owner = THIS_MODULE, ++ }, ++ .probe = gdium_laptop_probe, ++ .remove = gdium_laptop_remove, ++ .shutdown = gdium_laptop_remove, ++ .suspend = gdium_laptop_suspend, ++ .resume = gdium_laptop_resume, ++ .id_table = gdium_id, ++}; ++ ++static int __init gdium_laptop_init(void) ++{ ++ return i2c_add_driver(&gdium_laptop_driver); ++} ++ ++static void __exit gdium_laptop_exit(void) ++{ ++ i2c_del_driver(&gdium_laptop_driver); ++} ++ ++module_init(gdium_laptop_init); ++module_exit(gdium_laptop_exit); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("Gdium laptop extras"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/lynloong_pc.c b/drivers/platform/mips/lynloong_pc.c +new file mode 100644 +index 0000000..68f29e4 +--- /dev/null ++++ b/drivers/platform/mips/lynloong_pc.c +@@ -0,0 +1,515 @@ ++/* ++ * Driver for LynLoong PC extras ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin , Xiang Yu ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include /* for backlight subdriver */ ++#include ++#include /* for video output subdriver */ ++#include /* for suspend support */ ++ ++#include ++#include ++ ++#include ++ ++static u32 gpio_base, mfgpt_base; ++ ++static void set_gpio_reg_high(int gpio, int reg) ++{ ++ u32 val; ++ ++ val = inl(gpio_base + reg); ++ val |= (1 << gpio); ++ val &= ~(1 << (16 + gpio)); ++ outl(val, gpio_base + reg); ++ mmiowb(); ++} ++ ++static void set_gpio_reg_low(int gpio, int reg) ++{ ++ u32 val; ++ ++ val = inl(gpio_base + reg); ++ val |= (1 << (16 + gpio)); ++ val &= ~(1 << gpio); ++ outl(val, gpio_base + reg); ++ mmiowb(); ++} ++ ++static void set_gpio_output_low(int gpio) ++{ ++ set_gpio_reg_high(gpio, GPIOL_OUT_EN); ++ set_gpio_reg_low(gpio, GPIOL_OUT_VAL); ++} ++ ++static void set_gpio_output_high(int gpio) ++{ ++ set_gpio_reg_high(gpio, GPIOL_OUT_EN); ++ set_gpio_reg_high(gpio, GPIOL_OUT_VAL); ++} ++ ++/* backlight subdriver */ ++ ++#define MAX_BRIGHTNESS 100 ++#define DEFAULT_BRIGHTNESS 50 ++#define MIN_BRIGHTNESS 0 ++static unsigned int level; ++ ++DEFINE_SPINLOCK(backlight_lock); ++/* Tune the brightness */ ++static void setup_mfgpt2(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&backlight_lock, flags); ++ ++ /* Set MFGPT2 comparator 1,2 */ ++ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1); ++ outw(MAX_BRIGHTNESS, MFGPT2_CMP2); ++ /* Clear MFGPT2 UP COUNTER */ ++ outw(0, MFGPT2_CNT); ++ /* Enable counter, compare mode, 32k */ ++ outw(0x8280, MFGPT2_SETUP); ++ ++ spin_unlock_irqrestore(&backlight_lock, flags); ++} ++ ++static int lynloong_set_brightness(struct backlight_device *bd) ++{ ++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && ++ bd->props.power == FB_BLANK_UNBLANK) ? ++ bd->props.brightness : 0; ++ ++ if (level > MAX_BRIGHTNESS) ++ level = MAX_BRIGHTNESS; ++ else if (level < MIN_BRIGHTNESS) ++ level = MIN_BRIGHTNESS; ++ ++ setup_mfgpt2(); ++ ++ return 0; ++} ++ ++static int lynloong_get_brightness(struct backlight_device *bd) ++{ ++ return level; ++} ++ ++static struct backlight_ops backlight_ops = { ++ .get_brightness = lynloong_get_brightness, ++ .update_status = lynloong_set_brightness, ++}; ++ ++static struct backlight_device *lynloong_backlight_dev; ++ ++static int lynloong_backlight_init(void) ++{ ++ int ret; ++ u32 hi; ++ struct backlight_properties props; ++ ++ /* Get gpio_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); ++ /* Get mfgpt_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base); ++ /* Get gpio_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); ++ ++ /* Select for mfgpt */ ++ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL); ++ /* Enable brightness controlling */ ++ set_gpio_output_high(7); ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.max_brightness = MAX_BRIGHTNESS; ++ props.type = BACKLIGHT_PLATFORM; ++ lynloong_backlight_dev = backlight_device_register("backlight0", NULL, ++ NULL, &backlight_ops, &props); ++ ++ if (IS_ERR(lynloong_backlight_dev)) { ++ ret = PTR_ERR(lynloong_backlight_dev); ++ return ret; ++ } ++ ++ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS; ++ backlight_update_status(lynloong_backlight_dev); ++ ++ return 0; ++} ++ ++static void lynloong_backlight_exit(void) ++{ ++ if (lynloong_backlight_dev) { ++ backlight_device_unregister(lynloong_backlight_dev); ++ lynloong_backlight_dev = NULL; ++ } ++ /* Disable brightness controlling */ ++ set_gpio_output_low(7); ++} ++ ++/* video output driver */ ++static int vo_status = 1; ++ ++static int lcd_video_output_get(struct output_device *od) ++{ ++ return vo_status; ++} ++ ++static int lcd_video_output_set(struct output_device *od) ++{ ++ int i; ++ unsigned long status; ++ ++ status = !!od->request_state; ++ ++ if (status == 0) { ++ /* Set the current status as off */ ++ vo_status = 0; ++ /* Turn off the backlight */ ++ set_gpio_output_low(11); ++ for (i = 0; i < 0x500; i++) ++ delay(); ++ /* Turn off the LCD */ ++ set_gpio_output_high(8); ++ } else { ++ /* Turn on the LCD */ ++ set_gpio_output_low(8); ++ for (i = 0; i < 0x500; i++) ++ delay(); ++ /* Turn on the backlight */ ++ set_gpio_output_high(11); ++ /* Set the current status as on */ ++ vo_status = 1; ++ } ++ ++ return 0; ++} ++ ++static struct output_properties lcd_output_properties = { ++ .set_state = lcd_video_output_set, ++ .get_status = lcd_video_output_get, ++}; ++ ++static struct output_device *lcd_output_dev; ++ ++static void lynloong_lcd_vo_set(int status) ++{ ++ lcd_output_dev->request_state = status; ++ lcd_video_output_set(lcd_output_dev); ++} ++ ++static int lynloong_vo_init(void) ++{ ++ int ret; ++ ++ /* Register video output device: lcd */ ++ lcd_output_dev = video_output_register("LCD", NULL, NULL, ++ &lcd_output_properties); ++ ++ if (IS_ERR(lcd_output_dev)) { ++ ret = PTR_ERR(lcd_output_dev); ++ lcd_output_dev = NULL; ++ return ret; ++ } ++ /* Ensure LCD is on by default */ ++ lynloong_lcd_vo_set(1); ++ ++ return 0; ++} ++ ++static void lynloong_vo_exit(void) ++{ ++ if (lcd_output_dev) { ++ video_output_unregister(lcd_output_dev); ++ lcd_output_dev = NULL; ++ } ++} ++ ++/* suspend support */ ++ ++#ifdef CONFIG_PM ++ ++static u32 smb_base; ++ ++/* I2C operations */ ++ ++static int i2c_wait(void) ++{ ++ char c; ++ int i; ++ ++ udelay(1000); ++ for (i = 0; i < 20; i++) { ++ c = inb(smb_base | SMB_STS); ++ if (c & (SMB_STS_BER | SMB_STS_NEGACK)) ++ return -1; ++ if (c & SMB_STS_SDAST) ++ return 0; ++ udelay(100); ++ } ++ return -2; ++} ++ ++static void i2c_read_single(int addr, int regNo, char *value) ++{ ++ unsigned char c; ++ ++ /* Start condition */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ ++ /* Send slave address */ ++ outb(addr & 0xfe, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Send register index */ ++ outb(regNo, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Start condition again */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ ++ /* Send salve address again */ ++ outb(1 | addr, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Read data */ ++ *value = inb(smb_base | SMB_SDA); ++ ++ /* Stop condition */ ++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); ++ i2c_wait(); ++} ++ ++static void i2c_write_single(int addr, int regNo, char value) ++{ ++ unsigned char c; ++ ++ /* Start condition */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ /* Send slave address */ ++ outb(addr & 0xfe, smb_base | SMB_SDA); ++ i2c_wait();; ++ ++ /* Send register index */ ++ outb(regNo, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Write data */ ++ outb(value, smb_base | SMB_SDA); ++ i2c_wait(); ++ /* Stop condition */ ++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); ++ i2c_wait(); ++} ++ ++static void stop_clock(int clk_reg, int clk_sel) ++{ ++ u8 value; ++ ++ i2c_read_single(0xd3, clk_reg, &value); ++ value &= ~(1 << clk_sel); ++ i2c_write_single(0xd2, clk_reg, value); ++} ++ ++static void enable_clock(int clk_reg, int clk_sel) ++{ ++ u8 value; ++ ++ i2c_read_single(0xd3, clk_reg, &value); ++ value |= (1 << clk_sel); ++ i2c_write_single(0xd2, clk_reg, value); ++} ++ ++static char cached_clk_freq; ++static char cached_pci_fixed_freq; ++ ++static void decrease_clk_freq(void) ++{ ++ char value; ++ ++ i2c_read_single(0xd3, 1, &value); ++ cached_clk_freq = value; ++ ++ /* Select frequency by software */ ++ value |= (1 << 1); ++ /* CPU, 3V66, PCI : 100, 66, 33(1) */ ++ value |= (1 << 2); ++ i2c_write_single(0xd2, 1, value); ++ ++ /* Cache the pci frequency */ ++ i2c_read_single(0xd3, 14, &value); ++ cached_pci_fixed_freq = value; ++ ++ /* Enable PCI fix mode */ ++ value |= (1 << 5); ++ /* 3V66, PCI : 64MHz, 32MHz */ ++ value |= (1 << 3); ++ i2c_write_single(0xd2, 14, value); ++ ++} ++ ++static void resume_clk_freq(void) ++{ ++ i2c_write_single(0xd2, 1, cached_clk_freq); ++ i2c_write_single(0xd2, 14, cached_pci_fixed_freq); ++} ++ ++static void stop_clocks(void) ++{ ++ /* CPU Clock Register */ ++ stop_clock(2, 5); /* not used */ ++ stop_clock(2, 6); /* not used */ ++ stop_clock(2, 7); /* not used */ ++ ++ /* PCI Clock Register */ ++ stop_clock(3, 1); /* 8100 */ ++ stop_clock(3, 5); /* SIS */ ++ stop_clock(3, 0); /* not used */ ++ stop_clock(3, 6); /* not used */ ++ ++ /* PCI 48M Clock Register */ ++ stop_clock(4, 6); /* USB grounding */ ++ stop_clock(4, 5); /* REF(5536_14M) */ ++ ++ /* 3V66 Control Register */ ++ stop_clock(5, 0); /* VCH_CLK..., grounding */ ++} ++ ++static void enable_clocks(void) ++{ ++ enable_clock(3, 1); /* 8100 */ ++ enable_clock(3, 5); /* SIS */ ++ ++ enable_clock(4, 6); ++ enable_clock(4, 5); /* REF(5536_14M) */ ++ ++ enable_clock(5, 0); /* VCH_CLOCK, grounding */ ++} ++ ++static int lynloong_suspend(struct device *dev) ++{ ++ /* Disable AMP */ ++ set_gpio_output_high(6); ++ /* Turn off LCD */ ++ lynloong_lcd_vo_set(0); ++ ++ /* Stop the clocks of some devices */ ++ stop_clocks(); ++ ++ /* Decrease the external clock frequency */ ++ decrease_clk_freq(); ++ ++ return 0; ++} ++ ++static int lynloong_resume(struct device *dev) ++{ ++ /* Turn on the LCD */ ++ lynloong_lcd_vo_set(1); ++ ++ /* Resume clock frequency, enable the relative clocks */ ++ resume_clk_freq(); ++ enable_clocks(); ++ ++ /* Enable AMP */ ++ set_gpio_output_low(6); ++ ++ return 0; ++} ++ ++static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend, ++ lynloong_resume); ++#endif /* !CONFIG_PM */ ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "lynloong_pc", ++ }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "lynloong_pc", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &lynloong_pm_ops, ++#endif ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int __init lynloong_init(void) ++{ ++ int ret; ++ ++ pr_info("LynLoong platform specific driver loaded.\n"); ++ ++ /* Register platform stuff */ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) { ++ pr_err("Failed to register LynLoong platform driver.\n"); ++ return ret; ++ } ++ ++ ret = lynloong_backlight_init(); ++ if (ret) { ++ pr_err("Failed to register LynLoong backlight driver.\n"); ++ return ret; ++ } ++ ++ ret = lynloong_vo_init(); ++ if (ret) { ++ pr_err("Failed to register LynLoong backlight driver.\n"); ++ lynloong_vo_exit(); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit lynloong_exit(void) ++{ ++ lynloong_vo_exit(); ++ lynloong_backlight_exit(); ++ platform_driver_unregister(&platform_driver); ++ ++ pr_info("LynLoong platform specific driver unloaded.\n"); ++} ++ ++module_init(lynloong_init); ++module_exit(lynloong_exit); ++ ++MODULE_AUTHOR("Wu Zhangjin ; Xiang Yu "); ++MODULE_DESCRIPTION("LynLoong PC driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/yeeloong_ecrom.c b/drivers/platform/mips/yeeloong_ecrom.c +new file mode 100644 +index 0000000..1bfe4cf +--- /dev/null ++++ b/drivers/platform/mips/yeeloong_ecrom.c +@@ -0,0 +1,944 @@ ++/* ++ * Driver for flushing/dumping ROM of EC on YeeLoong laptop ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: liujl ++ * ++ * NOTE : ++ * The EC resources accessing and programming are supported. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define EC_MISC_DEV "ec_misc" ++#define EC_IOC_MAGIC 'E' ++ ++/* ec registers range */ ++#define EC_MAX_REGADDR 0xFFFF ++#define EC_MIN_REGADDR 0xF000 ++#define EC_RAM_ADDR 0xF800 ++ ++/* version burned address */ ++#define VER_ADDR 0xf7a1 ++#define VER_MAX_SIZE 7 ++#define EC_ROM_MAX_SIZE 0x10000 ++ ++/* ec internal register */ ++#define REG_POWER_MODE 0xF710 ++#define FLAG_NORMAL_MODE 0x00 ++#define FLAG_IDLE_MODE 0x01 ++#define FLAG_RESET_MODE 0x02 ++ ++/* ec update program flag */ ++#define PROGRAM_FLAG_NONE 0x00 ++#define PROGRAM_FLAG_IE 0x01 ++#define PROGRAM_FLAG_ROM 0x02 ++ ++/* XBI relative registers */ ++#define REG_XBISEG0 0xFEA0 ++#define REG_XBISEG1 0xFEA1 ++#define REG_XBIRSV2 0xFEA2 ++#define REG_XBIRSV3 0xFEA3 ++#define REG_XBIRSV4 0xFEA4 ++#define REG_XBICFG 0xFEA5 ++#define REG_XBICS 0xFEA6 ++#define REG_XBIWE 0xFEA7 ++#define REG_XBISPIA0 0xFEA8 ++#define REG_XBISPIA1 0xFEA9 ++#define REG_XBISPIA2 0xFEAA ++#define REG_XBISPIDAT 0xFEAB ++#define REG_XBISPICMD 0xFEAC ++#define REG_XBISPICFG 0xFEAD ++#define REG_XBISPIDATR 0xFEAE ++#define REG_XBISPICFG2 0xFEAF ++ ++/* commands definition for REG_XBISPICMD */ ++#define SPICMD_WRITE_STATUS 0x01 ++#define SPICMD_BYTE_PROGRAM 0x02 ++#define SPICMD_READ_BYTE 0x03 ++#define SPICMD_WRITE_DISABLE 0x04 ++#define SPICMD_READ_STATUS 0x05 ++#define SPICMD_WRITE_ENABLE 0x06 ++#define SPICMD_HIGH_SPEED_READ 0x0B ++#define SPICMD_POWER_DOWN 0xB9 ++#define SPICMD_SST_EWSR 0x50 ++#define SPICMD_SST_SEC_ERASE 0x20 ++#define SPICMD_SST_BLK_ERASE 0x52 ++#define SPICMD_SST_CHIP_ERASE 0x60 ++#define SPICMD_FRDO 0x3B ++#define SPICMD_SEC_ERASE 0xD7 ++#define SPICMD_BLK_ERASE 0xD8 ++#define SPICMD_CHIP_ERASE 0xC7 ++ ++/* bits definition for REG_XBISPICFG */ ++#define SPICFG_AUTO_CHECK 0x01 ++#define SPICFG_SPI_BUSY 0x02 ++#define SPICFG_DUMMY_READ 0x04 ++#define SPICFG_EN_SPICMD 0x08 ++#define SPICFG_LOW_SPICS 0x10 ++#define SPICFG_EN_SHORT_READ 0x20 ++#define SPICFG_EN_OFFSET_READ 0x40 ++#define SPICFG_EN_FAST_READ 0x80 ++ ++/* watchdog timer registers */ ++#define REG_WDTCFG 0xfe80 ++#define REG_WDTPF 0xfe81 ++#define REG_WDT 0xfe82 ++ ++/* lpc configure register */ ++#define REG_LPCCFG 0xfe95 ++ ++/* 8051 reg */ ++#define REG_PXCFG 0xff14 ++ ++/* Fan register in KB3310 */ ++#define REG_ECFAN_SPEED_LEVEL 0xf4e4 ++#define REG_ECFAN_SWITCH 0xf4d2 ++ ++/* the ec flash rom id number */ ++#define EC_ROM_PRODUCT_ID_SPANSION 0x01 ++#define EC_ROM_PRODUCT_ID_MXIC 0xC2 ++#define EC_ROM_PRODUCT_ID_AMIC 0x37 ++#define EC_ROM_PRODUCT_ID_EONIC 0x1C ++ ++/* misc ioctl operations */ ++#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int) ++#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int) ++#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int) ++#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int) ++#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int) ++ ++/* start address for programming of EC content or IE */ ++/* ec running code start address */ ++#define EC_START_ADDR 0x00000000 ++/* ec information element storing address */ ++#define IE_START_ADDR 0x00020000 ++ ++/* EC state */ ++#define EC_STATE_IDLE 0x00 /* ec in idle state */ ++#define EC_STATE_BUSY 0x01 /* ec in busy state */ ++ ++/* timeout value for programming */ ++#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */ ++/* command checkout timeout including cmd to port or state flag check */ ++#define EC_CMD_TIMEOUT 0x1000 ++#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */ ++#define EC_MAX_DELAY_UNIT (10) /* every time for polling */ ++#define SPI_FINISH_WAIT_TIME 10 ++/* EC content max size */ ++#define EC_CONTENT_MAX_SIZE (64 * 1024) ++#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR) ++ ++/* the register operation access struct */ ++struct ec_reg { ++ u32 addr; /* the address of kb3310 registers */ ++ u8 val; /* the register value */ ++}; ++ ++struct ec_info { ++ u32 start_addr; ++ u32 size; ++ u8 *buf; ++}; ++ ++/* open for using rom protection action */ ++#define EC_ROM_PROTECTION ++ ++/* enable the chip reset mode */ ++static int ec_init_reset_mode(void) ++{ ++ int timeout; ++ unsigned char status = 0; ++ int ret = 0; ++ ++ /* make chip goto reset mode */ ++ ret = ec_query_seq(CMD_INIT_RESET_MODE); ++ if (ret < 0) { ++ printk(KERN_ERR "ec init reset mode failed.\n"); ++ goto out; ++ } ++ ++ /* make the action take active */ ++ timeout = EC_CMD_TIMEOUT; ++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; ++ while (timeout--) { ++ if (status) { ++ udelay(EC_REG_DELAY); ++ break; ++ } ++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; ++ udelay(EC_REG_DELAY); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR "ec rom fixup : can't check reset status.\n"); ++ ret = -EINVAL; ++ } else ++ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout, ++ EC_CMD_TIMEOUT - timeout, status); ++ ++ /* set MCU to reset mode */ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_PXCFG); ++ status |= (1 << 0); ++ ec_write(REG_PXCFG, status); ++ udelay(EC_REG_DELAY); ++ ++ /* disable FWH/LPC */ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_LPCCFG); ++ status &= ~(1 << 7); ++ ec_write(REG_LPCCFG, status); ++ udelay(EC_REG_DELAY); ++ ++ printk(KERN_INFO "entering reset mode ok..............\n"); ++ ++ out: ++ return ret; ++} ++ ++/* make ec exit from reset mode */ ++static void ec_exit_reset_mode(void) ++{ ++ unsigned char regval; ++ ++ udelay(EC_REG_DELAY); ++ regval = ec_read(REG_LPCCFG); ++ regval |= (1 << 7); ++ ec_write(REG_LPCCFG, regval); ++ regval = ec_read(REG_PXCFG); ++ regval &= ~(1 << 0); ++ ec_write(REG_PXCFG, regval); ++ printk(KERN_INFO "exit reset mode ok..................\n"); ++ ++ return; ++} ++ ++/* make ec disable WDD */ ++static void ec_disable_WDD(void) ++{ ++ unsigned char status; ++ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_WDTCFG); ++ ec_write(REG_WDTPF, 0x03); ++ ec_write(REG_WDTCFG, (status & 0x80) | 0x48); ++ printk(KERN_INFO "Disable WDD ok..................\n"); ++ ++ return; ++} ++ ++/* make ec enable WDD */ ++static void ec_enable_WDD(void) ++{ ++ unsigned char status; ++ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_WDTCFG); ++ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */ ++ ec_write(REG_WDTCFG, (status & 0x80) | 0x03); ++ printk(KERN_INFO "Enable WDD ok..................\n"); ++ ++ return; ++} ++ ++/* make ec goto idle mode */ ++static int ec_init_idle_mode(void) ++{ ++ int timeout; ++ unsigned char status = 0; ++ int ret = 0; ++ ++ ec_query_seq(CMD_INIT_IDLE_MODE); ++ ++ /* make the action take active */ ++ timeout = EC_CMD_TIMEOUT; ++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; ++ while (timeout--) { ++ if (status) { ++ udelay(EC_REG_DELAY); ++ break; ++ } ++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; ++ udelay(EC_REG_DELAY); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR "ec rom fixup : can't check out the status.\n"); ++ ret = -EINVAL; ++ } else ++ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout, ++ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE)); ++ ++ printk(KERN_INFO "entering idle mode ok...................\n"); ++ ++ return ret; ++} ++ ++/* make ec exit from idle mode */ ++static int ec_exit_idle_mode(void) ++{ ++ ++ ec_query_seq(CMD_EXIT_IDLE_MODE); ++ ++ printk(KERN_INFO "exit idle mode ok...................\n"); ++ ++ return 0; ++} ++ ++static int ec_instruction_cycle(void) ++{ ++ unsigned long timeout; ++ int ret = 0; ++ ++ timeout = EC_FLASH_TIMEOUT; ++ while (timeout-- >= 0) { ++ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY)) ++ break; ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ return ret; ++} ++ ++/* To see if the ec is in busy state or not. */ ++static inline int ec_flash_busy(unsigned long timeout) ++{ ++ /* assurance the first command be going to rom */ ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++#if 1 ++ timeout = timeout / EC_MAX_DELAY_UNIT; ++ while (timeout-- > 0) { ++ /* check the rom's status of busy flag */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) ++ return EC_STATE_IDLE; ++ udelay(EC_MAX_DELAY_UNIT); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_FLASH_BUSY : timeout for check rom flag.\n"); ++ return EC_STATE_BUSY; ++ } ++#else ++ /* check the rom's status of busy flag */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++ ++ timeout = timeout / EC_MAX_DELAY_UNIT; ++ while (timeout-- > 0) { ++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) ++ return EC_STATE_IDLE; ++ udelay(EC_MAX_DELAY_UNIT); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_FLASH_BUSY : timeout for check rom flag.\n"); ++ return EC_STATE_BUSY; ++ } ++#endif ++ ++ return EC_STATE_IDLE; ++} ++ ++static int rom_instruction_cycle(unsigned char cmd) ++{ ++ unsigned long timeout = 0; ++ ++ switch (cmd) { ++ case SPICMD_READ_STATUS: ++ case SPICMD_WRITE_ENABLE: ++ case SPICMD_WRITE_DISABLE: ++ case SPICMD_READ_BYTE: ++ case SPICMD_HIGH_SPEED_READ: ++ timeout = 0; ++ break; ++ case SPICMD_WRITE_STATUS: ++ timeout = 300 * 1000; ++ break; ++ case SPICMD_BYTE_PROGRAM: ++ timeout = 5 * 1000; ++ break; ++ case SPICMD_SST_SEC_ERASE: ++ case SPICMD_SEC_ERASE: ++ timeout = 1000 * 1000; ++ break; ++ case SPICMD_SST_BLK_ERASE: ++ case SPICMD_BLK_ERASE: ++ timeout = 3 * 1000 * 1000; ++ break; ++ case SPICMD_SST_CHIP_ERASE: ++ case SPICMD_CHIP_ERASE: ++ timeout = 20 * 1000 * 1000; ++ break; ++ default: ++ timeout = EC_SPICMD_STANDARD_TIMEOUT; ++ } ++ if (timeout == 0) ++ return ec_instruction_cycle(); ++ if (timeout < EC_SPICMD_STANDARD_TIMEOUT) ++ timeout = EC_SPICMD_STANDARD_TIMEOUT; ++ ++ return ec_flash_busy(timeout); ++} ++ ++/* delay for start/stop action */ ++static void delay_spi(int n) ++{ ++ while (n--) ++ inb(EC_IO_PORT_HIGH); ++} ++ ++/* start the action to spi rom function */ ++static void ec_start_spi(void) ++{ ++ unsigned char val; ++ ++ delay_spi(SPI_FINISH_WAIT_TIME); ++ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK; ++ ec_write(REG_XBISPICFG, val); ++ delay_spi(SPI_FINISH_WAIT_TIME); ++} ++ ++/* stop the action to spi rom function */ ++static void ec_stop_spi(void) ++{ ++ unsigned char val; ++ ++ delay_spi(SPI_FINISH_WAIT_TIME); ++ val = ++ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK)); ++ ec_write(REG_XBISPICFG, val); ++ delay_spi(SPI_FINISH_WAIT_TIME); ++} ++ ++/* read one byte from xbi interface */ ++static int ec_read_byte(unsigned int addr, unsigned char *byte) ++{ ++ int ret = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* write the address */ ++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); ++ /* start action */ ++ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ); ++ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ *byte = ec_read(REG_XBISPIDAT); ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* write one byte to ec rom */ ++static int ec_write_byte(unsigned int addr, unsigned char byte) ++{ ++ int ret = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* write the address */ ++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); ++ ec_write(REG_XBISPIDAT, byte); ++ /* start action */ ++ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM); ++ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* unprotect SPI ROM */ ++/* EC_ROM_unprotect function code */ ++static int EC_ROM_unprotect(void) ++{ ++ unsigned char status; ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); ++ return 1; ++ } ++ ++ /* unprotect the status register of rom */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n"); ++ return 1; ++ } ++ status = ec_read(REG_XBISPIDAT); ++ ec_write(REG_XBISPIDAT, status & 0x02); ++ if (ec_instruction_cycle() < 0) { ++ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n"); ++ return 1; ++ } ++ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); ++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n"); ++ return 1; ++ } ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* erase one block or chip or sector as needed */ ++static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr) ++{ ++ unsigned char status; ++ int ret = 0, i = 0; ++ int unprotect_count = 3; ++ int check_flag = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++#ifdef EC_ROM_PROTECTION ++ /* added for re-check SPICMD_READ_STATUS */ ++ while (unprotect_count-- > 0) { ++ if (EC_ROM_unprotect()) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* first time:500ms --> 5.5sec -->10.5sec */ ++ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++) ++ udelay(50000); ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) ++ == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); ++ } else { ++ status = ec_read(REG_XBISPIDAT); ++ printk(KERN_INFO "Read unprotect status : 0x%x\n", ++ status); ++ if ((status & 0x1C) == 0x00) { ++ printk(KERN_INFO ++ "Read unprotect status OK1 : 0x%x\n", ++ status & 0x1C); ++ check_flag = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!check_flag) { ++ printk(KERN_INFO "SPI ROM unprotect fail.\n"); ++ return 1; ++ } ++#endif ++ ++ /* block address fill */ ++ if (erase_cmd == SPICMD_BLK_ERASE) { ++ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0); ++ } ++ ++ /* erase the whole chip first */ ++ ec_write(REG_XBISPICMD, erase_cmd); ++ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* update the whole rom content with H/W mode ++ * PLEASE USING ec_unit_erase() FIRSTLY ++ */ ++static int ec_program_rom(struct ec_info *info, int flag) ++{ ++ unsigned int addr = 0; ++ unsigned long size = 0; ++ unsigned char *ptr = NULL; ++ unsigned char data; ++ unsigned char val = 0; ++ int ret = 0; ++ int i, j; ++ unsigned char status; ++ ++ /* modify for program serial No. ++ * set IE_START_ADDR & use idle mode, ++ * disable WDD ++ */ ++ if (flag == PROGRAM_FLAG_ROM) { ++ ret = ec_init_reset_mode(); ++ addr = info->start_addr + EC_START_ADDR; ++ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n"); ++ } else if (flag == PROGRAM_FLAG_IE) { ++ ret = ec_init_idle_mode(); ++ ec_disable_WDD(); ++ addr = info->start_addr + IE_START_ADDR; ++ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n"); ++ } else { ++ return 0; ++ } ++ ++ if (ret < 0) { ++ if (flag == PROGRAM_FLAG_IE) ++ ec_enable_WDD(); ++ return ret; ++ } ++ ++ size = info->size; ++ ptr = info->buf; ++ printk(KERN_INFO "starting update ec ROM..............\n"); ++ ++ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr); ++ if (ret) { ++ printk(KERN_ERR "program ec : erase block failed.\n"); ++ goto out; ++ } ++ printk(KERN_ERR "program ec : erase block OK.\n"); ++ ++ i = 0; ++ while (i < size) { ++ data = *(ptr + i); ++ ec_write_byte(addr, data); ++ ec_read_byte(addr, &val); ++ if (val != data) { ++ ec_write_byte(addr, data); ++ ec_read_byte(addr, &val); ++ if (val != data) { ++ printk(KERN_INFO ++ "EC : Second flash program failed at:\t"); ++ printk(KERN_INFO ++ "addr : 0x%x, source : 0x%x, dest: 0x%x\n", ++ addr, data, val); ++ printk(KERN_INFO "This should not happen... STOP\n"); ++ break; ++ } ++ } ++ i++; ++ addr++; ++ } ++ ++#ifdef EC_ROM_PROTECTION ++ /* we should start spi access firstly */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n"); ++ goto out1; ++ } ++ ++ /* protect the status register of rom */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); ++ goto out1; ++ } ++ status = ec_read(REG_XBISPIDAT); ++ ++ ec_write(REG_XBISPIDAT, status | 0x1C); ++ if (ec_instruction_cycle() < 0) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : write status value failed.\n"); ++ goto out1; ++ } ++ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); ++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n"); ++ goto out1; ++ } ++#endif ++ ++ /* disable the write action to spi rom */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n"); ++ goto out1; ++ } ++ ++ out1: ++ /* we should stop spi access firstly */ ++ ec_stop_spi(); ++ out: ++ /* for security */ ++ for (j = 0; j < 2000; j++) ++ udelay(1000); ++ ++ /* modify for program serial No. ++ * after program No exit idle mode ++ * and enable WDD ++ */ ++ if (flag == PROGRAM_FLAG_ROM) { ++ /* exit from the reset mode */ ++ ec_exit_reset_mode(); ++ } else { ++ /* ec exit from idle mode */ ++ ret = ec_exit_idle_mode(); ++ ec_enable_WDD(); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* ioctl */ ++static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd, ++ u_long arg) ++{ ++ struct ec_info ecinfo; ++ void __user *ptr = (void __user *)arg; ++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); ++ int ret = 0; ++ ++ switch (cmd) { ++ case IOCTL_RDREG: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg read : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_MAX_REGADDR) ++ || (ecreg->addr < EC_MIN_REGADDR)) { ++ printk(KERN_ERR ++ "reg read : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ecreg->val = ec_read(ecreg->addr); ++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg read : copy to user error.\n"); ++ return -EFAULT; ++ } ++ break; ++ case IOCTL_WRREG: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg write : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_MAX_REGADDR) ++ || (ecreg->addr < EC_MIN_REGADDR)) { ++ printk(KERN_ERR ++ "reg write : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ec_write(ecreg->addr, ecreg->val); ++ break; ++ case IOCTL_READ_EC: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "spi read : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_RAM_ADDR) ++ && (ecreg->addr < EC_MAX_REGADDR)) { ++ printk(KERN_ERR ++ "spi read : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ec_read_byte(ecreg->addr, &(ecreg->val)); ++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "spi read : copy to user error.\n"); ++ return -EFAULT; ++ } ++ break; ++ case IOCTL_PROGRAM_IE: ++ ecinfo.start_addr = EC_START_ADDR; ++ ecinfo.size = EC_CONTENT_MAX_SIZE; ++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); ++ if (ecinfo.buf == NULL) { ++ printk(KERN_ERR "program ie : kmalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size); ++ if (ret) { ++ printk(KERN_ERR "program ie : copy from user error.\n"); ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ return -EFAULT; ++ } ++ ++ /* use ec_program_rom to write serial No */ ++ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE); ++ ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ break; ++ case IOCTL_PROGRAM_EC: ++ ecinfo.start_addr = EC_START_ADDR; ++ if (get_user((ecinfo.size), (u32 *) ptr)) { ++ printk(KERN_ERR "program ec : get user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) { ++ printk(KERN_ERR "program ec : size out of limited.\n"); ++ return -EINVAL; ++ } ++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); ++ if (ecinfo.buf == NULL) { ++ printk(KERN_ERR "program ec : kmalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size); ++ if (ret) { ++ printk(KERN_ERR "program ec : copy from user error.\n"); ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ return -EFAULT; ++ } ++ ++ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM); ++ ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static long misc_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg); ++} ++ ++static int misc_open(struct inode *inode, struct file *filp) ++{ ++ struct ec_reg *ecreg = NULL; ++ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL); ++ if (ecreg) ++ filp->private_data = ecreg; ++ ++ return ecreg ? 0 : -ENOMEM; ++} ++ ++static int misc_release(struct inode *inode, struct file *filp) ++{ ++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); ++ ++ filp->private_data = NULL; ++ kfree(ecreg); ++ ++ return 0; ++} ++ ++static const struct file_operations ecmisc_fops = { ++ .open = misc_open, ++ .release = misc_release, ++ .read = NULL, ++ .write = NULL, ++#ifdef CONFIG_64BIT ++ .compat_ioctl = misc_compat_ioctl, ++#else ++ .ioctl = misc_ioctl, ++#endif ++}; ++ ++static struct miscdevice ecmisc_device = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = EC_MISC_DEV, ++ .fops = &ecmisc_fops ++}; ++ ++static int __init ecmisc_init(void) ++{ ++ int ret; ++ ++ printk(KERN_INFO "EC misc device init.\n"); ++ ret = misc_register(&ecmisc_device); ++ ++ return ret; ++} ++ ++static void __exit ecmisc_exit(void) ++{ ++ printk(KERN_INFO "EC misc device exit.\n"); ++ misc_deregister(&ecmisc_device); ++} ++ ++module_init(ecmisc_init); ++module_exit(ecmisc_exit); ++ ++MODULE_AUTHOR("liujl "); ++MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c +new file mode 100644 +index 0000000..32a2bdb +--- /dev/null ++++ b/drivers/platform/mips/yeeloong_laptop.c +@@ -0,0 +1,1360 @@ ++/* ++ * Driver for YeeLoong laptop extras ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin , Liu Junliang ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include /* for backlight subdriver */ ++#include ++#include /* for hwmon subdriver */ ++#include ++#include /* for video output subdriver */ ++#include /* for lcd output subdriver */ ++#include /* for hotkey subdriver */ ++#include ++#include ++#include ++#include /* for AC & Battery subdriver */ ++#include /* for register_reboot_notifier */ ++#include /* for register_pm_notifier */ ++ ++#include ++ ++#include /* for loongson_cmdline */ ++#include ++ ++#define ON 1 ++#define OFF 0 ++#define EVENT_START EVENT_LID ++ ++/* common function */ ++#define EC_VER_LEN 64 ++ ++static int ec_version_before(char *version) ++{ ++ char *p, ec_ver[EC_VER_LEN]; ++ ++ p = strstr(loongson_cmdline, "EC_VER="); ++ if (!p) ++ memset(ec_ver, 0, EC_VER_LEN); ++ else { ++ strncpy(ec_ver, p, EC_VER_LEN); ++ p = strstr(ec_ver, " "); ++ if (p) ++ *p = '\0'; ++ } ++ ++ return (strncasecmp(ec_ver, version, 64) < 0); ++} ++ ++/* backlight subdriver */ ++#define MIN_BRIGHTNESS 1 ++#define MAX_BRIGHTNESS 8 ++ ++static int yeeloong_set_brightness(struct backlight_device *bd) ++{ ++ unsigned char level; ++ static unsigned char old_level; ++ ++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && ++ bd->props.power == FB_BLANK_UNBLANK) ? ++ bd->props.brightness : 0; ++ ++ level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS); ++ ++ /* Avoid to modify the brightness when EC is tuning it */ ++ if (old_level != level) { ++ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level) ++ ec_write(REG_DISPLAY_BRIGHTNESS, level); ++ old_level = level; ++ } ++ ++ return 0; ++} ++ ++static int yeeloong_get_brightness(struct backlight_device *bd) ++{ ++ return ec_read(REG_DISPLAY_BRIGHTNESS); ++} ++ ++static struct backlight_ops backlight_ops = { ++ .get_brightness = yeeloong_get_brightness, ++ .update_status = yeeloong_set_brightness, ++}; ++ ++static struct backlight_device *yeeloong_backlight_dev; ++ ++static int yeeloong_backlight_init(void) ++{ ++ int ret; ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.max_brightness = MAX_BRIGHTNESS; ++ props.type = BACKLIGHT_PLATFORM; ++ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL, ++ NULL, &backlight_ops, &props); ++ ++ if (IS_ERR(yeeloong_backlight_dev)) { ++ ret = PTR_ERR(yeeloong_backlight_dev); ++ yeeloong_backlight_dev = NULL; ++ return ret; ++ } ++ ++ yeeloong_backlight_dev->props.brightness = ++ yeeloong_get_brightness(yeeloong_backlight_dev); ++ backlight_update_status(yeeloong_backlight_dev); ++ ++ return 0; ++} ++ ++static void yeeloong_backlight_exit(void) ++{ ++ if (yeeloong_backlight_dev) { ++ backlight_device_unregister(yeeloong_backlight_dev); ++ yeeloong_backlight_dev = NULL; ++ } ++} ++ ++/* AC & Battery subdriver */ ++ ++static struct power_supply yeeloong_ac, yeeloong_bat; ++ ++#define RET (val->intval) ++ ++#define BAT_CAP_CRITICAL 5 ++#define BAT_CAP_HIGH 95 ++ ++#define get_bat(type) \ ++ ec_read(REG_BAT_##type) ++ ++#define get_bat_l(type) \ ++ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW)) ++ ++static int yeeloong_get_ac_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ if (psp == POWER_SUPPLY_PROP_ONLINE) ++ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN); ++ ++ return 0; ++} ++ ++static enum power_supply_property yeeloong_ac_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++}; ++ ++static struct power_supply yeeloong_ac = { ++ .name = "yeeloong-ac", ++ .type = POWER_SUPPLY_TYPE_MAINS, ++ .properties = yeeloong_ac_props, ++ .num_properties = ARRAY_SIZE(yeeloong_ac_props), ++ .get_property = yeeloong_get_ac_props, ++}; ++ ++static inline bool is_bat_in(void) ++{ ++ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN); ++} ++ ++static int get_bat_temp(void) ++{ ++ return get_bat_l(TEMPERATURE) * 10; ++} ++ ++static int get_bat_current(void) ++{ ++ return -(s16)get_bat_l(CURRENT); ++} ++ ++static int get_bat_voltage(void) ++{ ++ return get_bat_l(VOLTAGE); ++} ++ ++static char *get_manufacturer(void) ++{ ++ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO"; ++} ++ ++static int get_relative_cap(void) ++{ ++ /* ++ * When the relative capacity becomes 2, the hardware is observed to ++ * have been turned off forcely. so, we must tune it be suitable to ++ * make the software do related actions. ++ */ ++ int tmp = get_bat_l(RELATIVE_CAP); ++ ++ if (tmp <= (BAT_CAP_CRITICAL * 2)) ++ tmp -= 3; ++ ++ return tmp; ++} ++ ++static int yeeloong_get_bat_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ switch (psp) { ++ /* Fixed information */ ++ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: ++ /* mV -> µV */ ++ RET = get_bat_l(DESIGN_VOL) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ++ /* mAh->µAh */ ++ RET = get_bat_l(DESIGN_CAP) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ /* µAh */ ++ RET = get_bat_l(FULLCHG_CAP) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_MANUFACTURER: ++ val->strval = get_manufacturer(); ++ break; ++ /* Dynamic information */ ++ case POWER_SUPPLY_PROP_PRESENT: ++ RET = is_bat_in(); ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ /* mA -> µA */ ++ RET = is_bat_in() ? get_bat_current() * 1000 : 0; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ /* mV -> µV */ ++ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0; ++ break; ++ case POWER_SUPPLY_PROP_TEMP: ++ /* Celcius */ ++ RET = is_bat_in() ? get_bat_temp() : 0; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY: ++ RET = is_bat_in() ? get_relative_cap() : 0; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: { ++ int status; ++ ++ if (!is_bat_in()) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ break; ++ } ++ ++ status = get_bat(STATUS); ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; ++ ++ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ break; ++ } ++ ++ if (status & BIT_BAT_STATUS_FULL) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; ++ else { ++ int curr_cap = get_relative_cap(); ++ ++ if (status & BIT_BAT_STATUS_LOW) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; ++ if (curr_cap <= BAT_CAP_CRITICAL) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; ++ } else if (curr_cap >= BAT_CAP_HIGH) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; ++ } ++ } break; ++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ++ /* seconds */ ++ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0; ++ break; ++ case POWER_SUPPLY_PROP_STATUS: { ++ int charge = get_bat(CHARGE); ++ ++ RET = POWER_SUPPLY_STATUS_UNKNOWN; ++ if (charge & FLAG_BAT_CHARGE_DISCHARGE) ++ RET = POWER_SUPPLY_STATUS_DISCHARGING; ++ else if (charge & FLAG_BAT_CHARGE_CHARGE) ++ RET = POWER_SUPPLY_STATUS_CHARGING; ++ } break; ++ case POWER_SUPPLY_PROP_HEALTH: { ++ int status; ++ ++ if (!is_bat_in()) { ++ RET = POWER_SUPPLY_HEALTH_UNKNOWN; ++ break; ++ } ++ ++ status = get_bat(STATUS); ++ RET = POWER_SUPPLY_HEALTH_GOOD; ++ ++ if (status & (BIT_BAT_STATUS_DESTROY | ++ BIT_BAT_STATUS_LOW)) ++ RET = POWER_SUPPLY_HEALTH_DEAD; ++ if (get_bat(CHARGE_STATUS) & ++ BIT_BAT_CHARGE_STATUS_OVERTEMP) ++ RET = POWER_SUPPLY_HEALTH_OVERHEAT; ++ } break; ++ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */ ++ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10; ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++#undef RET ++ ++static enum power_supply_property yeeloong_bat_props[] = { ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL, ++ POWER_SUPPLY_PROP_CHARGE_NOW, ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_HEALTH, ++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_CAPACITY_LEVEL, ++ POWER_SUPPLY_PROP_TEMP, ++ POWER_SUPPLY_PROP_MANUFACTURER, ++}; ++ ++static struct power_supply yeeloong_bat = { ++ .name = "yeeloong-bat", ++ .type = POWER_SUPPLY_TYPE_BATTERY, ++ .properties = yeeloong_bat_props, ++ .num_properties = ARRAY_SIZE(yeeloong_bat_props), ++ .get_property = yeeloong_get_bat_props, ++}; ++ ++static int ac_bat_initialized; ++ ++static int yeeloong_bat_init(void) ++{ ++ int ret; ++ ++ ret = power_supply_register(NULL, &yeeloong_ac); ++ if (ret) ++ return ret; ++ ret = power_supply_register(NULL, &yeeloong_bat); ++ if (ret) { ++ power_supply_unregister(&yeeloong_ac); ++ return ret; ++ } ++ ac_bat_initialized = 1; ++ ++ return 0; ++} ++ ++static void yeeloong_bat_exit(void) ++{ ++ ac_bat_initialized = 0; ++ ++ power_supply_unregister(&yeeloong_ac); ++ power_supply_unregister(&yeeloong_bat); ++} ++/* hwmon subdriver */ ++ ++#define MIN_FAN_SPEED 0 ++#define MAX_FAN_SPEED 3 ++ ++#define get_fan(type) \ ++ ec_read(REG_FAN_##type) ++ ++#define set_fan(type, val) \ ++ ec_write(REG_FAN_##type, val) ++ ++static inline int get_fan_speed_level(void) ++{ ++ return get_fan(SPEED_LEVEL); ++} ++static inline void set_fan_speed_level(int speed) ++{ ++ set_fan(SPEED_LEVEL, speed); ++} ++ ++static inline int get_fan_mode(void) ++{ ++ return get_fan(AUTO_MAN_SWITCH); ++} ++static inline void set_fan_mode(int mode) ++{ ++ set_fan(AUTO_MAN_SWITCH, mode); ++} ++ ++/* ++ * 3 different modes: Full speed(0); manual mode(1); auto mode(2) ++ */ ++static int get_fan_pwm_enable(void) ++{ ++ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 : ++ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1; ++} ++ ++static void set_fan_pwm_enable(int mode) ++{ ++ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL); ++ if (mode == 0) ++ set_fan_speed_level(MAX_FAN_SPEED); ++} ++ ++static int get_fan_pwm(void) ++{ ++ return get_fan_speed_level(); ++} ++ ++static void set_fan_pwm(int value) ++{ ++ if (get_fan_mode() != BIT_FAN_MANUAL) ++ return; ++ ++ value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED); ++ ++ /* We must ensure the fan is on */ ++ if (value > 0) ++ set_fan(CONTROL, ON); ++ ++ set_fan_speed_level(value); ++} ++ ++static inline int get_fan_speed(void) ++{ ++ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW); ++} ++ ++static int get_fan_rpm(void) ++{ ++ return FAN_SPEED_DIVIDER / get_fan_speed(); ++} ++ ++static int get_cpu_temp(void) ++{ ++ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000; ++} ++ ++static int get_cpu_temp_max(void) ++{ ++ return 60 * 1000; ++} ++ ++static int get_bat_temp_alarm(void) ++{ ++ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP); ++} ++ ++static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long value; ++ ++ if (!count) ++ return 0; ++ ++ ret = kstrtoul(buf, 10, &value); ++ if (ret) ++ return ret; ++ ++ set(value); ++ ++ return count; ++} ++ ++static ssize_t show_sys_hwmon(int (*get) (void), char *buf) ++{ ++ return sprintf(buf, "%d\n", get()); ++} ++ ++#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ ++ static ssize_t show_##_name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++ { \ ++ return show_sys_hwmon(_set, buf); \ ++ } \ ++ static ssize_t store_##_name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ return store_sys_hwmon(_get, buf, count); \ ++ } \ ++ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); ++ ++CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL); ++CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm); ++CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable, ++ set_fan_pwm_enable); ++CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL); ++CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL); ++CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL); ++CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL); ++CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL); ++CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL); ++ ++static ssize_t ++show_name(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "yeeloong\n"); ++} ++ ++static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); ++ ++static struct attribute *hwmon_attributes[] = { ++ &sensor_dev_attr_pwm1.dev_attr.attr, ++ &sensor_dev_attr_pwm1_enable.dev_attr.attr, ++ &sensor_dev_attr_fan1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_max.dev_attr.attr, ++ &sensor_dev_attr_temp2_input.dev_attr.attr, ++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, ++ &sensor_dev_attr_curr1_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_name.dev_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group hwmon_attribute_group = { ++ .attrs = hwmon_attributes ++}; ++ ++static struct device *yeeloong_hwmon_dev; ++ ++static int yeeloong_hwmon_init(void) ++{ ++ int ret; ++ ++ yeeloong_hwmon_dev = hwmon_device_register(NULL); ++ if (IS_ERR(yeeloong_hwmon_dev)) { ++ yeeloong_hwmon_dev = NULL; ++ return PTR_ERR(yeeloong_hwmon_dev); ++ } ++ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj, ++ &hwmon_attribute_group); ++ if (ret) { ++ hwmon_device_unregister(yeeloong_hwmon_dev); ++ yeeloong_hwmon_dev = NULL; ++ return ret; ++ } ++ /* ensure fan is set to auto mode */ ++ set_fan_pwm_enable(2); ++ ++ return 0; ++} ++ ++static void yeeloong_hwmon_exit(void) ++{ ++ if (yeeloong_hwmon_dev) { ++ sysfs_remove_group(&yeeloong_hwmon_dev->kobj, ++ &hwmon_attribute_group); ++ hwmon_device_unregister(yeeloong_hwmon_dev); ++ yeeloong_hwmon_dev = NULL; ++ } ++} ++ ++/* video output subdriver */ ++ ++#define LCD 0 ++#define CRT 1 ++#define VOD_NUM 2 /* The total number of video output device*/ ++ ++static struct output_device *vod[VOD_NUM]; ++ ++static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT}; ++ ++static int get_vo_dev(struct output_device *od) ++{ ++ int i, dev; ++ ++ dev = -1; ++ for (i = 0; i < VOD_NUM; i++) ++ if (od == vod[i]) ++ dev = i; ++ ++ return dev; ++} ++ ++static int vo_get_status(int dev) ++{ ++ return ec_read(vor[dev]); ++} ++ ++static int yeeloong_vo_get_status(struct output_device *od) ++{ ++ int vd; ++ ++ vd = get_vo_dev(od); ++ if (vd != -1) ++ return vo_get_status(vd); ++ ++ return -ENODEV; ++} ++ ++static void vo_set_state(int dev, int state) ++{ ++ int addr; ++ unsigned long value; ++ ++ switch (dev) { ++ case LCD: ++ addr = 0x31; ++ break; ++ case CRT: ++ addr = 0x21; ++ break; ++ default: ++ /* return directly if the wrong video output device */ ++ return; ++ } ++ ++ outb(addr, 0x3c4); ++ value = inb(0x3c5); ++ ++ switch (dev) { ++ case LCD: ++ value |= (state ? 0x03 : 0x02); ++ break; ++ case CRT: ++ if (state) ++ clear_bit(7, &value); ++ else ++ set_bit(7, &value); ++ break; ++ default: ++ break; ++ } ++ ++ outb(addr, 0x3c4); ++ outb(value, 0x3c5); ++ ++ if (dev == LCD) ++ ec_write(REG_BACKLIGHT_CTRL, state); ++} ++ ++static int yeeloong_vo_set_state(struct output_device *od) ++{ ++ int vd; ++ ++ vd = get_vo_dev(od); ++ if (vd == -1) ++ return -ENODEV; ++ ++ if (vd == CRT && !vo_get_status(vd)) ++ return 0; ++ ++ vo_set_state(vd, !!od->request_state); ++ ++ return 0; ++} ++ ++static struct output_properties vop = { ++ .set_state = yeeloong_vo_set_state, ++ .get_status = yeeloong_vo_get_status, ++}; ++ ++static int yeeloong_vo_init(void) ++{ ++ int ret, i; ++ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; ++ ++ /* Register video output device: lcd, crt */ ++ for (i = 0; i < VOD_NUM; i++) { ++ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop); ++ if (IS_ERR(vod[i])) { ++ if (i != 0) ++ video_output_unregister(vod[i-1]); ++ ret = PTR_ERR(vod[i]); ++ vod[i] = NULL; ++ return ret; ++ } ++ } ++ /* Ensure LCD is on by default */ ++ vo_set_state(LCD, ON); ++ ++ /* ++ * Turn off CRT by default, and will be enabled when the CRT ++ * connectting event reported by SCI ++ */ ++ vo_set_state(CRT, OFF); ++ ++ return 0; ++} ++ ++static void yeeloong_vo_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < VOD_NUM; i++) { ++ if (vod[i]) { ++ video_output_unregister(vod[i]); ++ vod[i] = NULL; ++ } ++ } ++} ++ ++/* lcd subdriver */ ++ ++struct lcd_device *lcd[VOD_NUM]; ++ ++static int get_lcd_dev(struct lcd_device *ld) ++{ ++ int i, dev; ++ ++ dev = -1; ++ for (i = 0; i < VOD_NUM; i++) ++ if (ld == lcd[i]) ++ dev = i; ++ ++ return dev; ++} ++ ++static int yeeloong_lcd_set_power(struct lcd_device *ld, int power) ++{ ++ int dev = get_lcd_dev(ld); ++ ++ if (power == FB_BLANK_UNBLANK) ++ vo_set_state(dev, ON); ++ if (power == FB_BLANK_POWERDOWN) ++ vo_set_state(dev, OFF); ++ ++ return 0; ++} ++ ++static int yeeloong_lcd_get_power(struct lcd_device *ld) ++{ ++ return vo_get_status(get_lcd_dev(ld)); ++} ++ ++static struct lcd_ops lcd_ops = { ++ .set_power = yeeloong_lcd_set_power, ++ .get_power = yeeloong_lcd_get_power, ++}; ++ ++static int yeeloong_lcd_init(void) ++{ ++ int ret, i; ++ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; ++ ++ /* Register video output device: lcd, crt */ ++ for (i = 0; i < VOD_NUM; i++) { ++ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops); ++ if (IS_ERR(lcd[i])) { ++ if (i != 0) ++ lcd_device_unregister(lcd[i-1]); ++ ret = PTR_ERR(lcd[i]); ++ lcd[i] = NULL; ++ return ret; ++ } ++ } ++#if 0 ++ /* This has been done by the vide output driver */ ++ ++ /* Ensure LCD is on by default */ ++ vo_set_state(LCD, ON); ++ ++ /* ++ * Turn off CRT by default, and will be enabled when the CRT ++ * connectting event reported by SCI ++ */ ++ vo_set_state(CRT, OFF); ++#endif ++ return 0; ++} ++ ++static void yeeloong_lcd_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < VOD_NUM; i++) { ++ if (lcd[i]) { ++ lcd_device_unregister(lcd[i]); ++ lcd[i] = NULL; ++ } ++ } ++} ++ ++/* hotkey subdriver */ ++ ++static struct input_dev *yeeloong_hotkey_dev; ++ ++static atomic_t reboot_flag, sleep_flag; ++#define in_sleep() (&sleep_flag) ++#define in_reboot() (&reboot_flag) ++ ++static const struct key_entry yeeloong_keymap[] = { ++ {KE_SW, EVENT_LID, { SW_LID } }, ++ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */ ++ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */ ++ {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */ ++ {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */ ++ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */ ++ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */ ++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */ ++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */ ++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */ ++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */ ++ {KE_END, 0} ++}; ++ ++static int is_fake_event(u16 keycode) ++{ ++ switch (keycode) { ++ case KEY_SLEEP: ++ case SW_LID: ++ return atomic_read(in_sleep()) | atomic_read(in_reboot()); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct key_entry *get_event_key_entry(int event, int status) ++{ ++ struct key_entry *ke; ++ static int old_brightness_status = -1; ++ static int old_volume_status = -1; ++ ++ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event); ++ if (!ke) ++ return NULL; ++ ++ switch (event) { ++ case EVENT_DISPLAY_BRIGHTNESS: ++ /* current status > old one, means up */ ++ if ((status < old_brightness_status) || (0 == status)) ++ ke++; ++ old_brightness_status = status; ++ break; ++ case EVENT_AUDIO_VOLUME: ++ if ((status < old_volume_status) || (0 == status)) ++ ke++; ++ old_volume_status = status; ++ break; ++ default: ++ break; ++ } ++ ++ return ke; ++} ++ ++static int report_lid_switch(int status) ++{ ++ static int old_status; ++ ++ /* ++ * LID is a switch button, so, two continuous same status should be ++ * ignored ++ */ ++ if (old_status != status) { ++ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status); ++ input_sync(yeeloong_hotkey_dev); ++ } ++ old_status = status; ++ ++ return status; ++} ++ ++static int crt_detect_handler(int status) ++{ ++ /* ++ * When CRT is inserted, enable its output and disable the LCD output, ++ * otherwise, do reversely. ++ */ ++ vo_set_state(CRT, status); ++ vo_set_state(LCD, !status); ++ ++ return status; ++} ++ ++static int displaytoggle_handler(int status) ++{ ++ /* EC(>=PQ1D26) does this job for us, we can not do it again, ++ * otherwise, the brightness will not resume to the normal level! */ ++ if (ec_version_before("EC_VER=PQ1D26")) ++ vo_set_state(LCD, status); ++ ++ return status; ++} ++ ++static int mypow(int x, int y) ++{ ++ int i, j = x; ++ ++ for (i = 1; i < y; i++) ++ j *= j; ++ ++ return j; ++} ++ ++static int switchvideomode_handler(int status) ++{ ++ /* Default status: CRT|LCD = 0|1 = 1 */ ++ static int bin_state = 1; ++ int i; ++ ++ /* ++ * Only enable switch video output button ++ * when CRT is connected ++ */ ++ if (!vo_get_status(CRT)) ++ return 0; ++ /* ++ * 2. no CRT connected: LCD on, CRT off ++ * 3. BOTH on ++ * 0. BOTH off ++ * 1. LCD off, CRT on ++ */ ++ ++ bin_state++; ++ if (bin_state > mypow(2, VOD_NUM) - 1) ++ bin_state = 0; ++ ++ for (i = 0; i < VOD_NUM; i++) ++ vo_set_state(i, bin_state & (1 << i)); ++ ++ return bin_state; ++} ++ ++static int camera_handler(int status) ++{ ++ int value; ++ ++ value = ec_read(REG_CAMERA_CONTROL); ++ ec_write(REG_CAMERA_CONTROL, value | (1 << 1)); ++ ++ return status; ++} ++ ++static int usb2_handler(int status) ++{ ++ pr_emerg("USB2 Over Current occurred\n"); ++ ++ return status; ++} ++ ++static int usb0_handler(int status) ++{ ++ pr_emerg("USB0 Over Current occurred\n"); ++ ++ return status; ++} ++ ++static int ac_bat_handler(int status) ++{ ++ if (ac_bat_initialized) { ++ power_supply_changed(&yeeloong_ac); ++ power_supply_changed(&yeeloong_bat); ++ } ++ ++ return status; ++} ++ ++struct sci_event { ++ int reg; ++ sci_handler handler; ++}; ++ ++static const struct sci_event se[] = { ++ [EVENT_AC_BAT] = {0, ac_bat_handler}, ++ [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL}, ++ [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL}, ++ [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler}, ++ [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler}, ++ [EVENT_BLACK_SCREEN] = {REG_DISPLAY_LCD, displaytoggle_handler}, ++ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL}, ++ [EVENT_LID] = {REG_LID_DETECT, NULL}, ++ [EVENT_DISPLAY_TOGGLE] = {0, switchvideomode_handler}, ++ [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler}, ++ [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler}, ++ [EVENT_WLAN] = {REG_WLAN, NULL}, ++}; ++ ++static void do_event_action(int event) ++{ ++ int status = -1; ++ struct key_entry *ke; ++ struct sci_event *sep; ++ ++ sep = (struct sci_event *)&se[event]; ++ ++ if (sep->reg != 0) ++ status = ec_read(sep->reg); ++ ++ if (status == -1) { ++ /* ec_read hasn't been called, status is invalid */ ++ return; ++ } ++ ++ if (sep->handler != NULL) ++ status = sep->handler(status); ++ ++ pr_debug("%s: event: %d status: %d\n", __func__, event, status); ++ ++ /* Report current key to user-space */ ++ ke = get_event_key_entry(event, status); ++ ++ /* ++ * Ignore the LID and SLEEP event when we are already in sleep or ++ * reboot state, this will avoid the recursive pm operations. but note: ++ * the report_lid_switch() called in arch/mips/loongson/lemote-2f/pm.c ++ * is necessary, because it is used to wake the system from sleep ++ * state. In the future, perhaps SW_LID should works like SLEEP, no ++ * need to function as a SWITCH, just report the state when the LID is ++ * closed is enough, this event can tell the software to "SLEEP", no ++ * need to tell the softwares when we are resuming from "SLEEP". ++ */ ++ if (ke && !is_fake_event(ke->keycode)) { ++ if (ke->keycode == SW_LID) ++ report_lid_switch(status); ++ else ++ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1, ++ true); ++ } ++} ++ ++/* ++ * SCI(system control interrupt) main interrupt routine ++ * ++ * We will do the query and get event number together so the interrupt routine ++ * should be longer than 120us now at least 3ms elpase for it. ++ */ ++static irqreturn_t sci_irq_handler(int irq, void *dev_id) ++{ ++ int ret, event; ++ ++ if (SCI_IRQ_NUM != irq) ++ return IRQ_NONE; ++ ++ /* Query the event number */ ++ ret = ec_query_event_num(); ++ if (ret < 0) ++ return IRQ_NONE; ++ ++ event = ec_get_event_num(); ++ if (event < EVENT_START || event > EVENT_END) ++ return IRQ_NONE; ++ ++ /* Execute corresponding actions */ ++ do_event_action(event); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Config and init some msr and gpio register properly. ++ */ ++static int sci_irq_init(void) ++{ ++ u32 hi, lo; ++ u32 gpio_base; ++ unsigned long flags; ++ int ret; ++ ++ /* Get gpio base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); ++ gpio_base = lo & 0xff00; ++ ++ /* Filter the former kb3310 interrupt for security */ ++ ret = ec_query_event_num(); ++ if (ret) ++ return ret; ++ ++ /* For filtering next number interrupt */ ++ udelay(10000); ++ ++ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN ++ * gpio : ++ * input, pull-up, no-invert, event-count and value 0, ++ * no-filter, no edge mode ++ * gpio27 map to Virtual gpio0 ++ * msr : ++ * no primary and lpc ++ * Unrestricted Z input to IG10 from Virtual gpio 0. ++ */ ++ local_irq_save(flags); ++ _rdmsr(0x80000024, &hi, &lo); ++ lo &= ~(1 << 10); ++ _wrmsr(0x80000024, hi, lo); ++ _rdmsr(0x80000025, &hi, &lo); ++ lo &= ~(1 << 10); ++ _wrmsr(0x80000025, hi, lo); ++ _rdmsr(0x80000023, &hi, &lo); ++ lo |= (0x0a << 0); ++ _wrmsr(0x80000023, hi, lo); ++ local_irq_restore(flags); ++ ++ /* Set gpio27 as sci interrupt ++ * ++ * input, pull-up, no-fliter, no-negedge, invert ++ * the sci event is just about 120us ++ */ ++ asm(".set noreorder\n"); ++ /* input enable */ ++ outl(0x00000800, (gpio_base | 0xA0)); ++ /* revert the input */ ++ outl(0x00000800, (gpio_base | 0xA4)); ++ /* event-int enable */ ++ outl(0x00000800, (gpio_base | 0xB8)); ++ asm(".set reorder\n"); ++ ++ return 0; ++} ++ ++static int notify_reboot(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ switch (event) { ++ case SYS_RESTART: ++ case SYS_HALT: ++ case SYS_POWER_OFF: ++ atomic_set(in_reboot(), 1); ++ break; ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static int notify_pm(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ switch (event) { ++ case PM_HIBERNATION_PREPARE: ++ case PM_SUSPEND_PREPARE: ++ atomic_inc(in_sleep()); ++ break; ++ case PM_POST_HIBERNATION: ++ case PM_POST_SUSPEND: ++ case PM_RESTORE_PREPARE: /* do we need this ?? */ ++ atomic_dec(in_sleep()); ++ break; ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event, ++ atomic_read(in_sleep())); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block reboot_notifier = { ++ .notifier_call = notify_reboot, ++}; ++ ++static struct notifier_block pm_notifier = { ++ .notifier_call = notify_pm, ++}; ++ ++static int yeeloong_hotkey_init(void) ++{ ++ int ret = 0; ++ ++ ret = register_reboot_notifier(&reboot_notifier); ++ if (ret) { ++ pr_err("Can't register reboot notifier\n"); ++ goto end; ++ } ++ ++ ret = register_pm_notifier(&pm_notifier); ++ if (ret) { ++ pr_err("Can't register pm notifier\n"); ++ goto free_reboot_notifier; ++ } ++ ++ ret = sci_irq_init(); ++ if (ret) { ++ pr_err("Can't init SCI interrupt\n"); ++ goto free_pm_notifier; ++ } ++ ++ ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler, ++ IRQF_ONESHOT, "sci", NULL); ++ if (ret) { ++ pr_err("Can't thread SCI interrupt handler\n"); ++ goto free_pm_notifier; ++ } ++ ++ yeeloong_hotkey_dev = input_allocate_device(); ++ ++ if (!yeeloong_hotkey_dev) { ++ ret = -ENOMEM; ++ goto free_irq; ++ } ++ ++ yeeloong_hotkey_dev->name = "HotKeys"; ++ yeeloong_hotkey_dev->phys = "button/input0"; ++ yeeloong_hotkey_dev->id.bustype = BUS_HOST; ++ yeeloong_hotkey_dev->dev.parent = NULL; ++ ++ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL); ++ if (ret) { ++ pr_err("Failed to setup input device keymap\n"); ++ goto free_dev; ++ } ++ ++ ret = input_register_device(yeeloong_hotkey_dev); ++ if (ret) ++ goto free_keymap; ++ ++ /* Update the current status of LID */ ++ report_lid_switch(ON); ++ ++#ifdef CONFIG_LOONGSON_SUSPEND ++ /* Install the real yeeloong_report_lid_status for pm.c */ ++ yeeloong_report_lid_status = report_lid_switch; ++#endif ++ return 0; ++ ++free_keymap: ++ sparse_keymap_free(yeeloong_hotkey_dev); ++free_dev: ++ input_free_device(yeeloong_hotkey_dev); ++free_irq: ++ free_irq(SCI_IRQ_NUM, NULL); ++free_pm_notifier: ++ unregister_pm_notifier(&pm_notifier); ++free_reboot_notifier: ++ unregister_reboot_notifier(&reboot_notifier); ++end: ++ return ret; ++} ++ ++static void yeeloong_hotkey_exit(void) ++{ ++ /* Free irq */ ++ free_irq(SCI_IRQ_NUM, NULL); ++ ++#ifdef CONFIG_LOONGSON_SUSPEND ++ /* Uninstall yeeloong_report_lid_status for pm.c */ ++ if (yeeloong_report_lid_status == report_lid_switch) ++ yeeloong_report_lid_status = NULL; ++#endif ++ ++ if (yeeloong_hotkey_dev) { ++ sparse_keymap_free(yeeloong_hotkey_dev); ++ input_unregister_device(yeeloong_hotkey_dev); ++ yeeloong_hotkey_dev = NULL; ++ } ++} ++ ++#ifdef CONFIG_PM ++static void usb_ports_set(int status) ++{ ++ status = !!status; ++ ++ ec_write(REG_USB0_FLAG, status); ++ ec_write(REG_USB1_FLAG, status); ++ ec_write(REG_USB2_FLAG, status); ++} ++ ++static int yeeloong_suspend(struct device *dev) ++ ++{ ++ if (ec_version_before("EC_VER=PQ1D27")) ++ vo_set_state(LCD, OFF); ++ vo_set_state(CRT, OFF); ++ usb_ports_set(OFF); ++ ++ return 0; ++} ++ ++static int yeeloong_resume(struct device *dev) ++{ ++ int ret; ++ ++ if (ec_version_before("EC_VER=PQ1D27")) ++ vo_set_state(LCD, ON); ++ vo_set_state(CRT, ON); ++ usb_ports_set(ON); ++ ++ ret = sci_irq_init(); ++ if (ret) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend, ++ yeeloong_resume); ++#endif ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "yeeloong_laptop", ++ }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "yeeloong_laptop", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &yeeloong_pm_ops, ++#endif ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int __init yeeloong_init(void) ++{ ++ int ret; ++ ++ pr_info("YeeLoong Laptop platform specific driver loaded.\n"); ++ ++ /* Register platform stuff */ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) { ++ pr_err("Failed to register YeeLoong platform driver.\n"); ++ return ret; ++ } ++ ++#define yeeloong_init_drv(drv, alias) do { \ ++ pr_info("Registered YeeLoong " alias " driver.\n"); \ ++ ret = yeeloong_ ## drv ## _init(); \ ++ if (ret) { \ ++ pr_err("Failed to register YeeLoong " alias " driver.\n"); \ ++ yeeloong_ ## drv ## _exit(); \ ++ return ret; \ ++ } \ ++} while (0) ++ ++ yeeloong_init_drv(backlight, "backlight"); ++ yeeloong_init_drv(bat, "battery and AC"); ++ yeeloong_init_drv(hwmon, "hardware monitor"); ++ yeeloong_init_drv(vo, "video output"); ++ yeeloong_init_drv(lcd, "lcd output"); ++ yeeloong_init_drv(hotkey, "hotkey input"); ++ ++ return 0; ++} ++ ++static void __exit yeeloong_exit(void) ++{ ++ yeeloong_hotkey_exit(); ++ yeeloong_lcd_exit(); ++ yeeloong_vo_exit(); ++ yeeloong_hwmon_exit(); ++ yeeloong_bat_exit(); ++ yeeloong_backlight_exit(); ++ platform_driver_unregister(&platform_driver); ++ ++ pr_info("YeeLoong platform specific driver unloaded.\n"); ++} ++ ++module_init(yeeloong_init); ++module_exit(yeeloong_exit); ++ ++MODULE_AUTHOR("Wu Zhangjin ; Liu Junliang "); ++MODULE_DESCRIPTION("YeeLoong laptop driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index b5b5c3d..f908003 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -727,6 +727,7 @@ comment "Platform RTC drivers" + config RTC_DRV_CMOS + tristate "PC-style 'CMOS'" + depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 ++ depends on !DEXXON_GDIUM + default y if X86 + help + Say "yes" here to get direct support for the real time clock +diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +index f940056..a9bb1db 100644 +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -450,6 +450,26 @@ void usb_amd_dev_put(void) + } + EXPORT_SYMBOL_GPL(usb_amd_dev_put); + ++#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) ++static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) ++{ ++ u16 cmd; ++ return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); ++} ++ ++#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) ++#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) ++ ++static int mmio_resource_enabled(struct pci_dev *pdev, int idx) ++{ ++ return pci_resource_start(pdev, idx) && mmio_enabled(pdev); ++} ++#endif ++ ++#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) + /* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. +@@ -531,15 +551,6 @@ reset_needed: + } + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + +-static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) +-{ +- u16 cmd; +- return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); +-} +- +-#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) +-#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) +- + static void quirk_usb_handoff_uhci(struct pci_dev *pdev) + { + unsigned long base = 0; +@@ -557,12 +568,11 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev) + if (base) + uhci_check_and_reset_hc(pdev, base); + } ++#else ++#define quirk_usb_handoff_uhci(x) do { } while (0) ++#endif /* CONFIG_USB_UHCI_HCD* */ + +-static int mmio_resource_enabled(struct pci_dev *pdev, int idx) +-{ +- return pci_resource_start(pdev, idx) && mmio_enabled(pdev); +-} +- ++#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + static void quirk_usb_handoff_ohci(struct pci_dev *pdev) + { + void __iomem *base; +@@ -641,7 +651,11 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) + /* Now the controller is safely in SUSPEND and nothing can wake it up */ + iounmap(base); + } ++#else ++#define quirk_usb_handoff_ohci(x) do { } while(0) ++#endif /* CONFIG_USB_OHCI_HCD* */ + ++#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) + static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { + { + /* Pegatron Lucid (ExoPC) */ +@@ -816,6 +830,9 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev) + + iounmap(base); + } ++#else ++#define quirk_usb_disable_ehci(x) do { } while (0) ++#endif /* CONFIG_USB_EHCI_HCD* */ + + /* + * handshake - spin reading a register until handshake completes +@@ -956,6 +973,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) + } + EXPORT_SYMBOL_GPL(usb_disable_xhci_ports); + ++#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) + /** + * PCI Quirks for xHCI. + * +@@ -1064,6 +1082,9 @@ hc_init: + + iounmap(base); + } ++#else ++#define quirk_usb_handoff_xhci(x) do { } while (0) ++#endif /* CONFIG_USB_UHCI_HCD* */ + + static void quirk_usb_early_handoff(struct pci_dev *pdev) + { +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index f0c0c53..84dff90 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -79,6 +79,9 @@ static void option_instat_callback(struct urb *urb); + #define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 + #define OPTION_PRODUCT_GTM380_MODEM 0x7201 + ++#define HUAWO_VENDOR_ID 0x21F5 ++#define HUAWO_PRODUCT_E1621 0x2008 ++ + #define HUAWEI_VENDOR_ID 0x12D1 + #define HUAWEI_PRODUCT_E173 0x140C + #define HUAWEI_PRODUCT_E1750 0x1406 +@@ -633,6 +636,7 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, + { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, ++ { USB_DEVICE(HUAWO_VENDOR_ID, HUAWO_PRODUCT_E1621) }, /* QUANTA 6500 chips, Unicom extensive use of this card */ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 8bf495f..f6a15b6 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -36,6 +36,12 @@ config VGASTATE + tristate + default n + ++config VIDEO_OUTPUT_CONTROL ++ tristate "Lowlevel video output switch controls" ++ help ++ This framework adds support for low-level control of the video ++ output switch. ++ + config VIDEOMODE_HELPERS + bool + +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 9ad3c17..3d869d9 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -7,6 +7,8 @@ obj-y += backlight/ + + obj-y += fbdev/ + ++#video output switch sysfs driver ++obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o + obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o + ifeq ($(CONFIG_OF),y) + obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o +diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig +index b3dd417..452035ad 100644 +--- a/drivers/video/fbdev/Kconfig ++++ b/drivers/video/fbdev/Kconfig +@@ -2450,6 +2450,19 @@ config FB_SIMPLE + Configuration re: surface address, size, and format must be provided + through device tree, or plain old platform data. + ++config FB_SM712 ++ tristate "Silicon Motion SM712 framebuffer support" ++ depends on FB && PCI ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ Frame buffer driver for the Silicon Motion SM712 chip. ++ ++ This driver is also available as a module. The module will be ++ called sm712fb. If you want to compile it as a module, say M ++ here and read . ++ + source "drivers/video/fbdev/omap/Kconfig" + source "drivers/video/fbdev/omap2/Kconfig" + source "drivers/video/fbdev/exynos/Kconfig" +diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile +index 1979aff..9b694f9 100644 +--- a/drivers/video/fbdev/Makefile ++++ b/drivers/video/fbdev/Makefile +@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o + obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o + obj-$(CONFIG_FB_PS3) += ps3fb.o + obj-$(CONFIG_FB_SM501) += sm501fb.o ++obj-$(CONFIG_FB_SM712) += sm712fb/ + obj-$(CONFIG_FB_UDL) += udlfb.o + obj-$(CONFIG_FB_SMSCUFX) += smscufx.o + obj-$(CONFIG_FB_XILINX) += xilinxfb.o +diff --git a/drivers/video/fbdev/sm712fb/Makefile b/drivers/video/fbdev/sm712fb/Makefile +new file mode 100644 +index 0000000..9bf3519 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_FB_SM712) += sm712fb.o ++ ++sm712fb-objs := sm712fb_drv.o sm712fb_accel.o +diff --git a/drivers/video/fbdev/sm712fb/TODO b/drivers/video/fbdev/sm712fb/TODO +new file mode 100644 +index 0000000..dcfd4e7 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/TODO +@@ -0,0 +1,7 @@ ++TODO: ++- Dual head support ++- refine the code, convert more registers magic numbers to macros ++- Does it really works on Big Endian machines? ++ ++Please send any patches to Greg Kroah-Hartman and ++Tom Li . +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.c b/drivers/video/fbdev/sm712fb/sm712fb_accel.c +new file mode 100644 +index 0000000..12fce1f +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.c +@@ -0,0 +1,246 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#include ++#include ++#include ++ ++#include "sm712fb_drv.h" ++#include "sm712fb_accel.h" ++ ++static inline u32 bytes_to_dword(const u8 *bytes, int length) ++{ ++ u32 dword = 0; ++ ++ switch (length) { ++ case 4: ++#ifdef __BIG_ENDIAN ++ dword += bytes[3]; ++#else ++ dword += bytes[3] << 24; ++#endif ++ case 3: ++#ifdef __BIG_ENDIAN ++ dword += bytes[2] << 8; ++#else ++ dword += bytes[2] << 16; ++#endif ++ case 2: ++#ifdef __BIG_ENDIAN ++ dword += bytes[1] << 16; ++#else ++ dword += bytes[1] << 8; ++#endif ++ case 1: ++#ifdef __BIG_ENDIAN ++ dword += bytes[0] << 24; ++#else ++ dword += bytes[0]; ++#endif ++ } ++ return dword; ++} ++ ++int sm712fb_init_accel(struct sm712fb_info *fb) ++{ ++ u8 reg; ++ ++ /* reset the 2D engine */ ++ sm712_write_seq(fb, 0x21, sm712_read_seq(fb, 0x21) & 0xf8); ++ reg = sm712_read_seq(fb, 0x15); ++ sm712_write_seq(fb, 0x15, reg | 0x30); ++ sm712_write_seq(fb, 0x15, reg); ++ ++ if (sm712fb_wait(fb) != 0) ++ return -1; ++ ++ sm712_write_dpr(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0)); ++ ++ /* same width for DPR_PITCH and DPR_SRC_WINDOW */ ++ sm712_write_dpr(fb, DPR_PITCH, ++ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); ++ sm712_write_dpr(fb, DPR_SRC_WINDOW, ++ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); ++ ++ sm712_write_dpr(fb, DPR_BYTE_BIT_MASK, 0xffffffff); ++ sm712_write_dpr(fb, DPR_COLOR_COMPARE_MASK, 0); ++ sm712_write_dpr(fb, DPR_COLOR_COMPARE, 0); ++ sm712_write_dpr(fb, DPR_SRC_BASE, 0); ++ sm712_write_dpr(fb, DPR_DST_BASE, 0); ++ sm712_read_dpr(fb, DPR_DST_BASE); ++ ++ return 0; ++} ++ ++int sm712fb_wait(struct sm712fb_info *fb) ++{ ++ int i; ++ u8 reg; ++ ++ for (i = 0; i < 10000; i++) { ++ reg = sm712_read_seq(fb, SCR_DE_STATUS); ++ if ((reg & SCR_DE_STATUS_MASK) == SCR_DE_ENGINE_IDLE) ++ return 0; ++ udelay(1); ++ } ++ return -EBUSY; ++} ++ ++void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ++{ ++ u32 width = rect->width, height = rect->height; ++ u32 dx = rect->dx, dy = rect->dy; ++ u32 color; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((rect->dx >= info->var.xres_virtual) || ++ (rect->dy >= info->var.yres_virtual)) ++ return; ++ ++ if (info->fix.visual == FB_VISUAL_TRUECOLOR || ++ info->fix.visual == FB_VISUAL_DIRECTCOLOR) ++ color = ((u32 *) (info->pseudo_palette))[rect->color]; ++ else ++ color = rect->color; ++ ++ sm712_write_dpr(sfb, DPR_FG_COLOR, color); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | ++ (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} ++ ++void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) ++{ ++ u32 sx = area->sx, sy = area->sy; ++ u32 dx = area->dx, dy = area->dy; ++ u32 height = area->height, width = area->width; ++ u32 direction; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((sx >= info->var.xres_virtual) || (sy >= info->var.yres_virtual)) ++ return; ++ ++ if (sy < dy || (sy == dy && sx <= dx)) { ++ sx += width - 1; ++ dx += width - 1; ++ sy += height - 1; ++ dy += height - 1; ++ direction = DE_CTRL_RTOL; ++ } else ++ direction = 0; ++ ++ sm712_write_dpr(sfb, DPR_SRC_COORDS, DPR_COORDS(sx, sy)); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_DE_CTRL, ++ DE_CTRL_START | DE_CTRL_ROP_ENABLE | direction | ++ (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} ++ ++void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image) ++{ ++ u32 dx = image->dx, dy = image->dy; ++ u32 width = image->width, height = image->height; ++ u32 fg_color, bg_color; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ u32 imgidx = 0; ++ u32 line = image->width >> 3; ++ ++ int i, j; ++ u32 total_bytes, total_dwords, remain_bytes; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((image->dx >= info->var.xres_virtual) || ++ (image->dy >= info->var.yres_virtual)) ++ return; ++ ++ if (unlikely(image->depth != 1)) { ++ /* unsupported depth, fallback to draw Tux */ ++ cfb_imageblit(info, image); ++ return; ++ } ++ ++ if (info->fix.visual == FB_VISUAL_TRUECOLOR || ++ info->fix.visual == FB_VISUAL_DIRECTCOLOR) { ++ fg_color = ((u32 *) (info->pseudo_palette))[image->fg_color]; ++ bg_color = ((u32 *) (info->pseudo_palette))[image->bg_color]; ++ } else { ++ fg_color = image->fg_color; ++ bg_color = image->bg_color; ++ } ++ ++ /* total bytes we need to write */ ++ total_bytes = (width + 7) / 8; ++ ++ /* split the bytes into dwords and remainder bytes */ ++ total_dwords = (total_bytes & ~3) / 4; ++ remain_bytes = total_bytes & 3; ++ ++ sm712_write_dpr(sfb, DPR_SRC_COORDS, 0); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_FG_COLOR, fg_color); ++ sm712_write_dpr(sfb, DPR_BG_COLOR, bg_color); ++ ++ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | ++ (DE_CTRL_COMMAND_HOST_WRITE << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_HOST_MONO << DE_CTRL_HOST_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ ++ for (i = 0; i < height; i++) { ++ /* cast bytes data into dwords and write to the dataport */ ++ for (j = 0; j < total_dwords; j++) { ++ sm712_write_dataport(sfb, ++ bytes_to_dword(&image-> ++ data[imgidx] + ++ j * 4, 4)); ++ } ++ ++ if (remain_bytes) { ++ sm712_write_dataport(sfb, ++ bytes_to_dword(&image-> ++ data[imgidx] + ++ (total_dwords * 4), ++ remain_bytes)); ++ } ++ imgidx += line; ++ } ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.h b/drivers/video/fbdev/sm712fb/sm712fb_accel.h +new file mode 100644 +index 0000000..6f79177 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.h +@@ -0,0 +1,33 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#ifndef _SM712FB_ACCEL_H ++#define _SM712FB_ACCEL_H ++ ++int sm712fb_init_accel(struct sm712fb_info *fb); ++int sm712fb_wait(struct sm712fb_info *fb); ++void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); ++void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area); ++void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image); ++ ++#endif +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.c b/drivers/video/fbdev/sm712fb/sm712fb_drv.c +new file mode 100644 +index 0000000..7f7cd4f +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.c +@@ -0,0 +1,1022 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PM ++#include ++#endif ++ ++#include "sm712fb_drv.h" ++#include "sm712fb_accel.h" ++#include "sm712fb_modedb.h" ++ ++static struct fb_var_screeninfo sm712fb_var = { ++ .xres = 1024, ++ .yres = 600, ++ .xres_virtual = 1024, ++ .yres_virtual = 600, ++ .bits_per_pixel = 16, ++ .red = {16, 8, 0}, ++ .green = {8, 8, 0}, ++ .blue = {0, 8, 0}, ++ .activate = FB_ACTIVATE_NOW, ++ .height = -1, ++ .width = -1, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .nonstd = 0, ++ .accel_flags = FB_ACCELF_TEXT, ++}; ++ ++static struct fb_fix_screeninfo sm712fb_fix = { ++ .id = "smXXXfb", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .line_length = 800 * 3, ++ .accel = FB_ACCEL_SMI_LYNX, ++ .type_aux = 0, ++ .xpanstep = 0, ++ .ypanstep = 0, ++ .ywrapstep = 0, ++}; ++ ++struct vesa_mode { ++ char index[6]; ++ u16 lfb_width; ++ u16 lfb_height; ++ u16 lfb_depth; ++}; ++ ++static bool accel = 1; ++ ++static struct vesa_mode vesa_mode_table[] = { ++ {"0x301", 640, 480, 8}, ++ {"0x303", 800, 600, 8}, ++ {"0x305", 1024, 768, 8}, ++ {"0x307", 1280, 1024, 8}, ++ ++ {"0x311", 640, 480, 16}, ++ {"0x314", 800, 600, 16}, ++ {"0x317", 1024, 768, 16}, ++ {"0x31A", 1280, 1024, 16}, ++ ++ {"0x312", 640, 480, 24}, ++ {"0x315", 800, 600, 24}, ++ {"0x318", 1024, 768, 24}, ++ {"0x31B", 1280, 1024, 24}, ++}; ++ ++struct screen_info sm712_scr_info; ++ ++static int sm712fb_setup(char *options) ++{ ++ char *this_opt; ++ ++ if (!options || !*options) ++ return 0; ++ ++ while ((this_opt = strsep(&options, ",")) != NULL) { ++ if (!*this_opt) ++ continue; ++ ++ if (!strcmp(this_opt, "accel:0")) ++ accel = false; ++ else if (!strcmp(this_opt, "accel:1")) ++ accel = true; ++ } ++ return 0; ++} ++ ++/* process command line options, get vga parameter */ ++static int __init sm712_vga_setup(char *options) ++{ ++ int i; ++ ++ if (!options || !*options) ++ return -EINVAL; ++ ++ sm712_scr_info.lfb_width = 0; ++ sm712_scr_info.lfb_height = 0; ++ sm712_scr_info.lfb_depth = 0; ++ ++ pr_debug("sm712_vga_setup = %s\n", options); ++ ++ for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { ++ if (strstr(options, vesa_mode_table[i].index)) { ++ sm712_scr_info.lfb_width = vesa_mode_table[i].lfb_width; ++ sm712_scr_info.lfb_height = ++ vesa_mode_table[i].lfb_height; ++ sm712_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; ++ return 0; ++ } ++ } ++ ++ return -1; ++} ++ ++__setup("vga=", sm712_vga_setup); ++ ++static void sm712_setpalette(int regno, unsigned red, unsigned green, ++ unsigned blue, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb = info->par; ++ ++ /* set bit 5:4 = 01 (write LCD RAM only) */ ++ sm712_write_seq(sfb, 0x66, (sm712_read_seq(sfb, 0x66) & 0xC3) | 0x10); ++ ++ sm712_writeb(sfb->mmio, DAC_REG, regno); ++ sm712_writeb(sfb->mmio, DAC_VAL, red >> 10); ++ sm712_writeb(sfb->mmio, DAC_VAL, green >> 10); ++ sm712_writeb(sfb->mmio, DAC_VAL, blue >> 10); ++} ++ ++/* chan_to_field ++ * ++ * convert a colour value into a field position ++ * ++ * from pxafb.c ++ */ ++ ++static inline unsigned int chan_to_field(unsigned int chan, ++ struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++static int sm712_blank(int blank_mode, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb = info->par; ++ ++ /* clear DPMS setting */ ++ switch (blank_mode) { ++ case FB_BLANK_UNBLANK: ++ /* Screen On: HSync: On, VSync : On */ ++ sm712_write_seq(sfb, 0x01, ++ (sm712_read_seq(sfb, 0x01) & (~0x20))); ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) & 0x77)); ++ sm712_write_seq(sfb, 0x22, ++ (sm712_read_seq(sfb, 0x22) & (~0x30))); ++ sm712_write_seq(sfb, 0x23, ++ (sm712_read_seq(sfb, 0x23) & (~0xc0))); ++ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); ++ sm712_write_seq(sfb, 0x31, (sm712_read_seq(sfb, 0x31) | 0x03)); ++ break; ++ case FB_BLANK_NORMAL: ++ /* Screen Off: HSync: On, VSync : On Soft blank */ ++ sm712_write_seq(sfb, 0x01, ++ (sm712_read_seq(sfb, 0x01) & (~0x20))); ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x22, ++ (sm712_read_seq(sfb, 0x22) & (~0x30))); ++ sm712_write_seq(sfb, 0x23, ++ (sm712_read_seq(sfb, 0x23) & (~0xc0))); ++ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ break; ++ case FB_BLANK_VSYNC_SUSPEND: ++ /* Screen On: HSync: On, VSync : Off */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x0c); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x20)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0x20)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ case FB_BLANK_HSYNC_SUSPEND: ++ /* Screen On: HSync: Off, VSync : On */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x0c); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x10)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ case FB_BLANK_POWERDOWN: ++ /* Screen On: HSync: Off, VSync : Off */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x5a); ++ sm712_write_seq(sfb, 0x6b, 0x20); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x30)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int sm712_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned trans, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb; ++ u32 val; ++ ++ sfb = info->par; ++ ++ if (regno > 255) ++ return 1; ++ ++ switch (sfb->fb.fix.visual) { ++ case FB_VISUAL_DIRECTCOLOR: ++ case FB_VISUAL_TRUECOLOR: ++ /* ++ * 16/32 bit true-colour, use pseudo-palette for 16 base color ++ */ ++ if (regno < 16) { ++ if (sfb->fb.var.bits_per_pixel == 16) { ++ u32 *pal = sfb->fb.pseudo_palette; ++ ++ val = chan_to_field(red, &sfb->fb.var.red); ++ val |= chan_to_field(green, &sfb->fb.var.green); ++ val |= chan_to_field(blue, &sfb->fb.var.blue); ++#ifdef __BIG_ENDIAN ++ pal[regno] = ++ ((red & 0xf800) >> 8) | ++ ((green & 0xe000) >> 13) | ++ ((green & 0x1c00) << 3) | ++ ((blue & 0xf800) >> 3); ++#else ++ pal[regno] = val; ++#endif ++ } else { ++ u32 *pal = sfb->fb.pseudo_palette; ++ ++ val = chan_to_field(red, &sfb->fb.var.red); ++ val |= chan_to_field(green, &sfb->fb.var.green); ++ val |= chan_to_field(blue, &sfb->fb.var.blue); ++#ifdef __BIG_ENDIAN ++ val = ++ (val & 0xff00ff00 >> 8) | ++ (val & 0x00ff00ff << 8); ++#endif ++ pal[regno] = val; ++ } ++ } ++ break; ++ ++ case FB_VISUAL_PSEUDOCOLOR: ++ /* color depth 8 bit */ ++ sm712_setpalette(regno, red, green, blue, info); ++ break; ++ ++ default: ++ return 1; /* unknown type */ ++ } ++ ++ return 0; ++ ++} ++ ++#ifdef __BIG_ENDIAN ++static ssize_t sm712fb_read(struct fb_info *info, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ ++ u32 *buffer, *dst; ++ u32 __iomem *src; ++ int c, i, cnt = 0, err = 0; ++ unsigned long total_size; ++ ++ if (!info || !info->screen_base) ++ return -ENODEV; ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return -EPERM; ++ ++ total_size = info->screen_size; ++ ++ if (total_size == 0) ++ total_size = info->fix.smem_len; ++ ++ if (p >= total_size) ++ return 0; ++ ++ if (count >= total_size) ++ count = total_size; ++ ++ if (count + p > total_size) ++ count = total_size - p; ++ ++ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ src = (u32 __iomem *) (info->screen_base + p); ++ ++ if (info->fbops->fb_sync) ++ info->fbops->fb_sync(info); ++ ++ while (count) { ++ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; ++ dst = buffer; ++ for (i = c >> 2; i--;) { ++ *dst = fb_readl(src++); ++ *dst = ++ (*dst & 0xff00ff00 >> 8) | (*dst & 0x00ff00ff << 8); ++ dst++; ++ } ++ if (c & 3) { ++ u8 *dst8 = (u8 *) dst; ++ u8 __iomem *src8 = (u8 __iomem *) src; ++ ++ for (i = c & 3; i--;) { ++ if (i & 1) { ++ *dst8++ = fb_readb(++src8); ++ } else { ++ *dst8++ = fb_readb(--src8); ++ src8 += 2; ++ } ++ } ++ src = (u32 __iomem *) src8; ++ } ++ ++ if (copy_to_user(buf, buffer, c)) { ++ err = -EFAULT; ++ break; ++ } ++ *ppos += c; ++ buf += c; ++ cnt += c; ++ count -= c; ++ } ++ ++ kfree(buffer); ++ ++ return (err) ? err : cnt; ++} ++ ++static ssize_t ++sm712fb_write(struct fb_info *info, const char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ ++ u32 *buffer, *src; ++ u32 __iomem *dst; ++ int c, i, cnt = 0, err = 0; ++ unsigned long total_size; ++ ++ if (!info || !info->screen_base) ++ return -ENODEV; ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return -EPERM; ++ ++ total_size = info->screen_size; ++ ++ if (total_size == 0) ++ total_size = info->fix.smem_len; ++ ++ if (p > total_size) ++ return -EFBIG; ++ ++ if (count > total_size) { ++ err = -EFBIG; ++ count = total_size; ++ } ++ ++ if (count + p > total_size) { ++ if (!err) ++ err = -ENOSPC; ++ ++ count = total_size - p; ++ } ++ ++ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ dst = (u32 __iomem *) (info->screen_base + p); ++ ++ if (info->fbops->fb_sync) ++ info->fbops->fb_sync(info); ++ ++ while (count) { ++ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; ++ src = buffer; ++ ++ if (copy_from_user(src, buf, c)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ for (i = c >> 2; i--;) { ++ fb_writel((*src & 0xff00ff00 >> 8) | ++ (*src & 0x00ff00ff << 8), dst++); ++ src++; ++ } ++ if (c & 3) { ++ u8 *src8 = (u8 *) src; ++ u8 __iomem *dst8 = (u8 __iomem *) dst; ++ ++ for (i = c & 3; i--;) { ++ if (i & 1) { ++ fb_writeb(*src8++, ++dst8); ++ } else { ++ fb_writeb(*src8++, --dst8); ++ dst8 += 2; ++ } ++ } ++ dst = (u32 __iomem *) dst8; ++ } ++ ++ *ppos += c; ++ buf += c; ++ cnt += c; ++ count -= c; ++ } ++ ++ kfree(buffer); ++ ++ return (cnt) ? cnt : err; ++} ++#endif /* ! __BIG_ENDIAN */ ++ ++static void sm712_set_timing(struct sm712fb_info *sfb) ++{ ++ int i = 0, j = 0; ++ u32 m_nScreenStride; ++ ++ dev_dbg(&sfb->pdev->dev, ++ "sfb->width=%d sfb->height=%d " ++ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n", ++ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz); ++ ++ for (j = 0; j < numVGAModes; j++) { ++ if (VGAMode[j].mmSizeX != sfb->width || ++ VGAMode[j].mmSizeY != sfb->height || ++ VGAMode[j].bpp != sfb->fb.var.bits_per_pixel || ++ VGAMode[j].hz != sfb->hz) { ++ continue; ++ } ++ ++ dev_dbg(&sfb->pdev->dev, ++ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d " ++ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n", ++ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, ++ VGAMode[j].bpp, VGAMode[j].hz); ++ ++ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j); ++ ++ sm712_writeb(sfb->mmio, 0x3c6, 0x0); ++ ++ sm712_write_seq(sfb, 0, 0x1); ++ ++ sm712_writeb(sfb->mmio, 0x3c2, VGAMode[j].Init_MISC); ++ ++ /* init SEQ register SR00 - SR04 */ ++ for (i = 0; i < SR00_SR04_SIZE; i++) ++ sm712_write_seq(sfb, i, VGAMode[j].Init_SR00_SR04[i]); ++ ++ /* init SEQ register SR10 - SR24 */ ++ for (i = 0; i < SR10_SR24_SIZE; i++) ++ sm712_write_seq(sfb, i + 0x10, ++ VGAMode[j].Init_SR10_SR24[i]); ++ ++ /* init SEQ register SR30 - SR75 */ ++ for (i = 0; i < SR30_SR75_SIZE; i++) ++ if ((i + 0x30) != 0x62 && ++ (i + 0x30) != 0x6a && (i + 0x30) != 0x6b) ++ sm712_write_seq(sfb, i + 0x30, ++ VGAMode[j].Init_SR30_SR75[i]); ++ ++ /* init SEQ register SR80 - SR93 */ ++ for (i = 0; i < SR80_SR93_SIZE; i++) ++ sm712_write_seq(sfb, i + 0x80, ++ VGAMode[j].Init_SR80_SR93[i]); ++ ++ /* init SEQ register SRA0 - SRAF */ ++ for (i = 0; i < SRA0_SRAF_SIZE; i++) ++ sm712_write_seq(sfb, i + 0xa0, ++ VGAMode[j].Init_SRA0_SRAF[i]); ++ ++ /* init Graphic register GR00 - GR08 */ ++ for (i = 0; i < GR00_GR08_SIZE; i++) ++ sm712_write_grph(sfb, i, VGAMode[j].Init_GR00_GR08[i]); ++ ++ /* init Attribute register AR00 - AR14 */ ++ for (i = 0; i < AR00_AR14_SIZE; i++) ++ sm712_write_attr(sfb, i, VGAMode[j].Init_AR00_AR14[i]); ++ ++ /* init CRTC register CR00 - CR18 */ ++ for (i = 0; i < CR00_CR18_SIZE; i++) ++ sm712_write_crtc(sfb, i, VGAMode[j].Init_CR00_CR18[i]); ++ ++ /* init CRTC register CR30 - CR4D */ ++ for (i = 0; i < CR30_CR4D_SIZE; i++) ++ sm712_write_crtc(sfb, i + 0x30, ++ VGAMode[j].Init_CR30_CR4D[i]); ++ ++ /* init CRTC register CR90 - CRA7 */ ++ for (i = 0; i < CR90_CRA7_SIZE; i++) ++ sm712_write_crtc(sfb, i + 0x90, ++ VGAMode[j].Init_CR90_CRA7[i]); ++ } ++ sm712_writeb(sfb->mmio, 0x3c2, 0x67); ++ ++ /* set VPR registers */ ++ sm712_writel(sfb->vpr, 0x0C, 0x0); ++ sm712_writel(sfb->vpr, 0x40, 0x0); ++ ++ /* set data width */ ++ m_nScreenStride = (sfb->width * sfb->fb.var.bits_per_pixel) / 64; ++ switch (sfb->fb.var.bits_per_pixel) { ++ case 8: ++ sm712_writel(sfb->vpr, 0x0, 0x0); ++ break; ++ case 16: ++ sm712_writel(sfb->vpr, 0x0, 0x00020000); ++ break; ++ case 24: ++ sm712_writel(sfb->vpr, 0x0, 0x00040000); ++ break; ++ case 32: ++ sm712_writel(sfb->vpr, 0x0, 0x00030000); ++ break; ++ } ++ sm712_writel(sfb->vpr, 0x10, ++ (u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride)); ++} ++ ++static void sm712fb_setmode(struct sm712fb_info *sfb) ++{ ++ switch (sfb->fb.var.bits_per_pixel) { ++ case 32: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 4; ++ sfb->fb.var.red.length = 8; ++ sfb->fb.var.green.length = 8; ++ sfb->fb.var.blue.length = 8; ++ sfb->fb.var.red.offset = 16; ++ sfb->fb.var.green.offset = 8; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 24: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 3; ++ sfb->fb.var.red.length = 8; ++ sfb->fb.var.green.length = 8; ++ sfb->fb.var.blue.length = 8; ++ sfb->fb.var.red.offset = 16; ++ sfb->fb.var.green.offset = 8; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 8: ++ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres; ++ sfb->fb.var.red.length = 3; ++ sfb->fb.var.green.length = 3; ++ sfb->fb.var.blue.length = 2; ++ sfb->fb.var.red.offset = 5; ++ sfb->fb.var.green.offset = 2; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 16: ++ default: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 2; ++ sfb->fb.var.red.length = 5; ++ sfb->fb.var.green.length = 6; ++ sfb->fb.var.blue.length = 5; ++ sfb->fb.var.red.offset = 11; ++ sfb->fb.var.green.offset = 5; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ } ++ ++ sfb->width = sfb->fb.var.xres; ++ sfb->height = sfb->fb.var.yres; ++ sfb->hz = 60; ++ sm712_set_timing(sfb); ++} ++ ++static int sm712_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ /* sanity checks */ ++ if (var->xres_virtual < var->xres) ++ var->xres_virtual = var->xres; ++ ++ if (var->yres_virtual < var->yres) ++ var->yres_virtual = var->yres; ++ ++ /* set valid default bpp */ ++ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && ++ (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) ++ var->bits_per_pixel = 16; ++ ++ return 0; ++} ++ ++static int sm712_set_par(struct fb_info *info) ++{ ++ sm712fb_setmode(info->par); ++ ++ return 0; ++} ++ ++static struct fb_ops sm712fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = sm712_check_var, ++ .fb_set_par = sm712_set_par, ++ .fb_setcolreg = sm712_setcolreg, ++ .fb_blank = sm712_blank, ++ .fb_fillrect = cfb_fillrect, ++ .fb_imageblit = cfb_imageblit, ++ .fb_copyarea = cfb_copyarea, ++#ifdef __BIG_ENDIAN ++ .fb_read = sm712fb_read, ++ .fb_write = sm712fb_write, ++#endif ++}; ++ ++/* ++ * alloc struct sm712fb_info and assign default values ++ */ ++static struct sm712fb_info *sm712_fb_info_new(struct pci_dev *pdev) ++{ ++ struct sm712fb_info *sfb; ++ ++ sfb = kzalloc(sizeof(*sfb), GFP_KERNEL); ++ ++ if (!sfb) ++ return NULL; ++ ++ sfb->pdev = pdev; ++ ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT; ++ sfb->fb.fbops = &sm712fb_ops; ++ sfb->fb.fix = sm712fb_fix; ++ sfb->fb.var = sm712fb_var; ++ sfb->fb.pseudo_palette = sfb->colreg; ++ sfb->fb.par = sfb; ++ sfb->accel = accel; ++ ++ return sfb; ++} ++ ++/* ++ * free struct sm712fb_info ++ */ ++static void sm712_fb_info_free(struct sm712fb_info *sfb) ++{ ++ kfree(sfb); ++} ++ ++/* ++ * Map in the screen memory ++ */ ++ ++static int sm712_map_smem(struct sm712fb_info *sfb, ++ struct pci_dev *pdev, u_long smem_len) ++{ ++ ++ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); ++ ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 32) ++ sfb->fb.fix.smem_start += 0x800000; ++#endif ++ ++ sfb->fb.fix.smem_len = smem_len; ++ ++ sfb->fb.screen_base = sfb->lfb; ++ ++ if (!sfb->fb.screen_base) { ++ dev_err(&pdev->dev, ++ "%s: unable to map screen memory\n", sfb->fb.fix.id); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Unmap in the screen memory ++ * ++ */ ++static void sm712_unmap_smem(struct sm712fb_info *sfb) ++{ ++ if (sfb && sfb->fb.screen_base) { ++ iounmap(sfb->fb.screen_base); ++ sfb->fb.screen_base = NULL; ++ sfb->lfb = NULL; ++ } ++} ++ ++static inline void sm712_init_hw(struct sm712fb_info *sfb) ++{ ++ /* enable linear memory mode and packed pixel format */ ++ outb_p(0x18, 0x3c4); ++ outb_p(0x11, 0x3c5); ++ ++ /* set MCLK = 14.31818 * (0x16 / 0x2) */ ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x62, 0x3e); ++ ++ /* enable PCI burst */ ++ sm712_write_seq(sfb, 0x17, 0x20); ++ ++#ifdef __BIG_ENDIAN ++ /* enable word swap */ ++ if (sfb->fb.var.bits_per_pixel == 32) ++ sm712_write_seq(sfb, 0x17, 0x30); ++#endif ++ ++ if (!sfb->accel) { ++ dev_info(&sfb->pdev->dev, "2d acceleration was disabled by user.\n"); ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; ++ return; ++ } ++ ++ if (sm712fb_init_accel(sfb) < 0) { ++ dev_info(&sfb->pdev->dev, "failed to enable 2d accleration.\n"); ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; ++ return; ++ } else { ++ sm712fb_ops.fb_fillrect = sm712fb_fillrect; ++ sm712fb_ops.fb_copyarea = sm712fb_copyarea; ++ sm712fb_ops.fb_imageblit = sm712fb_imageblit; ++ sfb->fb.flags |= FBINFO_HWACCEL_COPYAREA | ++ FBINFO_HWACCEL_FILLRECT | ++ FBINFO_HWACCEL_IMAGEBLIT | ++ FBINFO_READS_FAST; ++ dev_info(&sfb->pdev->dev, "sm712fb: enable 2d acceleration.\n"); ++ } ++} ++ ++static int sm712fb_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct sm712fb_info *sfb; ++ int err; ++ unsigned long mmio_base; ++ ++#ifndef MODULE ++ char *option = NULL; ++ ++ if (!fb_get_options("sm712fb", &option)) ++ sm712fb_setup(option); ++#endif ++ ++ dev_info(&pdev->dev, "Silicon Motion display driver."); ++ ++ err = pci_enable_device(pdev); /* enable SMTC chip */ ++ if (err) ++ return err; ++ ++ sprintf(sm712fb_fix.id, "sm712fb"); ++ ++ sfb = sm712_fb_info_new(pdev); ++ ++ if (!sfb) { ++ err = -ENOMEM; ++ goto free_fail; ++ } ++ ++ sfb->chip_id = ent->device; ++ ++ pci_set_drvdata(pdev, sfb); ++ ++ /* get mode parameter from sm712_scr_info */ ++ if (sm712_scr_info.lfb_width != 0) { ++ sfb->fb.var.xres = sm712_scr_info.lfb_width; ++ sfb->fb.var.yres = sm712_scr_info.lfb_height; ++ sfb->fb.var.bits_per_pixel = sm712_scr_info.lfb_depth; ++ } else { ++ /* default resolution 1024x600 16bit mode */ ++ sfb->fb.var.xres = SM712_DEFAULT_XRES; ++ sfb->fb.var.yres = SM712_DEFAULT_YRES; ++ sfb->fb.var.bits_per_pixel = SM712_DEFAULT_BPP; ++ } ++ ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 24) ++ sfb->fb.var.bits_per_pixel = (sm712_scr_info.lfb_depth = 32); ++#endif ++ ++ /* Map address and memory detection */ ++ mmio_base = pci_resource_start(pdev, 0); ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); ++ ++ if (sfb->chip_id != 0x712) { ++ dev_err(&pdev->dev, ++ "No valid Silicon Motion display chip was detected!"); ++ ++ goto fb_fail; ++ } ++ ++ sfb->fb.fix.mmio_start = mmio_base + SM712_REG_BASE; ++ sfb->fb.fix.mmio_len = SM712_REG_SIZE; ++#ifdef __BIG_ENDIAN ++ sfb->lfb = ioremap(mmio_base, 0x00c00000); ++#else ++ sfb->lfb = ioremap(mmio_base, 0x00800000); ++#endif ++ sfb->mmio = sfb->lfb + SM712_MMIO_BASE; ++ sfb->dpr = sfb->lfb + SM712_DPR_BASE; ++ sfb->vpr = sfb->lfb + SM712_VPR_BASE; ++ sfb->dataport = sfb->lfb + SM712_DATAPORT_BASE; ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 32) { ++ sfb->lfb += 0x800000; ++ dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb); ++ } ++#endif ++ if (!sfb->mmio) { ++ dev_err(&pdev->dev, ++ "%s: unable to map memory mapped IO!", sfb->fb.fix.id); ++ err = -ENOMEM; ++ goto fb_fail; ++ } ++ ++ sm712_init_hw(sfb); ++ ++ /* can support 32 bpp */ ++ if (15 == sfb->fb.var.bits_per_pixel) ++ sfb->fb.var.bits_per_pixel = 16; ++ ++ sfb->fb.var.xres_virtual = sfb->fb.var.xres; ++ sfb->fb.var.yres_virtual = sfb->fb.var.yres; ++ err = sm712_map_smem(sfb, pdev, SM712_VRAM_SIZE); ++ if (err) ++ goto fail; ++ ++ sm712fb_setmode(sfb); ++ ++ err = register_framebuffer(&sfb->fb); ++ if (err < 0) ++ goto fail; ++ ++ dev_info(&pdev->dev, ++ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.", ++ sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres, ++ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); ++ ++ return 0; ++ ++fail: ++ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail."); ++ ++ sm712_unmap_smem(sfb); ++fb_fail: ++ sm712_fb_info_free(sfb); ++free_fail: ++ pci_disable_device(pdev); ++ ++ return err; ++} ++ ++/* ++ * 0x712 (LynxEM+) ++ */ ++static const struct pci_device_id sm712fb_pci_table[] = { ++ {PCI_DEVICE(0x126f, 0x712),}, ++ {0,} ++}; ++ ++static void sm712fb_pci_remove(struct pci_dev *pdev) ++{ ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ sm712_unmap_smem(sfb); ++ unregister_framebuffer(&sfb->fb); ++ sm712_fb_info_free(sfb); ++} ++ ++#ifdef CONFIG_PM ++static int sm712fb_pci_suspend(struct device *device) ++{ ++ struct pci_dev *pdev = to_pci_dev(device); ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ ++ /* set the hw in sleep mode use external clock and self memory refresh ++ * so that we can turn off internal PLLs later on ++ */ ++ sm712_write_seq(sfb, 0x20, (sm712_read_seq(sfb, 0x20) | 0xc0)); ++ sm712_write_seq(sfb, 0x69, (sm712_read_seq(sfb, 0x69) & 0xf7)); ++ ++ console_lock(); ++ fb_set_suspend(&sfb->fb, 1); ++ console_unlock(); ++ ++ /* additionally turn off all function blocks including internal PLLs */ ++ sm712_write_seq(sfb, 0x21, 0xff); ++ ++ return 0; ++} ++ ++static int sm712fb_pci_resume(struct device *device) ++{ ++ struct pci_dev *pdev = to_pci_dev(device); ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ ++ /* reinit hardware */ ++ sm712_init_hw(sfb); ++ ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0xc0)); ++ sm712_write_seq(sfb, 0x33, ((sm712_read_seq(sfb, 0x33) | 0x08) & 0xfb)); ++ ++ sm712fb_setmode(sfb); ++ ++ console_lock(); ++ fb_set_suspend(&sfb->fb, 0); ++ console_unlock(); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(sm712_pm_ops, sm712fb_pci_suspend, sm712fb_pci_resume); ++#define SM712_PM_OPS (&sm712_pm_ops) ++ ++#else /* !CONFIG_PM */ ++ ++#define SM712_PM_OPS NULL ++ ++#endif /* !CONFIG_PM */ ++ ++static struct pci_driver sm712fb_driver = { ++ .name = "sm712fb", ++ .id_table = sm712fb_pci_table, ++ .probe = sm712fb_pci_probe, ++ .remove = sm712fb_pci_remove, ++ .driver.pm = SM712_PM_OPS, ++}; ++ ++module_pci_driver(sm712fb_driver); ++ ++module_param(accel, bool, S_IRUGO); ++MODULE_PARM_DESC(accel, "Enable or disable 2D Acceleration"); ++ ++MODULE_AUTHOR("Siliconmotion "); ++MODULE_DESCRIPTION("Framebuffer driver for Silicon Motion SM712 Graphic Cards"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.h b/drivers/video/fbdev/sm712fb/sm712fb_drv.h +new file mode 100644 +index 0000000..bf81bff +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.h +@@ -0,0 +1,130 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#ifndef _SM712FB_DRV_H ++#define _SM712FB_DRV_H ++ ++/* ++* Private structure ++*/ ++struct sm712fb_info { ++ struct pci_dev *pdev; ++ struct fb_info fb; ++ u16 chip_id; ++ u8 chip_rev_id; ++ ++ void __iomem *lfb; /* linear frame buffer, the base address */ ++ ++ void __iomem *dpr; /* drawing processor control regs */ ++ void __iomem *vpr; /* video processor control regs */ ++ void __iomem *cpr; /* capture processor control regs */ ++ void __iomem *mmio; /* memory map IO port */ ++ void __iomem *dataport; /* 2d drawing engine data port */ ++ ++ u_int width; ++ u_int height; ++ u_int hz; ++ ++ u32 colreg[17]; ++ ++ bool accel; ++}; ++ ++/* constants for registers operations */ ++ ++#include "sm712fb_io.h" ++ ++#define FB_ACCEL_SMI_LYNX 88 ++ ++#define SM712_DEFAULT_XRES 1024 ++#define SM712_DEFAULT_YRES 600 ++#define SM712_DEFAULT_BPP 16 ++ ++#define SM712_VRAM_SIZE 0x00400000 ++ ++#define SM712_REG_BASE 0x00400000 ++#define SM712_REG_SIZE 0x00400000 ++ ++#define SM712_MMIO_BASE 0x00700000 ++ ++#define SM712_DPR_BASE 0x00408000 ++#define SM712_DPR_SIZE (0x6C + 1) ++ ++#define DPR_COORDS(x, y) (((x) << 16) | (y)) ++ ++#define DPR_SRC_COORDS 0x00 ++#define DPR_DST_COORDS 0x04 ++#define DPR_SPAN_COORDS 0x08 ++#define DPR_DE_CTRL 0x0c ++#define DPR_PITCH 0x10 ++#define DPR_FG_COLOR 0x14 ++#define DPR_BG_COLOR 0x18 ++#define DPR_STRETCH 0x1c ++#define DPR_COLOR_COMPARE 0x20 ++#define DPR_COLOR_COMPARE_MASK 0x24 ++#define DPR_BYTE_BIT_MASK 0x28 ++#define DPR_CROP_TOPLEFT_COORDS 0x2c ++#define DPR_CROP_BOTRIGHT_COORDS 0x30 ++#define DPR_SRC_WINDOW 0x3c ++#define DPR_SRC_BASE 0x40 ++#define DPR_DST_BASE 0x44 ++ ++#define DE_CTRL_START 0x80000000 ++#define DE_CTRL_RTOL 0x08000000 ++#define DE_CTRL_COMMAND_MASK 0x001f0000 ++#define DE_CTRL_COMMAND_SHIFT 16 ++#define DE_CTRL_COMMAND_BITBLT 0x00 ++#define DE_CTRL_COMMAND_SOLIDFILL 0x01 ++#define DE_CTRL_COMMAND_HOST_WRITE 0x08 ++#define DE_CTRL_ROP_ENABLE 0x00008000 ++#define DE_CTRL_ROP_MASK 0x000000ff ++#define DE_CTRL_ROP_SHIFT 0 ++#define DE_CTRL_ROP_SRC 0x0c ++ ++#define DE_CTRL_HOST_SHIFT 22 ++#define DE_CTRL_HOST_MONO 1 ++ ++#define SCR_DE_STATUS 0x16 ++#define SCR_DE_STATUS_MASK 0x18 ++#define SCR_DE_ENGINE_IDLE 0x10 ++ ++#define SM712_VPR_BASE 0x0040c000 ++#define SM712_VPR_SIZE (0x44 + 1) ++ ++#define SM712_DATAPORT_BASE 0x00400000 ++ ++#define SR00_SR04_SIZE (0x04 - 0x00 + 1) ++#define SR10_SR24_SIZE (0x24 - 0x10 + 1) ++#define SR30_SR75_SIZE (0x75 - 0x30 + 1) ++#define SR80_SR93_SIZE (0x93 - 0x80 + 1) ++#define SRA0_SRAF_SIZE (0xAF - 0xA0 + 1) ++#define GR00_GR08_SIZE (0x08 - 0x00 + 1) ++#define AR00_AR14_SIZE (0x14 - 0x00 + 1) ++#define CR00_CR18_SIZE (0x18 - 0x00 + 1) ++#define CR30_CR4D_SIZE (0x4D - 0x30 + 1) ++#define CR90_CRA7_SIZE (0xA7 - 0x90 + 1) ++ ++#define DAC_REG (0x3c8) ++#define DAC_VAL (0x3c9) ++ ++#endif +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_io.h b/drivers/video/fbdev/sm712fb/sm712fb_io.h +new file mode 100644 +index 0000000..93346a0 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_io.h +@@ -0,0 +1,90 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ */ ++ ++ ++#define sm712_writeb(base, reg, dat) writeb(dat, base + reg) ++#define sm712_writew(base, reg, dat) writew(dat, base + reg) ++#define sm712_writel(base, reg, dat) writel(dat, base + reg) ++ ++#define sm712_readb(base, reg) readb(base + reg) ++#define sm712_readw(base, reg) readw(base + reg) ++#define sm712_readl(base, reg) readl(base + reg) ++ ++ ++static inline void sm712_write_crtc(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3d4, reg); ++ sm712_writeb(fb->mmio, 0x3d5, val); ++} ++ ++static inline u8 sm712_read_crtc(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3d4, reg); ++ return sm712_readb(fb->mmio, 0x3d5); ++} ++ ++static inline void sm712_write_grph(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3ce, reg); ++ sm712_writeb(fb->mmio, 0x3cf, val); ++} ++ ++static inline u8 sm712_read_grph(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3ce, reg); ++ return sm712_readb(fb->mmio, 0x3cf); ++} ++ ++static inline void sm712_write_attr(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_readb(fb->mmio, 0x3da); ++ sm712_writeb(fb->mmio, 0x3c0, reg); ++ sm712_readb(fb->mmio, 0x3c1); ++ sm712_writeb(fb->mmio, 0x3c0, val); ++} ++ ++static inline void sm712_write_seq(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3c4, reg); ++ sm712_writeb(fb->mmio, 0x3c5, val); ++} ++ ++static inline u8 sm712_read_seq(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3c4, reg); ++ return sm712_readb(fb->mmio, 0x3c5); ++} ++ ++static inline u32 sm712_read_dpr(struct sm712fb_info *fb, u8 reg) ++{ ++ return sm712_readl(fb->dpr, reg); ++} ++ ++static inline void sm712_write_dpr(struct sm712fb_info *fb, u8 reg, u32 val) ++{ ++ sm712_writel(fb->dpr, reg, val); ++} ++ ++static inline void sm712_write_dataport(struct sm712fb_info *fb, u32 val) ++{ ++ sm712_writel(fb->dataport, 0, val); ++} +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_modedb.h b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h +new file mode 100644 +index 0000000..16ee7e3 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h +@@ -0,0 +1,682 @@ ++/* The next structure holds all information relevant for a specific video mode. ++ */ ++ ++struct ModeInit { ++ int mmSizeX; ++ int mmSizeY; ++ int bpp; ++ int hz; ++ unsigned char Init_MISC; ++ unsigned char Init_SR00_SR04[SR00_SR04_SIZE]; ++ unsigned char Init_SR10_SR24[SR10_SR24_SIZE]; ++ unsigned char Init_SR30_SR75[SR30_SR75_SIZE]; ++ unsigned char Init_SR80_SR93[SR80_SR93_SIZE]; ++ unsigned char Init_SRA0_SRAF[SRA0_SRAF_SIZE]; ++ unsigned char Init_GR00_GR08[GR00_GR08_SIZE]; ++ unsigned char Init_AR00_AR14[AR00_AR14_SIZE]; ++ unsigned char Init_CR00_CR18[CR00_CR18_SIZE]; ++ unsigned char Init_CR30_CR4D[CR30_CR4D_SIZE]; ++ unsigned char Init_CR90_CRA7[CR90_CRA7_SIZE]; ++}; ++ ++/********************************************************************** ++ SM712 Mode table. ++ **********************************************************************/ ++struct ModeInit VGAMode[] = { ++ { ++ /* mode#0: 640 x 480 16Bpp 60Hz */ ++ 640, 480, 16, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ { ++ /* mode#1: 640 x 480 24Bpp 60Hz */ ++ 640, 480, 24, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ { ++ /* mode#0: 640 x 480 32Bpp 60Hz */ ++ 640, 480, 32, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ ++ { /* mode#2: 800 x 600 16Bpp 60Hz */ ++ 800, 600, 16, 60, ++ /* Init_MISC */ ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, ++ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, ++ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ { /* mode#3: 800 x 600 24Bpp 60Hz */ ++ 800, 600, 24, 60, ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ { /* mode#7: 800 x 600 32Bpp 60Hz */ ++ 800, 600, 32, 60, ++ /* Init_MISC */ ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, ++ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, ++ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ /* We use 1024x768 table to light 1024x600 panel for lemote */ ++ { /* mode#4: 1024 x 600 16Bpp 60Hz */ ++ 1024, 600, 16, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, ++ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x00, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, ++ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, ++ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, ++ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#5: 1024 x 768 24Bpp 60Hz */ ++ 1024, 768, 24, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, ++ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#4: 1024 x 768 32Bpp 60Hz */ ++ 1024, 768, 32, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, ++ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#6: 320 x 240 16Bpp 60Hz */ ++ 320, 240, 16, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, ++ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ ++ { /* mode#8: 320 x 240 32Bpp 60Hz */ ++ 320, 240, 32, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, ++ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++}; ++ ++#define numVGAModes ARRAY_SIZE(VGAMode) +diff --git a/drivers/video/output.c b/drivers/video/output.c +new file mode 100644 +index 0000000..1446c49 +--- /dev/null ++++ b/drivers/video/output.c +@@ -0,0 +1,133 @@ ++/* ++ * output.c - Display Output Switch driver ++ * ++ * Copyright (C) 2006 Luming Yu ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++ ++MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Luming Yu "); ++ ++static ssize_t state_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ ssize_t ret_size = 0; ++ struct output_device *od = to_output_device(dev); ++ if (od->props) ++ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); ++ return ret_size; ++} ++ ++static ssize_t state_store(struct device *dev, struct device_attribute *attr, ++ const char *buf,size_t count) ++{ ++ char *endp; ++ struct output_device *od = to_output_device(dev); ++ int request_state = simple_strtoul(buf,&endp,0); ++ size_t size = endp - buf; ++ ++ if (isspace(*endp)) ++ size++; ++ if (size != count) ++ return -EINVAL; ++ ++ if (od->props) { ++ od->request_state = request_state; ++ od->props->set_state(od); ++ } ++ return count; ++} ++static DEVICE_ATTR_RW(state); ++ ++static void video_output_release(struct device *dev) ++{ ++ struct output_device *od = to_output_device(dev); ++ kfree(od); ++} ++ ++static struct attribute *video_output_attrs[] = { ++ &dev_attr_state.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(video_output); ++ ++static struct class video_output_class = { ++ .name = "video_output", ++ .dev_release = video_output_release, ++ .dev_groups = video_output_groups, ++}; ++ ++struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op) ++{ ++ struct output_device *new_dev; ++ int ret_code = 0; ++ ++ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); ++ if (!new_dev) { ++ ret_code = -ENOMEM; ++ goto error_return; ++ } ++ new_dev->props = op; ++ new_dev->dev.class = &video_output_class; ++ new_dev->dev.parent = dev; ++ dev_set_name(&new_dev->dev, "%s", name); ++ dev_set_drvdata(&new_dev->dev, devdata); ++ ret_code = device_register(&new_dev->dev); ++ if (ret_code) { ++ kfree(new_dev); ++ goto error_return; ++ } ++ return new_dev; ++ ++error_return: ++ return ERR_PTR(ret_code); ++} ++EXPORT_SYMBOL(video_output_register); ++ ++void video_output_unregister(struct output_device *dev) ++{ ++ if (!dev) ++ return; ++ device_unregister(&dev->dev); ++} ++EXPORT_SYMBOL(video_output_unregister); ++ ++static void __exit video_output_class_exit(void) ++{ ++ class_unregister(&video_output_class); ++} ++ ++static int __init video_output_class_init(void) ++{ ++ return class_register(&video_output_class); ++} ++ ++postcore_initcall(video_output_class_init); ++module_exit(video_output_class_exit); +diff --git a/include/linux/sm501.h b/include/linux/sm501.h +index 02fde50..a8677f0 100644 +--- a/include/linux/sm501.h ++++ b/include/linux/sm501.h +@@ -27,6 +27,9 @@ extern unsigned long sm501_set_clock(struct device *dev, + extern unsigned long sm501_find_clock(struct device *dev, + int clksrc, unsigned long req_freq); + ++extern void sm501_configure_gpio(struct device *dev, ++ unsigned int gpio, unsigned char mode); ++ + /* sm501_misc_control + * + * Modify the SM501's MISC_CONTROL register +@@ -122,6 +125,7 @@ struct sm501_reg_init { + #define SM501_USE_AC97 (1<<7) + #define SM501_USE_I2S (1<<8) + #define SM501_USE_GPIO (1<<9) ++#define SM501_USE_PWM (1<<10) + + #define SM501_USE_ALL (0xffffffff) + +diff --git a/include/linux/video_output.h b/include/linux/video_output.h +new file mode 100644 +index 0000000..ed5cdeb +--- /dev/null ++++ b/include/linux/video_output.h +@@ -0,0 +1,57 @@ ++/* ++ * ++ * Copyright (C) 2006 Luming Yu ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++#ifndef _LINUX_VIDEO_OUTPUT_H ++#define _LINUX_VIDEO_OUTPUT_H ++#include ++#include ++struct output_device; ++struct output_properties { ++ int (*set_state)(struct output_device *); ++ int (*get_status)(struct output_device *); ++}; ++struct output_device { ++ int request_state; ++ struct output_properties *props; ++ struct device dev; ++}; ++#define to_output_device(obj) container_of(obj, struct output_device, dev) ++#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE) ++struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op); ++void video_output_unregister(struct output_device *dev); ++#else ++static struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op) ++{ ++ return ERR_PTR(-ENODEV); ++} ++static void video_output_unregister(struct output_device *dev) ++{ ++ return; ++} ++#endif ++#endif +diff --git a/init/calibrate.c b/init/calibrate.c +index ce635dc..10e775d 100644 +--- a/init/calibrate.c ++++ b/init/calibrate.c +@@ -21,6 +21,7 @@ static int __init lpj_setup(char *str) + + __setup("lpj=", lpj_setup); + ++#ifndef ARCH_HAS_PREPARED_LPJ + #ifdef ARCH_HAS_READ_CURRENT_TIMER + + /* This routine uses the read_current_timer() routine and gets the +@@ -171,6 +172,7 @@ static unsigned long calibrate_delay_direct(void) + return 0; + } + #endif ++#endif /* ARCH_HAS_PREPARED_LPJ */ + + /* + * This is the number of bits of precision for the loops_per_jiffy. Each +@@ -291,6 +293,7 @@ void calibrate_delay(void) + lpj = lpj_fine; + pr_info("Calibrating delay loop (skipped), " + "value calculated using timer frequency.. "); ++#ifndef ARCH_HAS_PREPARED_LPJ + } else if ((lpj = calibrate_delay_is_known())) { + ; + } else if ((lpj = calibrate_delay_direct()) != 0) { +@@ -301,6 +304,7 @@ void calibrate_delay(void) + if (!printed) + pr_info("Calibrating delay loop... "); + lpj = calibrate_delay_converge(); ++#endif /* ARCH_HAS_PREPARED_LPJ */ + } + per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj; + if (!printed) +diff --git a/net/rfkill/core.c b/net/rfkill/core.c +index fa7cd79..616abb5 100644 +--- a/net/rfkill/core.c ++++ b/net/rfkill/core.c +@@ -111,7 +111,7 @@ static LIST_HEAD(rfkill_list); /* list of registered rf switches */ + static DEFINE_MUTEX(rfkill_global_mutex); + static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ + +-static unsigned int rfkill_default_state = 1; ++static unsigned int rfkill_default_state; /* default: 0 = radio off */ + module_param_named(default_state, rfkill_default_state, uint, 0444); + MODULE_PARM_DESC(default_state, + "Default initial state for all radio types, 0 = radio off"); +diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl +index 826470d..9e6dc30 100755 +--- a/scripts/recordmcount.pl ++++ b/scripts/recordmcount.pl +@@ -309,14 +309,33 @@ if ($arch eq "x86_64") { + $cc .= " -m64"; + $objcopy .= " -O elf64-sparc"; + } elsif ($arch eq "mips") { +- # To enable module support, we need to enable the -mlong-calls option +- # of gcc for module, after using this option, we can not get the real +- # offset of the calling to _mcount, but the offset of the lui +- # instruction or the addiu one. herein, we record the address of the +- # first one, and then we can replace this instruction by a branch +- # instruction to jump over the profiling function to filter the +- # indicated functions, or swith back to the lui instruction to trace +- # them, which means dynamic tracing. ++ # ++ # To disable tracing, just replace "jal _mcount" with nop; ++ # to enable tracing, replace back. so, the offset 14 is ++ # needed to be recorded. ++ # ++ # 10: 03e0082d move at,ra ++ # 14: 0c000000 jal 0 ++ # 14: R_MIPS_26 _mcount ++ # 14: R_MIPS_NONE *ABS* ++ # 14: R_MIPS_NONE *ABS* ++ # 18: 00020021 nop ++ # ++ # ++ # ++ # If no long call(-mlong-calls), the same to kernel. ++ # ++ # If the module space differs from the kernel space, long ++ # call is needed, as a result, the address of _mcount is ++ # needed to be recorded in a register and then jump from ++ # module space to kernel space via "jalr ". To ++ # disable tracing, "jalr " can be replaced by ++ # nop; to enable tracing, replace it back. Since the ++ # offset of "jalr " is not easy to be matched, ++ # the offset of the 1st _mcount below is recorded and to ++ # disable tracing, "lui v1, 0x0" is substituted with "b ++ # label", which jumps over "jalr "; to enable ++ # tracing, replace it back. + # + # c: 3c030000 lui v1,0x0 + # c: R_MIPS_HI16 _mcount +@@ -328,19 +347,12 @@ if ($arch eq "x86_64") { + # 10: R_MIPS_NONE *ABS* + # 14: 03e0082d move at,ra + # 18: 0060f809 jalr v1 ++ # label: + # +- # for the kernel: +- # +- # 10: 03e0082d move at,ra +- # 14: 0c000000 jal 0 +- # 14: R_MIPS_26 _mcount +- # 14: R_MIPS_NONE *ABS* +- # 14: R_MIPS_NONE *ABS* +- # 18: 00020021 nop + if ($is_module eq "0") { + $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$"; + } else { +- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$"; ++ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_(HI16|26)\\s+_mcount\$"; + } + $objdump .= " -Melf-trad".$endian."mips "; + +diff --git a/scripts/sstrip.sh b/scripts/sstrip.sh +new file mode 100755 +index 0000000..49b973a +--- /dev/null ++++ b/scripts/sstrip.sh +@@ -0,0 +1,59 @@ ++#!/bin/bash ++# sstrip.sh -- strip the section table of an elf file ++# ++# Copyright (C) 2010 Wu Zhangjin, wuzhangjin@gmail.com ++# Licensed under the GPLv2 ++# ++# Since the section table is useless for the embedded device, it can be ++# stripped out. ++# ++# Note: Some bootloader may check the section table but most of the time, it ++# may be not really used, If it really need the section table, it may need the ++# decompressed kernel image. ++ ++# Usage ++ ++function usage ++{ ++cat </dev/null` ++[ "xELF" != "x${FILE_TYPE}" ] && echo "$0: ${IMAGE} is not an ELF file" && exit -1 ++ ++[ "x${V}" == "x1" ] && orig_filesz=`wc -c ${IMAGE} | cut -d' ' -f1` ++ ++# Get the offset of the section table, here get the end of the program section ++filesz=$((`${OBJDUMP} -p ${IMAGE} | grep -m1 filesz | tr -s ' ' | cut -d' ' -f3`)) ++ ++# Truncate it via the dd tool ++dd if=/dev/null bs=1 of=${IMAGE} seek=${filesz} 2>/dev/null ++ ++# Clear the section table information in the ELF header ++# The last 6 bytes of the ELF header are the section table information ++echo -ne "\x00\x00\x00\x00\x00\x00" | dd of=${IMAGE} bs=1 seek=46 count=6 conv=notrunc 2>/dev/null ++ ++# Debug ++if [ "x${V}" == "x1" ]; then ++ echo "----------------------------------------------------------------" ++ echo "Strip the section table at ${filesz} of ${IMAGE}" ++ echo "----------------------------------------------------------------" ++ echo " sstrip: $0" ++ echo " objdump: ${OBJDUMP}" ++ echo "original size: ${orig_filesz}" ++ echo "current size: ${filesz}" ++ echo "reduced size: $((${orig_filesz} - ${filesz}))" ++fi diff --git a/libre/linux-libre/PKGBUILD b/libre/linux-libre/PKGBUILD index 6a205f495..ca13870d4 100644 --- a/libre/linux-libre/PKGBUILD +++ b/libre/linux-libre/PKGBUILD @@ -9,7 +9,7 @@ pkgbase=linux-libre # Build stock "" kernel _pkgbasever=4.0-gnu -_pkgver=4.0.3-gnu +_pkgver=4.0.4-gnu _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -35,20 +35,20 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li 'logo_linux_'{clut224.ppm,vga16.ppm,mono.pbm} 'change-default-console-loglevel.patch' # loongson-community patch: http://linux-libre.fsfla.org/pub/linux-libre/lemote/gnewsense/pool/debuginfo/ - '4.0-rc7-37af2c8aae-loongson-community.patch') + '4.0.2-ae91f13af5-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - '73e5adbee83c5d5898f03b4f7525876cc0db6eab0e569a4229ee8d8cf9e3ef2e' + 'e447de9a53c5aefd25f0474f3304ab87076b88353badaae20dcbd85712e85e61' 'SKIP' - 'a9a0590e45ec7b3913f0da294c52bbd6f4c0034a1ef1fedb83f3c6347003f499' - '69f73083d02e937e4c47a88c559da55a45efa17a6740459d0a002aa8ccfd89c2' - '254fff11b9dc1e33637615cfafebaa2838ed6e5b59b4200dcfbe775cbbe7f2c2' + '5fa50ffbe7b6e82c70d1d15947c34caa0b484ecd264f01149f40b910e7c8f394' + '33f68753bc12456e601492f870f7e04cd116f36b81630d9bad954093d72bc57a' + '7b6954ed843d17149129cc04064d00db791767ad8b7dca5a4833a2febafce50a' 'f0d90e756f14533ee67afda280500511a62465b4f76adcc5effa95a40045179c' 'bfd4a7f61febe63c880534dcb7c31c5b932dde6acf991810b41a939a93535494' '6de8a8319271809ffdb072b68d53d155eef12438e6d04ff06a5a4db82c34fa8a' '13bd7a8d9ed6b6bc971e4cd162262c5a20448a83796af39ce394d827b0e5de74' '1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99' - '6fd223e0e11421f87ff4c913b61636ecbbecf249f431ba87a1288463b847f26c') + '13e141279af2bc17decfc041e015710daac9a6cd1c9b4e871a76cb8f916b9e22') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva ) @@ -85,7 +85,7 @@ prepare() { # Adding loongson-community patch if [ "${CARCH}" == "mips64el" ]; then - patch -p1 -i ${srcdir}/4.0-rc7-37af2c8aae-loongson-community.patch + patch -p1 -i ${srcdir}/4.0.2-ae91f13af5-loongson-community.patch fi cat "${srcdir}/config.${CARCH}" > ./.config diff --git a/libre/linux-libre/config.i686 b/libre/linux-libre/config.i686 index 0754e396b..bb9de9662 100644 --- a/libre/linux-libre/config.i686 +++ b/libre/linux-libre/config.i686 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 4.0.0-gnu-1 Kernel Configuration +# Linux/x86 4.0.4-gnu-1 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -151,7 +151,7 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_HUGETLB is not set # CONFIG_CGROUP_PERF is not set @@ -851,7 +851,7 @@ CONFIG_TCP_CONG_DCTCP=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -3202,6 +3202,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m CONFIG_INPUT_E3X0_BUTTON=m CONFIG_INPUT_PCSPKR=m @@ -3660,7 +3661,7 @@ CONFIG_POWER_RESET_GPIO=y # CONFIG_POWER_RESET_RESTART is not set # CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3818,6 +3819,7 @@ CONFIG_SENSORS_W83627EHF=m CONFIG_SENSORS_ACPI_POWER=m CONFIG_SENSORS_ATK0110=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_OF=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set @@ -4327,6 +4329,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4838,8 +4841,10 @@ CONFIG_SOUND_OSS_CORE=y CONFIG_SND=m CONFIG_SND_TIMER=m CONFIG_SND_PCM=m +CONFIG_SND_DMAENGINE_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -5050,7 +5055,109 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y +# CONFIG_SND_ATMEL_SOC is not set +CONFIG_SND_DESIGNWARE_I2S=m + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +CONFIG_SND_SST_MFLD_PLATFORM=m +CONFIG_SND_SST_IPC=m +CONFIG_SND_SST_IPC_ACPI=m +CONFIG_SND_SOC_INTEL_SST=m +CONFIG_SND_SOC_INTEL_SST_ACPI=m +CONFIG_SND_SOC_INTEL_HASWELL=m +CONFIG_SND_SOC_INTEL_BAYTRAIL=m +CONFIG_SND_SOC_INTEL_HASWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH=m +CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +CONFIG_SND_SOC_MAX98090=m +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +CONFIG_SND_SOC_RL6231=m +CONFIG_SND_SOC_RT286=m +# CONFIG_SND_SOC_RT5631 is not set +CONFIG_SND_SOC_RT5640=m +CONFIG_SND_SOC_RT5645=m +CONFIG_SND_SOC_RT5670=m +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -5770,7 +5877,7 @@ CONFIG_VIRTIO=m # Virtio drivers # CONFIG_VIRTIO_PCI=m -CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_PCI_LEGACY=y CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y @@ -6247,6 +6354,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set CONFIG_EXTCON_SM5502=m @@ -7148,7 +7256,7 @@ CONFIG_CRYPTO_CRC32_PCLMUL=m CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m diff --git a/libre/linux-libre/config.mips64el b/libre/linux-libre/config.mips64el index f5961b335..1017c9e65 100644 --- a/libre/linux-libre/config.mips64el +++ b/libre/linux-libre/config.mips64el @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/mips 4.0.0-gnu-1 Kernel Configuration +# Linux/mips 4.0.4-gnu-1 Kernel Configuration # CONFIG_MIPS=y @@ -273,7 +273,7 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y @@ -629,7 +629,7 @@ CONFIG_TCP_CONG_ILLINOIS=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -2813,6 +2813,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m # CONFIG_INPUT_E3X0_BUTTON is not set CONFIG_INPUT_MC13783_PWRBUTTON=m @@ -3188,7 +3189,7 @@ CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_BRCMSTB is not set # CONFIG_POWER_RESET_RESTART is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3328,6 +3329,7 @@ CONFIG_SENSORS_W83L786NG=m CONFIG_SENSORS_W83627HF=m CONFIG_SENSORS_W83627EHF=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set # CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set @@ -3782,6 +3784,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4235,6 +4238,7 @@ CONFIG_SND_TIMER=m CONFIG_SND_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -4399,7 +4403,87 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +# CONFIG_SND_ATMEL_SOC is not set + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -5055,7 +5139,7 @@ CONFIG_VIRTIO=m # Virtio drivers # CONFIG_VIRTIO_PCI=m -CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_PCI_LEGACY=y CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y @@ -5384,6 +5468,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set # CONFIG_EXTCON_SM5502 is not set @@ -6199,7 +6284,7 @@ CONFIG_CRYPTO_CRC32=m CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m diff --git a/libre/linux-libre/config.x86_64 b/libre/linux-libre/config.x86_64 index cc69f030f..2a925a8c9 100644 --- a/libre/linux-libre/config.x86_64 +++ b/libre/linux-libre/config.x86_64 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 4.0.0-gnu-1 Kernel Configuration +# Linux/x86 4.0.4-gnu-1 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -159,7 +159,7 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_HUGETLB is not set # CONFIG_CGROUP_PERF is not set @@ -839,7 +839,7 @@ CONFIG_TCP_CONG_DCTCP=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -3100,6 +3100,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m CONFIG_INPUT_E3X0_BUTTON=m CONFIG_INPUT_PCSPKR=m @@ -3524,7 +3525,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_RESTART is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3681,6 +3682,7 @@ CONFIG_SENSORS_W83627EHF=m CONFIG_SENSORS_ACPI_POWER=m CONFIG_SENSORS_ATK0110=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set # CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set @@ -4171,6 +4173,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4664,6 +4667,7 @@ CONFIG_SND_TIMER=m CONFIG_SND_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -4833,7 +4837,108 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +# CONFIG_SND_ATMEL_SOC is not set +CONFIG_SND_DESIGNWARE_I2S=m + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +CONFIG_SND_SST_MFLD_PLATFORM=m +CONFIG_SND_SST_IPC=m +CONFIG_SND_SST_IPC_ACPI=m +CONFIG_SND_SOC_INTEL_SST=m +CONFIG_SND_SOC_INTEL_SST_ACPI=m +CONFIG_SND_SOC_INTEL_HASWELL=m +CONFIG_SND_SOC_INTEL_BAYTRAIL=m +CONFIG_SND_SOC_INTEL_HASWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH=m +CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +CONFIG_SND_SOC_MAX98090=m +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +CONFIG_SND_SOC_RL6231=m +CONFIG_SND_SOC_RT286=m +# CONFIG_SND_SOC_RT5631 is not set +CONFIG_SND_SOC_RT5640=m +CONFIG_SND_SOC_RT5645=m +CONFIG_SND_SOC_RT5670=m +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -5541,7 +5646,7 @@ CONFIG_VIRTIO=m # Virtio drivers # CONFIG_VIRTIO_PCI=m -CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_PCI_LEGACY=y CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_MMIO=m CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y @@ -5986,6 +6091,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set CONFIG_EXTCON_SM5502=m @@ -6883,7 +6989,7 @@ CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -- cgit v1.2.3 From 7b9b1532c54a173efd8bd231576cc7a21870d4d1 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 20 May 2015 23:02:59 -0300 Subject: linux-libre-lts-3.14.43_gnu-1: updating version --- libre/linux-libre-lts/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libre') diff --git a/libre/linux-libre-lts/PKGBUILD b/libre/linux-libre-lts/PKGBUILD index b18238083..3916be539 100644 --- a/libre/linux-libre-lts/PKGBUILD +++ b/libre/linux-libre-lts/PKGBUILD @@ -9,7 +9,7 @@ pkgbase=linux-libre-lts # Build kernel with -lts localname _pkgbasever=3.14-gnu -_pkgver=3.14.42-gnu +_pkgver=3.14.43-gnu _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -43,7 +43,7 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li '3.14.26-8475f027b4-loongson-community.patch') sha256sums=('477555c709b9407fe37dbd70d3331ff9dde1f9d874aba2741f138d07ae6f281b' 'SKIP' - 'b3b2b73aab358b0371fb02cbb112e90daf341db661300262f2a835ea29d9161c' + '1c8d7336a4176e3a96de49688cb268cc5e7a44063d32a2597a339094f3f7cc16' 'SKIP' 'b4cc9c49948fc1d571c27ddeddd93b5b499ccc17fb06fa75bfe41ecddfbc12e4' '3fa8ce26aea9b5e596ccfc842baa3f2a8be8ef4a62bc13d75e8da2bafd89141c' -- cgit v1.2.3 From 9621572e3cdaab31dcdf2f79ec7bf8907c741847 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Fri, 22 May 2015 14:50:47 -0300 Subject: icedove-1:31.7.0.deb1-1{,.nonprism1}: updating version --- libre/icedove/PKGBUILD | 22 ++- libre/icedove/icedove.desktop | 272 ++++++++++++++----------------------- libre/icedove/rhbz-966424.patch | 23 ---- nonprism/icedove/PKGBUILD | 22 ++- nonprism/icedove/icedove.desktop | 272 ++++++++++++++----------------------- nonprism/icedove/rhbz-966424.patch | 23 ---- 6 files changed, 220 insertions(+), 414 deletions(-) delete mode 100644 libre/icedove/rhbz-966424.patch delete mode 100644 nonprism/icedove/rhbz-966424.patch (limited to 'libre') diff --git a/libre/icedove/PKGBUILD b/libre/icedove/PKGBUILD index 0f2f95f04..d86927420 100644 --- a/libre/icedove/PKGBUILD +++ b/libre/icedove/PKGBUILD @@ -3,7 +3,7 @@ # We're getting this from Debian Sid _debname=icedove -_debver=31.6.0 +_debver=31.7.0 _debrel=deb1 _debrepo=http://ftp.debian.org/debian/pool/main/ debfile() { echo $@|sed -r 's@(.).*@\1/&/&@'; } @@ -11,7 +11,7 @@ debfile() { echo $@|sed -r 's@(.).*@\1/&/&@'; } pkgname=${_debname} epoch=1 pkgver=${_debver}.${_debrel} -pkgrel=2 +pkgrel=1 pkgdesc="A libre version of Debian Icedove, the standalone mail/news reader based on Mozilla Thunderbird." arch=('i686' 'x86_64' 'mips64el') license=('MPL' 'GPL' 'LGPL') @@ -28,16 +28,14 @@ source=("${_debrepo}/`debfile ${_debname}`_${_debver}.orig.tar.xz" mozconfig ${pkgname}.desktop ${pkgname}-install-dir.patch - vendor.js - rhbz-966424.patch) + vendor.js) options=(!emptydirs) -sha256sums=('9011da6632434d6ee991cc69f4e040a194d998ce3a04e5c3a05f21fc361124dc' - 'ac73365adcccf126b97432cfd60828da667b2eb82512ae252cf577939d666fd9' +sha256sums=('00ce17575690400e22e7ce21dc5b3b4f71092b7708ee9aad74448d1401da8794' + '04c30b4e72819b764bc463d36c39f55741d3e47ae994ba89fd14e63fe32c6561' '09a0041f7f12498d933284b3d3a44e19002515accaff767d145a8f404b79e86a' - 'a0be56fc87f255804e00e7c85abbc4731ebdaa8938858f1f8ac47dd2f17c0b8b' + '0b0d25067c64c6b829c84e5259ffca978e3971f85acc8483f47bdbed5b0b5b6a' '24599eab8862476744fe1619a9a53a5b8cdcab30b3fc5767512f31d3529bd05d' - 'b44f0eb82dce8a02aa71f0eab4b0d820e5383f613becc62cc995aac8638b54ec' - '746cb474c5a2c26fc474256e430e035e604b71b27df1003d4af85018fa263f4a') + 'b44f0eb82dce8a02aa71f0eab4b0d820e5383f613becc62cc995aac8638b54ec') prepare() { export DEBIAN_BUILD="comm-esr31" @@ -59,6 +57,9 @@ prepare() { install -Dm644 "debian/app-icons/${pkgname}${i/x*/}.png" "${srcdir}/${DEBIAN_BUILD}/mail/branding/${pkgname}/content/icon${i/x*/}.png" done + # We are doing it from sed commands + rm -v debian/patches/fixes/vp8_impl.cc-backporting-naming-for-constants.patch || true + quilt push -av # Fix paths on makefile @@ -89,9 +90,6 @@ prepare() { cp "${srcdir}/mozconfig" .mozconfig - # https://bugs.archlinux.org/task/41689 - patch -Np1 -d mozilla -i ../../rhbz-966424.patch - # configure script misdetects the preprocessor without an optimization level # https://bugs.archlinux.org/task/34644 sed -i '/ac_cpp=/s/$CPPFLAGS/& -O2/' mozilla/configure diff --git a/libre/icedove/icedove.desktop b/libre/icedove/icedove.desktop index f39d5823c..1ba43e0b3 100644 --- a/libre/icedove/icedove.desktop +++ b/libre/icedove/icedove.desktop @@ -1,32 +1,5 @@ [Desktop Entry] Name=Icedove -Name[ast]=Veceru de corréu Icedove -Name[ca]=Client de correu Icedove -Name[cs]=Poštovní klient Icedove -Name[da]=Icedove - e-post/nyhedsgruppe -Name[de]=Icedove-E-Mail und -Nachrichten -Name[el]=Ηλεκτρονική αλληλογραφία Icedove -Name[es]=Cliente de correo Icedove -Name[fi]=Icedove-sähköposti -Name[fr]=Messagerie Icedove -Name[gl]=Cliente de correo Icedove -Name[he]=Icedove דוא״ל/חדשות -Name[hr]=Icedove e-pošta/novosti -Name[hu]=Icedove levelezőkliens -Name[it]=Email Icedove -Name[ja]=Icedove メールクライアント -Name[ko]=Icedove -Name[nl]=Icedove e-mail/nieuws -Name[pl]=Klient poczty Icedove -Name[pt_BR]=Cliente de E-mail Icedove -Name[ru]=Почтовый клиент Icedove -Name[sk]=Icedove - poštový klient -Name[sv]=E-postklienten Icedove -Name[ug]=Icedove ئېلخەت/خەۋەر -Name[uk]=Поштова програма Icedove -Name[vi]=Trình điện thư Icedove -Name[zh_CN]=Icedove 邮件/新闻 -Name[zh_TW]=Icedove 郵件 Comment=Send and receive mail with Icedove Comment[ast]=Lleer y escribir corréu electrónicu Comment[ca]=Llegiu i escriviu correu @@ -82,164 +55,119 @@ GenericName[uk]=Поштова програма GenericName[vi]=Phần mềm khách quản lý thư điện tử GenericName[zh_CN]=邮件新闻客户端 GenericName[zh_TW]=郵件用戶端 -Keywords=Email;E-mail;Newsgroup;Feed;RSS; -Keywords[ast]=Corréu;Corréu-e;Noticies;Discusiones;Mensaxes;Canales;RSS; -Keywords[ca]=Correu;Email;E-mail;Mailing;Llistes;Notícies;RSS; -Keywords[cs]=Email;E-mail;Pošta;Elektronická pošta;Diskusní skupiny;Čtečka;RSS; -Keywords[da]=Email;E-mail;Epost;E-post;E-brev;Newsgroup;Nyhedsgruppe;Nyhedskilde;Usenet;Feed;RSS; -Keywords[de]=Mail;E-Mail;Newsgroup;Nachrichten;Feed;RSS;Post;News;Usenet;online;lesen;schreiben; -Keywords[el]=Email;E-mail;Newsgroup;Feed;RSS;ημαιλ;Αλληλογραφία;Ροή;ΡΣΣ;Συζητήσεις;Γράμματα; -Keywords[es]=Email;Correo electrónico;Noticias;Discusiones;Mensajes;Canales;RSS; -Keywords[fi]=Mail;E-Mail;Email;Newsgroup;Feed;RSS;posti;sähköposti;maili;meili;Usenet;uutisryhmät;syöte; -Keywords[fr]=Mails;Mels;E-Mails;Emails;Courriels;Courriers;Newsgroup;Feed;RSS;Poster;Icedove;Lire;Écrire; -Keywords[he]=דוא"ל;דוא״ל;מייל;אי-מייל;אימייל;הודעות;מוזילה;תאנדרבירד;ת׳אנדרבירד;ת'אנדרבירד;ת׳אנדרברד;ת'אנדרברד;דואל; -Keywords[hr]=email;e-mail;e-pošta;pošta;RSS; -Keywords[hu]=Email;E-mail;Levél;Levelezés;Hírcsoport;Feed;Hírforrás;RSS; -Keywords[it]=Email;Mail;Posta;Newsgroup;Feed;RSS; -Keywords[is]=tölvupóstur;rafpóstur;fréttir;fréttahópar;samtöl;skilaboð;fréttastraumar;RSS; -Keywords[ja]=Eメール;イーメール;mail;e-mail;email;メール;電子メール;ニュースグループ;ネットニュース;RSS;フィードリーダー;書く;読む;Icedove; -Keywords[nl]=Email;E-mail;Newsgroup;Feed;RSS;Nieuwsgroep;Post; -Keywords[ru]=Email;E-mail;Newsgroup;Feed;RSS;почта;письма;новости;фиды; -Keywords[sk]=Email;E-mail;Elektronická pošta;Diskusné skupiny;Čítačka kanálov;RSS; -Keywords[uk]=Email;E-mail;Newsgroup;Feed;RSS;пошта;новини;подачі;стрічка; -Keywords[vi]=Mail;E-Mail;Email;Newsgroup;Feed;RSS;Thư điện tử;Gửi thư; -Keywords[zh_CN]=Mail;E-Mail;Email;Newsgroup;Feed;RSS;电子;邮件;新闻;Icedove;tb;雷鸟;电邮;邮箱;阅读器; Exec=icedove %u Terminal=false -X-MultipleArgs=false Type=Application Icon=icedove Categories=Network;Email; MimeType=message/rfc822;x-scheme-handler/mailto;application/x-xpinstall; StartupNotify=true -Actions=Compose;Contacts; +Actions=ComposeMessage;OpenAddressBook; -[Desktop Action Compose] -Name=Compose New Message -Name[af]=Skryf 'n nuwe boodskap -Name[ar]=حرر رسالة جديدة -Name[ast]=Redactar un mensaxe nuevu -Name[be]=Напісаць ліст -Name[bg]=Ново писмо -Name[bn]=নতুন বার্তা লিখুন -Name[br]=Sevel ur gemennadenn nevez -Name[bs]=Napiši novu poruku -Name[ca]=Redacta un missatge nou +[Desktop Action ComposeMessage] +Name=Write new message +Name[ar]=اكتب رسالة جديدة +Name[ast]=Redactar mensaxe nuevu +Name[be]=Напісаць новы ліст +Name[bg]=Съставяне на ново съобщение +Name[br]=Skrivañ ur gemennadenn nevez +Name[ca]=Escriu un missatge nou Name[cs]=Napsat novou zprávu -Name[cy]=Cyfansoddi Neges Newydd -Name[da]=Skriv en ny besked -Name[de]=Neue Nachricht erstellen +Name[da]=Skriv en ny meddelelse +Name[de]=Neue Nachricht verfassen Name[el]=Σύνταξη νέου μηνύματος -Name[eo]=Redakti novan mesaĝon -Name[es]=Redactar un mensaje nuevo -Name[et]=Koosta uus sõnum -Name[eu]=Mezu Berria Idatzi -Name[fi]=Luo uusi viesti -Name[fr]=Rédiger un nouveau courriel -Name[gd]=Co-chuir Teachdaireachd Ùr -Name[gl]=Redactar unha nova mensaxe -Name[he]=חיבור הודעה חדשה -Name[hi]=नया संदेश लिखें -Name[hr]=Nova poruka +Name[es_AR]=Escribir un nuevo mensaje +Name[es_ES]=Redactar nuevo mensaje +Name[et]=Kirjuta uus kiri +Name[eu]=Idatzi mezu berria +Name[fi]=Kirjoita uusi viesti +Name[fr]=Rédiger un nouveau message +Name[fy_NL]=Skriuw in nij berjocht +Name[ga_IE]=Scríobh teachtaireacht nua +Name[gd]=Sgrìobh teachdaireachd ùr +Name[gl]=Escribir unha nova mensaxe +Name[he]=כתיבת הודעה חדשה +Name[hr]=Piši novu poruku Name[hu]=Új üzenet írása -Name[hy]=Նամակ գրել -Name[id]=Buat Pesan Baru -Name[is]=Skrifa nýtt bréf -Name[it]=Componi nuovo messaggio -Name[ja]=新しいメッセージの作成 -Name[kk]=Жаңа хат жазу -Name[kn]=ಹೊಸ ಸಂದೇಶವನ್ನು ಸಂಯೋಜಿಸು -Name[ko]=새 메시지 쓰기 -Name[ku]=Peyameke nû biafirînê +Name[hy_AM]=Գրել նոր նամակ +Name[is]=SKrifa nýjan póst +Name[it]=Scrivi nuovo messaggio +Name[ja]=新しいメッセージを作成する +Name[ko]=새 메시지 작성 Name[lt]=Rašyti naują laišką -Name[lv]=Sacerēt jaunu vēstuli -Name[mk]=Состави нова порака -Name[ml]=പുതിയ സന്ദേശം രചിക്കുക -Name[mr]=नवीन संदेश लिहा. -Name[nb]=Skriv en ny melding -Name[nl]=Nieuw bericht opstellen -Name[nn]=Skriv ei ny melding -Name[pl]=Utwórz nową wiadomość -Name[pt]=Criar nova mensagem -Name[pt_BR]=Compor nova mensagem -Name[ro]=Compune un mesaj nou -Name[ru]=Написать письмо -Name[si]=නව පණිවිඩයක් අරඹන්න -Name[sk]=Napísať novú správu +Name[nb_NO]=Skriv ny melding +Name[nl]=Nieuw bericht aanmaken +Name[nn_NO]=Skriv ny melding +Name[pl]=Nowa wiadomość +Name[pt_BR]=Nova mensagem +Name[pt_PT]=Escrever nova mensagem +Name[rm]=Scriver in nov messadi +Name[ro]=Scrie un mesaj nou +Name[ru]=Создать новое сообщение +Name[si]=නව ලිපියක් ලියන්න +Name[sk]=Nová e-mailová správa Name[sl]=Sestavi novo sporočilo -Name[sq]=Krijo Mesazh të Ri -Name[sr]=Састави нову поруку -Name[sv]=Skriv nytt meddelande -Name[ta]=புதிய செய்தியை உருவாக்கு -Name[te]=కొత్త సందేశాన్ని రచించు -Name[th]=สร้างข้อความใหม่ -Name[tr]=Yeni İleti Oluştur -Name[uk]=Написати нове повідомлення -Name[zh_CN]=撰写新消息 -Name[zh_TW]=撰寫新郵件 +Name[sq]=Shkruani mesazh të ri +Name[sr]=Писање нове поруке +Name[sv_SE]=Skriv ett nytt meddelande +Name[ta_LK]=புதிய செய்தியை எழுதுக +Name[tr]=Yeni ileti yaz +Name[uk]=Написати нового листа +Name[vi]=Viết thư mới +Name[zh_CN]=编写新消息 +Name[zh_TW]=寫一封新訊息 Exec=icedove -compose -[Desktop Action Contacts] -Name=Contacts -Name[af]=Kontakte -Name[ar]=المتراسلين -Name[ast]=Contautos -Name[be]=Кантакты -Name[bg]=Контакти -Name[bn]=পরিচিতি সমূহ -Name[br]=Darempredoù -Name[bs]=Kontakti -Name[ca]=Contactes -Name[cs]=Kontakty -Name[cy]=Cysylltiadau -Name[da]=Kontakter -Name[de]=Kontakte -Name[el]=Επαφές -Name[eo]=Kontaktoj -Name[es]=Contactos -Name[et]=Kontaktid -Name[eu]=Kontaktuak -Name[fi]=Yhteystiedot -Name[fr]=Carnet d'adresses -Name[gd]=Buntanasan -Name[gl]=Contactos -Name[he]=אנשי קשר -Name[hi]=संपर्क -Name[hr]=Kontakti -Name[hu]=Névjegyek -Name[hy]=Կապորդներ -Name[id]=Kontak -Name[is]=Tengiliðir -Name[it]=Contatti -Name[ja]=連絡先 -Name[kk]=Байланыс жазулары -Name[kn]=ಸಂಪರ್ಕಗಳು -Name[ko]=연락처 -Name[ku]=Tekilî -Name[lt]=Kontaktai -Name[lv]=Kontakti -Name[mk]=Контакти -Name[ml]=വിലാസങ്ങള്‍ -Name[mr]=संपर्क -Name[nb]=Kontakter -Name[nl]=Contacten -Name[nn]=Kontaktar -Name[pl]=Kontakty -Name[pt]=Contactos -Name[pt_BR]=Contatos -Name[ro]=Contacte -Name[ru]=Контакты -Name[si]=සබඳතා -Name[sk]=Kontakty -Name[sl]=Stiki -Name[sq]=Kontaktet -Name[sr]=Контакти -Name[sv]=Kontakter -Name[ta]=தொடர்புகள் -Name[te]=పరిచయాలు -Name[th]=รายชื่อติดต่อ -Name[tr]=Kişiler -Name[uk]=Контакти -Name[zh_CN]=联系人 -Name[zh_TW]=連絡人 +[Desktop Action OpenAddressBook] +Name=Open address book +Name[ar]=افتح دفتر العناوين +Name[ast]=Abrir llibreta de direiciones +Name[be]=Адкрыць адрасную кнігу +Name[bg]=Отваряне на адресник +Name[br]=Digeriñ ur c'harned chomlec'hioù +Name[ca]=Obre la llibreta d'adreces +Name[cs]=Otevřít Adresář +Name[da]=Åbn adressebog +Name[de]=Adressbuch öffnen +Name[el]=Άνοιγμα ευρετηρίου διευθύνσεων +Name[es_AR]=Abrir libreta de direcciones +Name[es_ES]=Abrir libreta de direcciones +Name[et]=Ava aadressiraamat +Name[eu]=Ireki helbide-liburua +Name[fi]=Avaa osoitekirja +Name[fr]=Ouvrir un carnet d'adresses +Name[fy_NL]=Iepenje adresboek +Name[ga_IE]=Oscail leabhar seoltaí +Name[gd]=Fosgail leabhar-sheòlaidhean +Name[gl]=Abrir a axenda de enderezos +Name[he]=פתיחת ספר כתובות +Name[hr]=Otvori adresar +Name[hu]=Címjegyzék megnyitása +Name[hy_AM]=Բացել Հասցեագիրքը +Name[is]=Opna nafnaskrá +Name[it]=Apri rubrica +Name[ja]=アドレス帳を開く +Name[ko]=주소록 열기 +Name[lt]=Atverti adresų knygą +Name[nb_NO]=Åpne adressebok +Name[nl]=Adresboek openen +Name[nn_NO]=Opne adressebok +Name[pl]=Książka adresowa +Name[pt_BR]=Catálogo de endereços +Name[pt_PT]=Abrir livro de endereços +Name[rm]=Avrir il cudeschet d'adressas +Name[ro]=Deschide agenda de contacte +Name[ru]=Открыть адресную книгу +Name[si]=ලිපින පොත විවෘත කරන්න +Name[sk]=Otvoriť adresár +Name[sl]=Odpri adressar +Name[sq]=Hapni libër adresash +Name[sr]=Отвори адресар +Name[sv_SE]=Öppna adressboken +Name[ta_LK]=முகவரி பத்தகத்தை திறக்க +Name[tr]=Adres defterini aç +Name[uk]=Відкрити адресну книгу +Name[vi]=Mở sổ địa chỉ +Name[zh_CN]=打开通讯录 +Name[zh_TW]=開啟通訊錄 Exec=icedove -addressbook diff --git a/libre/icedove/rhbz-966424.patch b/libre/icedove/rhbz-966424.patch deleted file mode 100644 index c4c332e9e..000000000 --- a/libre/icedove/rhbz-966424.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/toolkit/modules/CertUtils.jsm -+++ b/toolkit/modules/CertUtils.jsm -@@ -170,17 +170,19 @@ this.checkCert = - issuerCert = issuerCert.QueryInterface(Ci.nsIX509Cert3); - var tokenNames = issuerCert.getAllTokenNames({}); - - if (!tokenNames || !tokenNames.some(isBuiltinToken)) - throw new Ce(certNotBuiltInErr, Cr.NS_ERROR_ABORT); - } - - function isBuiltinToken(tokenName) { -- return tokenName == "Builtin Object Token"; -+ return tokenName == "Builtin Object Token" || -+ tokenName == "Default Trust" || -+ tokenName == "System Trust"; - } - - /** - * This class implements nsIBadCertListener. Its job is to prevent "bad cert" - * security dialogs from being shown to the user. It is better to simply fail - * if the certificate is bad. See bug 304286. - * - * @param aAllowNonBuiltInCerts (optional) diff --git a/nonprism/icedove/PKGBUILD b/nonprism/icedove/PKGBUILD index 3ef75b2fa..9db1e0a0d 100644 --- a/nonprism/icedove/PKGBUILD +++ b/nonprism/icedove/PKGBUILD @@ -3,7 +3,7 @@ # We're getting this from Debian Sid _debname=icedove -_debver=31.6.0 +_debver=31.7.0 _debrel=deb1 _debrepo=http://ftp.debian.org/debian/pool/main/ debfile() { echo $@|sed -r 's@(.).*@\1/&/&@'; } @@ -11,7 +11,7 @@ debfile() { echo $@|sed -r 's@(.).*@\1/&/&@'; } pkgname=${_debname} epoch=1 pkgver=${_debver}.${_debrel} -pkgrel=2.nonprism1 +pkgrel=1.nonprism1 pkgdesc="A libre version of Debian Icedove, the standalone mail/news reader based on Mozilla Thunderbird, without support for unsafe and dangerous for privacy protocols" arch=('i686' 'x86_64' 'mips64el') license=('MPL' 'GPL' 'LGPL') @@ -28,16 +28,14 @@ source=("${_debrepo}/`debfile ${_debname}`_${_debver}.orig.tar.xz" mozconfig ${pkgname}.desktop ${pkgname}-install-dir.patch - vendor.js - rhbz-966424.patch) + vendor.js) options=(!emptydirs) -sha256sums=('9011da6632434d6ee991cc69f4e040a194d998ce3a04e5c3a05f21fc361124dc' - 'ac73365adcccf126b97432cfd60828da667b2eb82512ae252cf577939d666fd9' +sha256sums=('00ce17575690400e22e7ce21dc5b3b4f71092b7708ee9aad74448d1401da8794' + '04c30b4e72819b764bc463d36c39f55741d3e47ae994ba89fd14e63fe32c6561' '09a0041f7f12498d933284b3d3a44e19002515accaff767d145a8f404b79e86a' - 'a0be56fc87f255804e00e7c85abbc4731ebdaa8938858f1f8ac47dd2f17c0b8b' + '0b0d25067c64c6b829c84e5259ffca978e3971f85acc8483f47bdbed5b0b5b6a' '24599eab8862476744fe1619a9a53a5b8cdcab30b3fc5767512f31d3529bd05d' - 'b44f0eb82dce8a02aa71f0eab4b0d820e5383f613becc62cc995aac8638b54ec' - '746cb474c5a2c26fc474256e430e035e604b71b27df1003d4af85018fa263f4a') + 'b44f0eb82dce8a02aa71f0eab4b0d820e5383f613becc62cc995aac8638b54ec') prepare() { export DEBIAN_BUILD="comm-esr31" @@ -59,6 +57,9 @@ prepare() { install -Dm644 "debian/app-icons/${pkgname}${i/x*/}.png" "${srcdir}/${DEBIAN_BUILD}/mail/branding/${pkgname}/content/icon${i/x*/}.png" done + # We are doing it from sed commands + rm -v debian/patches/fixes/vp8_impl.cc-backporting-naming-for-constants.patch || true + quilt push -av # Fix paths on makefile @@ -105,9 +106,6 @@ prepare() { cp "${srcdir}/mozconfig" .mozconfig - # https://bugs.archlinux.org/task/41689 - patch -Np1 -d mozilla -i ../../rhbz-966424.patch - # configure script misdetects the preprocessor without an optimization level # https://bugs.archlinux.org/task/34644 sed -i '/ac_cpp=/s/$CPPFLAGS/& -O2/' mozilla/configure diff --git a/nonprism/icedove/icedove.desktop b/nonprism/icedove/icedove.desktop index f39d5823c..1ba43e0b3 100644 --- a/nonprism/icedove/icedove.desktop +++ b/nonprism/icedove/icedove.desktop @@ -1,32 +1,5 @@ [Desktop Entry] Name=Icedove -Name[ast]=Veceru de corréu Icedove -Name[ca]=Client de correu Icedove -Name[cs]=Poštovní klient Icedove -Name[da]=Icedove - e-post/nyhedsgruppe -Name[de]=Icedove-E-Mail und -Nachrichten -Name[el]=Ηλεκτρονική αλληλογραφία Icedove -Name[es]=Cliente de correo Icedove -Name[fi]=Icedove-sähköposti -Name[fr]=Messagerie Icedove -Name[gl]=Cliente de correo Icedove -Name[he]=Icedove דוא״ל/חדשות -Name[hr]=Icedove e-pošta/novosti -Name[hu]=Icedove levelezőkliens -Name[it]=Email Icedove -Name[ja]=Icedove メールクライアント -Name[ko]=Icedove -Name[nl]=Icedove e-mail/nieuws -Name[pl]=Klient poczty Icedove -Name[pt_BR]=Cliente de E-mail Icedove -Name[ru]=Почтовый клиент Icedove -Name[sk]=Icedove - poštový klient -Name[sv]=E-postklienten Icedove -Name[ug]=Icedove ئېلخەت/خەۋەر -Name[uk]=Поштова програма Icedove -Name[vi]=Trình điện thư Icedove -Name[zh_CN]=Icedove 邮件/新闻 -Name[zh_TW]=Icedove 郵件 Comment=Send and receive mail with Icedove Comment[ast]=Lleer y escribir corréu electrónicu Comment[ca]=Llegiu i escriviu correu @@ -82,164 +55,119 @@ GenericName[uk]=Поштова програма GenericName[vi]=Phần mềm khách quản lý thư điện tử GenericName[zh_CN]=邮件新闻客户端 GenericName[zh_TW]=郵件用戶端 -Keywords=Email;E-mail;Newsgroup;Feed;RSS; -Keywords[ast]=Corréu;Corréu-e;Noticies;Discusiones;Mensaxes;Canales;RSS; -Keywords[ca]=Correu;Email;E-mail;Mailing;Llistes;Notícies;RSS; -Keywords[cs]=Email;E-mail;Pošta;Elektronická pošta;Diskusní skupiny;Čtečka;RSS; -Keywords[da]=Email;E-mail;Epost;E-post;E-brev;Newsgroup;Nyhedsgruppe;Nyhedskilde;Usenet;Feed;RSS; -Keywords[de]=Mail;E-Mail;Newsgroup;Nachrichten;Feed;RSS;Post;News;Usenet;online;lesen;schreiben; -Keywords[el]=Email;E-mail;Newsgroup;Feed;RSS;ημαιλ;Αλληλογραφία;Ροή;ΡΣΣ;Συζητήσεις;Γράμματα; -Keywords[es]=Email;Correo electrónico;Noticias;Discusiones;Mensajes;Canales;RSS; -Keywords[fi]=Mail;E-Mail;Email;Newsgroup;Feed;RSS;posti;sähköposti;maili;meili;Usenet;uutisryhmät;syöte; -Keywords[fr]=Mails;Mels;E-Mails;Emails;Courriels;Courriers;Newsgroup;Feed;RSS;Poster;Icedove;Lire;Écrire; -Keywords[he]=דוא"ל;דוא״ל;מייל;אי-מייל;אימייל;הודעות;מוזילה;תאנדרבירד;ת׳אנדרבירד;ת'אנדרבירד;ת׳אנדרברד;ת'אנדרברד;דואל; -Keywords[hr]=email;e-mail;e-pošta;pošta;RSS; -Keywords[hu]=Email;E-mail;Levél;Levelezés;Hírcsoport;Feed;Hírforrás;RSS; -Keywords[it]=Email;Mail;Posta;Newsgroup;Feed;RSS; -Keywords[is]=tölvupóstur;rafpóstur;fréttir;fréttahópar;samtöl;skilaboð;fréttastraumar;RSS; -Keywords[ja]=Eメール;イーメール;mail;e-mail;email;メール;電子メール;ニュースグループ;ネットニュース;RSS;フィードリーダー;書く;読む;Icedove; -Keywords[nl]=Email;E-mail;Newsgroup;Feed;RSS;Nieuwsgroep;Post; -Keywords[ru]=Email;E-mail;Newsgroup;Feed;RSS;почта;письма;новости;фиды; -Keywords[sk]=Email;E-mail;Elektronická pošta;Diskusné skupiny;Čítačka kanálov;RSS; -Keywords[uk]=Email;E-mail;Newsgroup;Feed;RSS;пошта;новини;подачі;стрічка; -Keywords[vi]=Mail;E-Mail;Email;Newsgroup;Feed;RSS;Thư điện tử;Gửi thư; -Keywords[zh_CN]=Mail;E-Mail;Email;Newsgroup;Feed;RSS;电子;邮件;新闻;Icedove;tb;雷鸟;电邮;邮箱;阅读器; Exec=icedove %u Terminal=false -X-MultipleArgs=false Type=Application Icon=icedove Categories=Network;Email; MimeType=message/rfc822;x-scheme-handler/mailto;application/x-xpinstall; StartupNotify=true -Actions=Compose;Contacts; +Actions=ComposeMessage;OpenAddressBook; -[Desktop Action Compose] -Name=Compose New Message -Name[af]=Skryf 'n nuwe boodskap -Name[ar]=حرر رسالة جديدة -Name[ast]=Redactar un mensaxe nuevu -Name[be]=Напісаць ліст -Name[bg]=Ново писмо -Name[bn]=নতুন বার্তা লিখুন -Name[br]=Sevel ur gemennadenn nevez -Name[bs]=Napiši novu poruku -Name[ca]=Redacta un missatge nou +[Desktop Action ComposeMessage] +Name=Write new message +Name[ar]=اكتب رسالة جديدة +Name[ast]=Redactar mensaxe nuevu +Name[be]=Напісаць новы ліст +Name[bg]=Съставяне на ново съобщение +Name[br]=Skrivañ ur gemennadenn nevez +Name[ca]=Escriu un missatge nou Name[cs]=Napsat novou zprávu -Name[cy]=Cyfansoddi Neges Newydd -Name[da]=Skriv en ny besked -Name[de]=Neue Nachricht erstellen +Name[da]=Skriv en ny meddelelse +Name[de]=Neue Nachricht verfassen Name[el]=Σύνταξη νέου μηνύματος -Name[eo]=Redakti novan mesaĝon -Name[es]=Redactar un mensaje nuevo -Name[et]=Koosta uus sõnum -Name[eu]=Mezu Berria Idatzi -Name[fi]=Luo uusi viesti -Name[fr]=Rédiger un nouveau courriel -Name[gd]=Co-chuir Teachdaireachd Ùr -Name[gl]=Redactar unha nova mensaxe -Name[he]=חיבור הודעה חדשה -Name[hi]=नया संदेश लिखें -Name[hr]=Nova poruka +Name[es_AR]=Escribir un nuevo mensaje +Name[es_ES]=Redactar nuevo mensaje +Name[et]=Kirjuta uus kiri +Name[eu]=Idatzi mezu berria +Name[fi]=Kirjoita uusi viesti +Name[fr]=Rédiger un nouveau message +Name[fy_NL]=Skriuw in nij berjocht +Name[ga_IE]=Scríobh teachtaireacht nua +Name[gd]=Sgrìobh teachdaireachd ùr +Name[gl]=Escribir unha nova mensaxe +Name[he]=כתיבת הודעה חדשה +Name[hr]=Piši novu poruku Name[hu]=Új üzenet írása -Name[hy]=Նամակ գրել -Name[id]=Buat Pesan Baru -Name[is]=Skrifa nýtt bréf -Name[it]=Componi nuovo messaggio -Name[ja]=新しいメッセージの作成 -Name[kk]=Жаңа хат жазу -Name[kn]=ಹೊಸ ಸಂದೇಶವನ್ನು ಸಂಯೋಜಿಸು -Name[ko]=새 메시지 쓰기 -Name[ku]=Peyameke nû biafirînê +Name[hy_AM]=Գրել նոր նամակ +Name[is]=SKrifa nýjan póst +Name[it]=Scrivi nuovo messaggio +Name[ja]=新しいメッセージを作成する +Name[ko]=새 메시지 작성 Name[lt]=Rašyti naują laišką -Name[lv]=Sacerēt jaunu vēstuli -Name[mk]=Состави нова порака -Name[ml]=പുതിയ സന്ദേശം രചിക്കുക -Name[mr]=नवीन संदेश लिहा. -Name[nb]=Skriv en ny melding -Name[nl]=Nieuw bericht opstellen -Name[nn]=Skriv ei ny melding -Name[pl]=Utwórz nową wiadomość -Name[pt]=Criar nova mensagem -Name[pt_BR]=Compor nova mensagem -Name[ro]=Compune un mesaj nou -Name[ru]=Написать письмо -Name[si]=නව පණිවිඩයක් අරඹන්න -Name[sk]=Napísať novú správu +Name[nb_NO]=Skriv ny melding +Name[nl]=Nieuw bericht aanmaken +Name[nn_NO]=Skriv ny melding +Name[pl]=Nowa wiadomość +Name[pt_BR]=Nova mensagem +Name[pt_PT]=Escrever nova mensagem +Name[rm]=Scriver in nov messadi +Name[ro]=Scrie un mesaj nou +Name[ru]=Создать новое сообщение +Name[si]=නව ලිපියක් ලියන්න +Name[sk]=Nová e-mailová správa Name[sl]=Sestavi novo sporočilo -Name[sq]=Krijo Mesazh të Ri -Name[sr]=Састави нову поруку -Name[sv]=Skriv nytt meddelande -Name[ta]=புதிய செய்தியை உருவாக்கு -Name[te]=కొత్త సందేశాన్ని రచించు -Name[th]=สร้างข้อความใหม่ -Name[tr]=Yeni İleti Oluştur -Name[uk]=Написати нове повідомлення -Name[zh_CN]=撰写新消息 -Name[zh_TW]=撰寫新郵件 +Name[sq]=Shkruani mesazh të ri +Name[sr]=Писање нове поруке +Name[sv_SE]=Skriv ett nytt meddelande +Name[ta_LK]=புதிய செய்தியை எழுதுக +Name[tr]=Yeni ileti yaz +Name[uk]=Написати нового листа +Name[vi]=Viết thư mới +Name[zh_CN]=编写新消息 +Name[zh_TW]=寫一封新訊息 Exec=icedove -compose -[Desktop Action Contacts] -Name=Contacts -Name[af]=Kontakte -Name[ar]=المتراسلين -Name[ast]=Contautos -Name[be]=Кантакты -Name[bg]=Контакти -Name[bn]=পরিচিতি সমূহ -Name[br]=Darempredoù -Name[bs]=Kontakti -Name[ca]=Contactes -Name[cs]=Kontakty -Name[cy]=Cysylltiadau -Name[da]=Kontakter -Name[de]=Kontakte -Name[el]=Επαφές -Name[eo]=Kontaktoj -Name[es]=Contactos -Name[et]=Kontaktid -Name[eu]=Kontaktuak -Name[fi]=Yhteystiedot -Name[fr]=Carnet d'adresses -Name[gd]=Buntanasan -Name[gl]=Contactos -Name[he]=אנשי קשר -Name[hi]=संपर्क -Name[hr]=Kontakti -Name[hu]=Névjegyek -Name[hy]=Կապորդներ -Name[id]=Kontak -Name[is]=Tengiliðir -Name[it]=Contatti -Name[ja]=連絡先 -Name[kk]=Байланыс жазулары -Name[kn]=ಸಂಪರ್ಕಗಳು -Name[ko]=연락처 -Name[ku]=Tekilî -Name[lt]=Kontaktai -Name[lv]=Kontakti -Name[mk]=Контакти -Name[ml]=വിലാസങ്ങള്‍ -Name[mr]=संपर्क -Name[nb]=Kontakter -Name[nl]=Contacten -Name[nn]=Kontaktar -Name[pl]=Kontakty -Name[pt]=Contactos -Name[pt_BR]=Contatos -Name[ro]=Contacte -Name[ru]=Контакты -Name[si]=සබඳතා -Name[sk]=Kontakty -Name[sl]=Stiki -Name[sq]=Kontaktet -Name[sr]=Контакти -Name[sv]=Kontakter -Name[ta]=தொடர்புகள் -Name[te]=పరిచయాలు -Name[th]=รายชื่อติดต่อ -Name[tr]=Kişiler -Name[uk]=Контакти -Name[zh_CN]=联系人 -Name[zh_TW]=連絡人 +[Desktop Action OpenAddressBook] +Name=Open address book +Name[ar]=افتح دفتر العناوين +Name[ast]=Abrir llibreta de direiciones +Name[be]=Адкрыць адрасную кнігу +Name[bg]=Отваряне на адресник +Name[br]=Digeriñ ur c'harned chomlec'hioù +Name[ca]=Obre la llibreta d'adreces +Name[cs]=Otevřít Adresář +Name[da]=Åbn adressebog +Name[de]=Adressbuch öffnen +Name[el]=Άνοιγμα ευρετηρίου διευθύνσεων +Name[es_AR]=Abrir libreta de direcciones +Name[es_ES]=Abrir libreta de direcciones +Name[et]=Ava aadressiraamat +Name[eu]=Ireki helbide-liburua +Name[fi]=Avaa osoitekirja +Name[fr]=Ouvrir un carnet d'adresses +Name[fy_NL]=Iepenje adresboek +Name[ga_IE]=Oscail leabhar seoltaí +Name[gd]=Fosgail leabhar-sheòlaidhean +Name[gl]=Abrir a axenda de enderezos +Name[he]=פתיחת ספר כתובות +Name[hr]=Otvori adresar +Name[hu]=Címjegyzék megnyitása +Name[hy_AM]=Բացել Հասցեագիրքը +Name[is]=Opna nafnaskrá +Name[it]=Apri rubrica +Name[ja]=アドレス帳を開く +Name[ko]=주소록 열기 +Name[lt]=Atverti adresų knygą +Name[nb_NO]=Åpne adressebok +Name[nl]=Adresboek openen +Name[nn_NO]=Opne adressebok +Name[pl]=Książka adresowa +Name[pt_BR]=Catálogo de endereços +Name[pt_PT]=Abrir livro de endereços +Name[rm]=Avrir il cudeschet d'adressas +Name[ro]=Deschide agenda de contacte +Name[ru]=Открыть адресную книгу +Name[si]=ලිපින පොත විවෘත කරන්න +Name[sk]=Otvoriť adresár +Name[sl]=Odpri adressar +Name[sq]=Hapni libër adresash +Name[sr]=Отвори адресар +Name[sv_SE]=Öppna adressboken +Name[ta_LK]=முகவரி பத்தகத்தை திறக்க +Name[tr]=Adres defterini aç +Name[uk]=Відкрити адресну книгу +Name[vi]=Mở sổ địa chỉ +Name[zh_CN]=打开通讯录 +Name[zh_TW]=開啟通訊錄 Exec=icedove -addressbook diff --git a/nonprism/icedove/rhbz-966424.patch b/nonprism/icedove/rhbz-966424.patch deleted file mode 100644 index c4c332e9e..000000000 --- a/nonprism/icedove/rhbz-966424.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/toolkit/modules/CertUtils.jsm -+++ b/toolkit/modules/CertUtils.jsm -@@ -170,17 +170,19 @@ this.checkCert = - issuerCert = issuerCert.QueryInterface(Ci.nsIX509Cert3); - var tokenNames = issuerCert.getAllTokenNames({}); - - if (!tokenNames || !tokenNames.some(isBuiltinToken)) - throw new Ce(certNotBuiltInErr, Cr.NS_ERROR_ABORT); - } - - function isBuiltinToken(tokenName) { -- return tokenName == "Builtin Object Token"; -+ return tokenName == "Builtin Object Token" || -+ tokenName == "Default Trust" || -+ tokenName == "System Trust"; - } - - /** - * This class implements nsIBadCertListener. Its job is to prevent "bad cert" - * security dialogs from being shown to the user. It is better to simply fail - * if the certificate is bad. See bug 304286. - * - * @param aAllowNonBuiltInCerts (optional) -- cgit v1.2.3 From 64154e3650850f02ae065cd6afd18029f186772f Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Fri, 22 May 2015 14:54:27 -0300 Subject: icedove-l10n-1:31.7.0.deb1-1: updating version --- libre/icedove-l10n/PKGBUILD | 114 ++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 57 deletions(-) (limited to 'libre') diff --git a/libre/icedove-l10n/PKGBUILD b/libre/icedove-l10n/PKGBUILD index b2a89bb28..476ea454e 100644 --- a/libre/icedove-l10n/PKGBUILD +++ b/libre/icedove-l10n/PKGBUILD @@ -4,8 +4,8 @@ epoch=1 _pkgbase=icedove pkgbase=$_pkgbase-l10n -_pkgver=31.6.0 -pkgver=31.6.0.deb1 +_pkgver=31.7.0 +pkgver=31.7.0.deb1 pkgrel=1 pkgdesc="Language pack for Debian ${_pkgbase^}." arch=('any') @@ -114,58 +114,58 @@ _package() { sha256sums=('49b419449431d8d64e20427a2e7105e3ac1ffc41e677a5f9a8eb276f5b82df4a' 'acc2cf95661be7cb8928fca89e08d0681685409ff2428e4e3d25baf1af427b38' - '469ba3e8822685b1b16131da5c50dd3b7372cc92a932f61569d9734daaea2eac' - '26bccf23d234e2ecef00733909bb432969c72cb74527adecc2ae59022b43ca97' - '95540e5f60de453d2281951beb7df8bd78ca91bc88437fcbbc6bb16844d31b90' - 'd7e08d395b768f1de63ced97518f8dbf6a747273264fae3d241cc0ae17a3e867' - '2e69e0b9d95a4018d658cf831dcfd7c8897534ce078d492a96a215dee9bb940c' - '4b7d3ef6c5df11058772483fe7945c3691e2cd8e8236963f4d19b23b4bb1f329' - '735bf46013112a854b3f283714bb0847c475cc068e63c6a3485f1631feae27bf' - '23619105a28386b9cd927f65fd59223a1378fc09134b00864cd21d119c762857' - '117129fbc2fdd5e6572942b600b1049189a7fd91852011c5c92c44bf042362a3' - '2d181ce84bf62a45118941f52e70a5987c610356dca4df48e0e88fc95b45da37' - '90608f577f5ef31c9003b6e2ea937dbf0435f3c06aa1eba561bbf8309568c90c' - 'fde93bbf9ff06e121870bf496418bc1703e0a2d0c5f27bcc3d130d2304921f67' - '11e68ba7462dc8df41a43a1e4c04f6865c8f46e96295abfd6366559204c89cd9' - 'b600ba8e2543eedc1833f6b936a70f25b9553dbc6835879d65dc14749e6db4fb' - '9017824378160bfe10d41bb2decbbc5a60a4db9199bff614c2b63cf40b3d310d' - 'd81f38f094ad0b962bc8fa6e11b57031748f3ca52c0ae0e335d704210e1f63f0' - 'a4f47a340b5623317756cd861705e96aba343a3175bc738bfdc72634859deed2' - '3a66f399789c0375d5e908a23ab306fb64eab8a4c35588112b0c83e027635987' - '38f52c3ae85908354964f816f3e83b12c26899b3112cd3de6d7c2672a35e86dc' - '0deaef241661c4fb34b159528297b7a922a5bacc103fd62e6d5fa73cb129a2d3' - '628c3682e167f87b50aed76ac02fe5e069015fb850eabdc79bfe41d0d2b239e0' - '41cd7af4039f99ba71d30c61764c2b5079c5b23aa6d8bbeb1d7eb5ba76d9915a' - '80788599aba0058d055e14c6931adfc5c3fcafdab2b3f82c765e82ba85cd6618' - 'f2b3dc16e00792dcb23da705428ac694510df99a2365eb92587d814015f91c33' - 'e866fdc131fdb5e384aa3905f41bea5498941a6cbfa73af9c933e3368869c30b' - '975596a745b826d545ab70c000663a3464b22edefb23e97a128d1d8f3c1c3020' - '99288ff622c443eb2701c5cc041705ecbb02afd99d59276c0aea04147f955335' - '746d6a546528e49a5f66a88704a9adfb2d6605dd1148de42ec1ce8427190176d' - '68ba2fd9b48b844d5d3470986ed344917a8021794fe67108c626e5945a2a1e7f' - '48adc76231ef558458a23d91c1055e22b3100412499344cb2f5f17ebbed96c88' - '282169e68a88f96299feaf19cf8c779817c29fa0f9e381691b912988562e3009' - 'f42996017694aa23dfa6d785f165461347cbefc1841ba841d403cc9a7e6cd9cd' - '71d61ba20fb60f7f57e0cc3633f6e4cdbff36fd5a55392646db97d162bd452f2' - '7a135a00b3106249147d5d023e17710266c9f32b0e55496d59387571164db82d' - 'ae50880cfada890136723afd10f7e4ff6edb958bc8cce8c34c9298d8e34d20d3' - '1b6b140130026c86e2f9aacc10fa6e642cee186c67c2a23b350e9bfea3ac828e' - 'b4da0cd42307642492a73ef30e652394927530471b1d71897ce6fc28c53f25d9' - 'ad3e92b8ec4caae1d2228e33e4c55ab46f7ece5eefb5ead17ff76c092fc75be3' - '1a67a4855350a6e13ffcd15da4a546bd830bc4cdb6cc69e75f769c04415c9e45' - 'b3a9c93f19297092f77c3018ccff6b863c333fc60edcbfd7baa503d290cbb091' - '3e511b47615ff491d99d524cdfea9aaf97ec6d2fa44080b32a512a7c8a9a54b9' - 'fbe0f58f8ad2bce7d9a589cdff6bd4f25661aaf8ee3984ea0ecb1390b21a89ff' - '0faa4cea2a9b11329f337c583f9660afd3b243560e6c46709b141192f1957b02' - '2314272354b7eee77ad7ac35c76efcf4d72951062f9ec55ddce0fcb4ae69a6c6' - '0597c8b782f7c5386e926a27798e7f35a39d623e8c3056b1e9a7ce2849268541' - '2f49d57813524da0e686587dc2a442eaec1ba90b53cab4294a99833ba62d8aed' - 'b2df645d03d2b103760a8372792183ad7202c96cbbcd00334ebf15c0532576d8' - '95a3053e4749dd6236e4aa9d23f0fac65151cfb494103c550ac79b644c3a14db' - 'aac574c17163d1ba286677c696d654e667afe9d7eee48b89cf0cfdca86ccb03c' - '9134c27513ee9f4eb51a7b343624e73ba0e74f00372b3fe0dc31f317843da181' - '4f82c2e827b5b5955e476cd92ea5ee3e6ded7b7d608dede7fadb04423704249a' - '2b53c55a0301cf5d5fa64473d1dc97706fef163d96d2af013a90b950fc4be0fd' - '9ff8daa9ee8fcbae042c582e8038505775c0bff64f02d5d482ad275928e3af3b' - 'b2a613f62cb45b4c136cc402e7e54f1737358c63466944d4753b47e7b212e84e' - 'a424e49bb2fa28e4d87e94714d3076cd756760316a5499ae5e7d0cf3e7d50efc') + 'fac353e1067852ccac7bc23a958c54fdebd2aad30ad9551a07deb23811046d79' + '4e39fb7792c7fe787bb9d9f3a03ac57da15e9b353a51f1602afcffc3e0e0ffa8' + '8be5b81c0a747d89ff9f586d726706718711a01ffd70ecbed9fe00352fb795dd' + '7ab3641502204c37108430f5be2f78a161b1aa5a63561c8edcf0186a7f509df6' + '51cf109e8416775e656a1431630f3f4a6b0bde3e44744449283d0666284698bf' + '97bbaea547340a56f528d8675b04a596369fb9b63245e20acd76d74211f7a668' + '49d3df068e9edcf17ed99754bd45c7d00c50f4bacd7a5484ab86018197258523' + 'd491ebf429f56ad21632bc476f9364857ee838a330ff1b966cae2e8ec5a944e8' + 'c95a6ce7d22eca56f365f05805393a1b52a5427af02a447f9dba1cd1559dd7c7' + '0debd56af6d8872d525e62ae8fd609620c3a66a425817dec83d701346fd766ba' + '9b3ca0a7df6b8bc91274b2b757dfb909beb04815cf51b377b22755114776b536' + 'd8d4dc74889792dc9b434f11a8934d5363dafb07aada75068809f1d3ceba7d66' + 'c4e5def480042a55d8532129f3bd5226004b98f5dd3991eeb429a35152f4391e' + 'e0bf50d99447934d0f9865329469559308ab54c32d2d64321a9742b3aa4be063' + '162a5c3879bb4d826b8cfea0dd68cf13f29d417bac79cc2482dd78d76cc0a8f7' + '9f5846d2147eeb8a834a282abc80ef1cd58389faaf4a0dfedfc4e91cd28faaf5' + 'bba78265515862435a7aa19345460c0bdd192be207550f6a9ac0cdb7de535ac8' + 'bdf3d4bf05bc66951c9d861af635c791fd3513f578fe32a9ccc150aa81ba6304' + '5700997d79942d74db684fddb255ee1e5a1b10b0c7c0df875b917dbba91f9607' + 'ed3f3e4bbba12218a0025747257cdaefceb4f37ce65fbf8e3ec1746cacf62d62' + '788127820d6404540b698794a9008990f77005056ec1f15da05785087729c178' + 'f688f29b6e4032d6f6fd9b3e7ae20d2f94f7ae34e977bcb1ea1e9b4393ac9f4d' + '52ba67336de4d8d19ac1d29d22df362af9e8b43a2cb800a0303b51e0b6d4c4fb' + '39519209cf6c19208e8c677439b3cad194d9d14f7ff3814c189890d6285b7af7' + '7abab0668491b42dff80e8b656407b9489f8a133a58f0ca42f8c83a1973efd77' + 'ec4d3c63698bc825fee4a2dedde66a7796fef0efee8df307d8f233f382ba784a' + 'f22b7f8a56d6b92448d4b1cf471fdad56cef13e8668a472e833a8efc8400b53f' + '40c62742c10f08f1b93e68b026b48b849dcf323f99987720be19c0bc0f4fbb7f' + '1007cd1f3f72deecdbfbb3ec54837955f53235de4b39405158eec9dd74750246' + '6de47224c4342a1fc1c81d8ec0bab90cdacb4b4e54709e9590c2bd341fbfbae7' + '4e3f6637cccafab04d665bb66b2d808797384c3b322a4375efcb9a3be480fe7f' + '6c962ee2ce9051223897ace9fa6d7c60ffb7e95b103a52bad0f17803efcfeaf2' + '9dbde5ddc20a9512320490318f5f6278d5626357f3b17401482a439a4f6be654' + '51a38f39dfc18d945a0985a23d0b7770f8fe3cebf8a28f22fd92bb288345a9b0' + '784ba5505afef70f492a85651c632da974c01bf1c5a945ff132df40b077304d7' + 'cfd312de7632a96facd36acdc00a04bc571101d655c5c8f70300d3f982b58366' + 'e444889660a60b44a3e5e6fc94972e2b8a2b97e0fa8959b41bcacacfc8be931d' + '3ef71ff4f72e28f15ea76764be9179cefdbf92a2270e87dad557cbf6d6c44f36' + '298f9a4a205a77e471f96e38d12dbba00b6fb9ddf89b496e8b5eb106d1f33c97' + 'e01d684612fd224536e9cb21f44ace5cab81bf8fd15e8e5265847df1b2407a59' + '0d2606836428595232daf0aedbafea4935e641658712fd99e34668e686c0d2e7' + '7de4b8e3ffcf3ac7ced5aeae0ca84d1e9c8603646e54473665505e1f1ac66925' + '38b372432b02c42703e3f425946cee6a42918d574f7bff7df5f9997ddb076f64' + '3441d57aeedf15c5a29800e8f544b8571d41e5ed5a381d8bb2087cda97074970' + 'dcd56d713daa7b6fb03d64219797e159eab8bef2e7eb9bd7999c0b285a24d153' + '7e7fb8287b9255aa8988bf63677e0bed8ae30c0da5ac7d83ba1300ba2bca41d3' + 'b9270889a4905233e450be25d61e4a1359a057bc6c021d5aba23a941cde56123' + '0ef471cf54c052214d5169189a72efc0e8d65801e482aeff413ffc7c822c1651' + '803529203aded6bf1194a6d5d575f5e16f8a4a249a68878650c5469e92512923' + '3529d8a55ea5458edf24059d55178b6c4935aa82b604bc1c46e4b4bffb88234b' + 'e83e64f528b12b1550efb28ba4dea51e7912ab2af470c1382d78e01d9dc3a3ff' + '12c2001834af439d1a0f95ed3f416788672d41c5b02481d26e54f66e721c83a6' + '7a20d9842117105f4ac641d602977cf20d4149564593adba0f3415976fd7b52d' + 'f582fac503f385ceb59761134ed24170ded9f65861106ff77219040b169e6a37' + '3b60993a3c85f61ef57b02334d3a71d864e9e6609ec29f398c1f60094cad43a3') -- cgit v1.2.3 From a8661be3e2bda96404292baf1daa51e8bb87dd06 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Fri, 22 May 2015 14:57:11 -0300 Subject: linux-libre-grsec{,-knock}-4.0.4_gnu.201505182014-1: updating version --- .../4.0-rc7-37af2c8aae-loongson-community.patch | 12143 ------------------ .../4.0.2-ae91f13af5-loongson-community.patch | 12144 ++++++++++++++++++ kernels/linux-libre-grsec-knock/PKGBUILD | 20 +- kernels/linux-libre-grsec-knock/config.i686 | 122 +- kernels/linux-libre-grsec-knock/config.mips64el | 99 +- kernels/linux-libre-grsec-knock/config.x86_64 | 122 +- .../4.0-rc7-37af2c8aae-loongson-community.patch | 12143 ------------------ .../4.0.2-ae91f13af5-loongson-community.patch | 12168 +++++++++++++++++++ libre/linux-libre-grsec/PKGBUILD | 20 +- libre/linux-libre-grsec/config.i686 | 122 +- libre/linux-libre-grsec/config.mips64el | 99 +- libre/linux-libre-grsec/config.x86_64 | 122 +- 12 files changed, 24976 insertions(+), 24348 deletions(-) delete mode 100644 kernels/linux-libre-grsec-knock/4.0-rc7-37af2c8aae-loongson-community.patch create mode 100644 kernels/linux-libre-grsec-knock/4.0.2-ae91f13af5-loongson-community.patch delete mode 100644 libre/linux-libre-grsec/4.0-rc7-37af2c8aae-loongson-community.patch create mode 100644 libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch (limited to 'libre') diff --git a/kernels/linux-libre-grsec-knock/4.0-rc7-37af2c8aae-loongson-community.patch b/kernels/linux-libre-grsec-knock/4.0-rc7-37af2c8aae-loongson-community.patch deleted file mode 100644 index 5fb2ec0b7..000000000 --- a/kernels/linux-libre-grsec-knock/4.0-rc7-37af2c8aae-loongson-community.patch +++ /dev/null @@ -1,12143 +0,0 @@ -diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig -index c7a1690..0f854f0 100644 ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -333,7 +333,7 @@ config LASAT - - config MACH_LOONGSON - bool "Loongson family of machines" -- select SYS_SUPPORTS_ZBOOT -+ select SYS_SUPPORTS_ZBOOT_UART16550 - help - This enables the support of Loongson family of machines. - -@@ -1640,6 +1640,15 @@ config CPU_LOONGSON2 - bool - select CPU_SUPPORTS_32BIT_KERNEL - select CPU_SUPPORTS_64BIT_KERNEL -+ select CPU_SUPPORTS_HIGHMEM if ! EMBEDDED -+ select ARCH_WANT_OPTIONAL_GPIOLIB -+ -+config CPU_LOONGSON1 -+ bool -+ select CPU_MIPS32 -+ select CPU_MIPSR2 -+ select CPU_HAS_PREFETCH -+ select CPU_SUPPORTS_32BIT_KERNEL - select CPU_SUPPORTS_HIGHMEM - select CPU_SUPPORTS_HUGEPAGES - -@@ -2313,7 +2322,7 @@ config CPU_SUPPORTS_MSA - - config ARCH_FLATMEM_ENABLE - def_bool y -- depends on !NUMA && !CPU_LOONGSON2 -+ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION) - - config ARCH_DISCONTIGMEM_ENABLE - bool -diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile -index 61af6b6..8598044 100644 ---- a/arch/mips/boot/compressed/Makefile -+++ b/arch/mips/boot/compressed/Makefile -@@ -30,9 +30,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ - targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o - - # decompressor objects (linked with vmlinuz) --vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o -+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o - - ifdef CONFIG_DEBUG_ZBOOT -+vmlinuzobjs-y += $(obj)/dbg.o - vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o - vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o - endif -@@ -79,9 +80,18 @@ quiet_cmd_zld = LD $@ - cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ - quiet_cmd_strip = STRIP $@ - cmd_strip = $(STRIP) -s $@ -+ifdef CONFIG_EMBEDDED -+quiet_cmd_sstrip = SSTRIP $@ -+ cmd_sstrip = $(srctree)/scripts/sstrip.sh $@ -+endif - vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr - $(call cmd,zld) - $(call cmd,strip) -+ $(call cmd,sstrip) -+ -+vmlinuz.unsstrip: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr -+ $(call cmd,zld) -+ $(call cmd,strip) - - # - # Some DECstations need all possible sections of an ECOFF executable -@@ -94,14 +104,14 @@ endif - hostprogs-y += ../elf2ecoff - - ifdef CONFIG_32BIT -- VMLINUZ = vmlinuz -+ VMLINUZ = vmlinuz.unsstrip - else - VMLINUZ = vmlinuz.32 - endif - - quiet_cmd_32 = OBJCOPY $@ - cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ --vmlinuz.32: vmlinuz -+vmlinuz.32: vmlinuz.unsstrip - $(call cmd,32) - - quiet_cmd_ecoff = ECOFF $@ -@@ -110,11 +120,11 @@ vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ) - $(call cmd,ecoff) - - OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary --vmlinuz.bin: vmlinuz -+vmlinuz.bin: vmlinuz.unsstrip - $(call cmd,objcopy) - - OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec --vmlinuz.srec: vmlinuz -+vmlinuz.srec: vmlinuz.unsstrip - $(call cmd,objcopy) - --clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} -+clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec,unsstrip} -diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c -index 31903cf..14da73c 100644 ---- a/arch/mips/boot/compressed/decompress.c -+++ b/arch/mips/boot/compressed/decompress.c -@@ -28,8 +28,13 @@ unsigned long free_mem_end_ptr; - extern unsigned char __image_begin, __image_end; - - /* debug interfaces */ -+#ifdef CONFIG_DEBUG_ZBOOT - extern void puts(const char *s); - extern void puthex(unsigned long long val); -+#else -+#define puts(s) -+#define puthex(val) -+#endif - - void error(char *x) - { -diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script -index 5a33409..de04ac9 100644 ---- a/arch/mips/boot/compressed/ld.script -+++ b/arch/mips/boot/compressed/ld.script -@@ -49,5 +49,6 @@ SECTIONS - *(.reginfo) - *(.comment) - *(.note) -+ *(.gnu.attributes) - } - } -diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -index a0ee0cb..4e18add 100644 ---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo); - /* GPIO : I/O SPACE; REG : 32BITS */ - #define GPIOL_OUT_VAL 0x00 - #define GPIOL_OUT_EN 0x04 -+#define GPIOL_OUT_AUX1_SEL 0x10 -+/* SMB : I/O SPACE, REG : 8BITS WIDTH */ -+#define SMB_SDA 0x00 -+#define SMB_STS 0x01 -+#define SMB_STS_SLVSTP (1 << 7) -+#define SMB_STS_SDAST (1 << 6) -+#define SMB_STS_BER (1 << 5) -+#define SMB_STS_NEGACK (1 << 4) -+#define SMB_STS_STASTR (1 << 3) -+#define SMB_STS_NMATCH (1 << 2) -+#define SMB_STS_MASTER (1 << 1) -+#define SMB_STS_XMIT (1 << 0) -+#define SMB_CTRL_STS 0x02 -+#define SMB_CSTS_TGSTL (1 << 5) -+#define SMB_CSTS_TSDA (1 << 4) -+#define SMB_CSTS_GCMTCH (1 << 3) -+#define SMB_CSTS_MATCH (1 << 2) -+#define SMB_CSTS_BB (1 << 1) -+#define SMB_CSTS_BUSY (1 << 0) -+#define SMB_CTRL1 0x03 -+#define SMB_CTRL1_STASTRE (1 << 7) -+#define SMB_CTRL1_NMINTE (1 << 6) -+#define SMB_CTRL1_GCMEN (1 << 5) -+#define SMB_CTRL1_ACK (1 << 4) -+#define SMB_CTRL1_RSVD (1 << 3) -+#define SMB_CTRL1_INTEN (1 << 2) -+#define SMB_CTRL1_STOP (1 << 1) -+#define SMB_CTRL1_START (1 << 0) -+#define SMB_ADDR 0x04 -+#define SMB_ADDR_SAEN (1 << 7) -+#define SMB_CONTROLLER_ADDR (0xef << 0) -+#define SMB_CTRL2 0x05 -+#define SMB_FREQ (0x20 << 1) -+#define SMB_ENABLE (0x01 << 0) -+#define SMB_CTRL3 0x06 - - #endif /* _CS5536_H */ -diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -index 021d017..50aafca 100644 ---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -@@ -28,8 +28,19 @@ static inline void __maybe_unused enable_mfgpt0_counter(void) - #define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ) - - #define MFGPT_BASE mfgpt_base -+#define MFGPT0_CMP1 (MFGPT_BASE + 0) - #define MFGPT0_CMP2 (MFGPT_BASE + 2) - #define MFGPT0_CNT (MFGPT_BASE + 4) - #define MFGPT0_SETUP (MFGPT_BASE + 6) - -+#define MFGPT1_CMP1 (MFGPT_BASE + 0x08) -+#define MFGPT1_CMP2 (MFGPT_BASE + 0x0A) -+#define MFGPT1_CNT (MFGPT_BASE + 0x0C) -+#define MFGPT1_SETUP (MFGPT_BASE + 0x0E) -+ -+#define MFGPT2_CMP1 (MFGPT_BASE + 0x10) -+#define MFGPT2_CMP2 (MFGPT_BASE + 0x12) -+#define MFGPT2_CNT (MFGPT_BASE + 0x14) -+#define MFGPT2_SETUP (MFGPT_BASE + 0x16) -+ - #endif /*!_CS5536_MFGPT_H */ -diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h -index 5459ac0..14e82d9 100644 ---- a/arch/mips/include/asm/mach-loongson/loongson.h -+++ b/arch/mips/include/asm/mach-loongson/loongson.h -@@ -46,6 +46,12 @@ static inline void prom_init_uart_base(void) - #endif - } - -+/* -+ * Copy kernel command line from arcs_cmdline -+ */ -+#include -+extern char loongson_cmdline[COMMAND_LINE_SIZE]; -+ - /* irq operation functions */ - extern void bonito_irqdispatch(void); - extern void __init bonito_irq_init(void); -diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h -index cb2b602..78fcd38 100644 ---- a/arch/mips/include/asm/mach-loongson/machine.h -+++ b/arch/mips/include/asm/mach-loongson/machine.h -@@ -24,6 +24,12 @@ - - #endif - -+#ifdef CONFIG_DEXXON_GDIUM -+ -+#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10 -+ -+#endif -+ - #ifdef CONFIG_LOONGSON_MACH3X - - #define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC -diff --git a/arch/mips/include/asm/mach-loongson1/clock.h b/arch/mips/include/asm/mach-loongson1/clock.h -new file mode 100644 -index 0000000..dd1afdb ---- /dev/null -+++ b/arch/mips/include/asm/mach-loongson1/clock.h -@@ -0,0 +1,53 @@ -+#ifndef __ASM_MACH_LOONGSON1_CLOCK_H -+#define __ASM_MACH_LOONGSON1_CLOCK_H -+ -+#include -+#include -+#include -+#include -+ -+extern void (*cpu_wait) (void); -+ -+struct clk; -+ -+struct clk_ops { -+ void (*init) (struct clk *clk); -+ void (*enable) (struct clk *clk); -+ void (*disable) (struct clk *clk); -+ void (*recalc) (struct clk *clk); -+ int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id); -+ long (*round_rate) (struct clk *clk, unsigned long rate); -+}; -+ -+struct clk { -+ struct list_head node; -+ const char *name; -+ int id; -+ struct module *owner; -+ -+ struct clk *parent; -+ struct clk_ops *ops; -+ -+ struct kref kref; -+ -+ unsigned long rate; -+ unsigned long flags; -+}; -+ -+#define CLK_ALWAYS_ENABLED (1 << 0) -+#define CLK_RATE_PROPAGATES (1 << 1) -+ -+/* Should be defined by processor-specific code */ -+void arch_init_clk_ops(struct clk_ops **, int type); -+ -+int clk_init(void); -+ -+int __clk_enable(struct clk *); -+void __clk_disable(struct clk *); -+ -+void clk_recalc_rate(struct clk *); -+ -+int clk_register(struct clk *); -+void clk_unregister(struct clk *); -+ -+#endif /* __ASM_MIPS_CLOCK_H */ -diff --git a/arch/mips/include/asm/mach-loongson1/regs-intc.h b/arch/mips/include/asm/mach-loongson1/regs-intc.h -new file mode 100644 -index 0000000..6d5db23 ---- /dev/null -+++ b/arch/mips/include/asm/mach-loongson1/regs-intc.h -@@ -0,0 +1,25 @@ -+/* -+ * Copyright (c) 2011 Zhang, Keguang -+ * -+ * Loongson1 Interrupt register definitions. -+ * -+ * 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. -+ */ -+ -+#ifndef __ASM_MACH_LOONGSON1_REGS_INTC_H -+#define __ASM_MACH_LOONGSON1_REGS_INTC_H -+ -+#define LS1X_INTC_REG(n, x) \ -+ (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4)) -+ -+#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) -+#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) -+#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) -+#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) -+#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) -+#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) -+ -+#endif /* __ASM_MACH_LOONGSON1_REGS_INTC_H */ -diff --git a/arch/mips/include/asm/sparsemem.h b/arch/mips/include/asm/sparsemem.h -index b1071c1..8b8e551 100644 ---- a/arch/mips/include/asm/sparsemem.h -+++ b/arch/mips/include/asm/sparsemem.h -@@ -11,7 +11,11 @@ - #else - # define SECTION_SIZE_BITS 28 - #endif --#define MAX_PHYSMEM_BITS 48 -+#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit c461731836 broke Loongson2. */ -+# define MAX_PHYSMEM_BITS 48 -+#else -+# define MAX_PHYSMEM_BITS 35 -+#endif - - #endif /* CONFIG_SPARSEMEM */ - #endif /* _MIPS_SPARSEMEM_H */ -diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h -index b05bb70..44c9a69 100644 ---- a/arch/mips/include/asm/timex.h -+++ b/arch/mips/include/asm/timex.h -@@ -11,6 +11,10 @@ - - #ifdef __KERNEL__ - -+#ifdef CONFIG_CSRC_R4K -+#define ARCH_HAS_PREPARED_LPJ -+#endif -+ - #include - - #include -diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h -index fc0cf5a..99e6430 100644 ---- a/arch/mips/include/uapi/asm/inst.h -+++ b/arch/mips/include/uapi/asm/inst.h -@@ -65,6 +65,8 @@ enum spec_op { - enum spec2_op { - madd_op, maddu_op, mul_op, spec2_3_unused_op, - msub_op, msubu_op, /* more unused ops */ -+ loongson_madd_op = 0x18, loongson_msub_op, -+ loongson_nmadd_op, loongson_nmsub_op, - clz_op = 0x20, clo_op, - dclz_op = 0x24, dclo_op, - sdbpp_op = 0x3f -@@ -151,7 +153,7 @@ enum cop0_com_func { - */ - enum cop1_fmt { - s_fmt, d_fmt, e_fmt, q_fmt, -- w_fmt, l_fmt -+ w_fmt, l_fmt, ps_fmt - }; - - /* -@@ -180,7 +182,8 @@ enum cop1_sdw_func { - enum cop1x_func { - lwxc1_op = 0x00, ldxc1_op = 0x01, - swxc1_op = 0x08, sdxc1_op = 0x09, -- pfetch_op = 0x0f, madd_s_op = 0x20, -+ pfetch_op = 0x0f, -+ prefx_op = 0x17, madd_s_op = 0x20, - madd_d_op = 0x21, madd_e_op = 0x22, - msub_s_op = 0x28, msub_d_op = 0x29, - msub_e_op = 0x2a, nmadd_s_op = 0x30, -diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S -index d07b210..69996f2 100644 ---- a/arch/mips/kernel/scall64-o32.S -+++ b/arch/mips/kernel/scall64-o32.S -@@ -26,6 +26,18 @@ - - .align 5 - NESTED(handle_sys, PT_SIZE, sp) -+#ifdef CONFIG_MIPS_USER_RDTSC -+ MFC0 k0, CP0_EPC -+ lw k1, 0(k0) -+ sltiu k1, k1, 0x1c -+ bne k1, zero, 1f # Normal syscall code: 0x0c < 0x1c -+ nop -+ mfc0 v0, CP0_COUNT # Get TSC -+ PTR_ADDIU k0, 4 # ret from syscall -+ MTC0 k0, CP0_EPC -+ eret -+1: -+#endif /* CONFIG_MIPS_USER_RDTSC */ - .set noat - SAVE_SOME - TRACE_IRQS_ON_RELOAD -diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c -index 8d01709..9cd25da 100644 ---- a/arch/mips/kernel/time.c -+++ b/arch/mips/kernel/time.c -@@ -119,6 +119,11 @@ static __init int cpu_has_mfc0_count_bug(void) - - void __init time_init(void) - { -+#ifdef CONFIG_HR_SCHED_CLOCK -+ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) -+ write_c0_count(0); -+#endif -+ - plat_time_init(); - - /* -diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile -index 1e9e900..36fcccc 100644 ---- a/arch/mips/lib/Makefile -+++ b/arch/mips/lib/Makefile -@@ -2,10 +2,14 @@ - # Makefile for MIPS-specific library files.. - # - --lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ -+lib-y += bitops.o csum_partial.o memcpy.o memset.o \ - mips-atomic.o strlen_user.o strncpy_user.o \ - strnlen_user.o uncached.o - -+ifndef CONFIG_CSRC_R4K -+lib-y += delay.o -+endif -+ - obj-y += iomap.o - obj-$(CONFIG_PCI) += iomap-pci.o - lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y)) -diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig -index 156de85..0a433e6 100644 ---- a/arch/mips/loongson/Kconfig -+++ b/arch/mips/loongson/Kconfig -@@ -32,12 +32,12 @@ config LEMOTE_FULOONG2E - - config LEMOTE_MACH2F - bool "Lemote Loongson 2F family machines" -- select ARCH_SPARSEMEM_ENABLE -+ select ARCH_SPARSEMEM_ENABLE if HIBERNATION - select BOARD_SCACHE - select BOOT_ELF32 - select CEVT_R4K if ! MIPS_EXTERNAL_TIMER - select CPU_HAS_WB -- select CS5536 -+ select CS5536 if PCI - select CSRC_R4K if ! MIPS_EXTERNAL_TIMER - select DMA_NONCOHERENT - select GENERIC_ISA_DMA_SUPPORT_BROKEN -@@ -45,14 +45,13 @@ config LEMOTE_MACH2F - select HW_HAS_PCI - select I8259 - select IRQ_CPU -- select ISA - select SYS_HAS_CPU_LOONGSON2F - select SYS_HAS_EARLY_PRINTK - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL -- select SYS_SUPPORTS_HIGHMEM -+ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED - select SYS_SUPPORTS_LITTLE_ENDIAN -- select LOONGSON_MC146818 -+ select LOONGSON_MC146818 if RTC_DRV_CMOS - help - Lemote Loongson 2F family machines utilize the 2F revision of - Loongson processor and the AMD CS5536 south bridge. -@@ -60,6 +59,31 @@ config LEMOTE_MACH2F - These family machines include fuloong2f mini PC, yeeloong2f notebook, - LingLoong allinone PC and so forth. - -+config DEXXON_GDIUM -+ bool "Dexxon Gdium Netbook" -+ select ARCH_SPARSEMEM_ENABLE -+ select BOARD_SCACHE -+ select BOOT_ELF32 -+ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER -+ select CPU_HAS_WB -+ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER -+ select DMA_NONCOHERENT -+ select GENERIC_ISA_DMA_SUPPORT_BROKEN -+ select HW_HAS_PCI -+ select I8259 -+ select IRQ_CPU -+ select ISA -+ select SYS_HAS_CPU_LOONGSON2F -+ select SYS_HAS_EARLY_PRINTK -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_64BIT_KERNEL -+ select SYS_SUPPORTS_HIGHMEM -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select ARCH_REQUIRE_GPIOLIB -+ select HAVE_PWM if MFD_SM501 -+ help -+ Dexxon gdium netbook based on Loongson 2F and SM502. -+ - config LOONGSON_MACH3X - bool "Generic Loongson 3 family machines" - select ARCH_SPARSEMEM_ENABLE -@@ -152,6 +176,24 @@ config LOONGSON_MC146818 - bool - default n - -+config GDIUM_PWM_CLOCK -+ tristate "Gdium PWM Timer" -+ default n -+ depends on HAVE_PWM && EXPERIMENTAL && BROKEN -+ select MIPS_EXTERNAL_TIMER -+ help -+ This options enables the experimental sm501-pwm based clock. With it, -+ you may be possible to use the loongson2f cpufreq driver. -+ -+config GDIUM_VERSION -+ int "Configure Gdium Version" -+ depends on DEXXON_GDIUM -+ default "3" -+ help -+ I have no information about how to determine which version your board -+ is, If the default config doesn't work for it, please change it to -+ smaller ones. -+ - config LEFI_FIRMWARE_INTERFACE - bool - -diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile -index 7429994..63214c8 100644 ---- a/arch/mips/loongson/Makefile -+++ b/arch/mips/loongson/Makefile -@@ -17,6 +17,12 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ - obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ - - # -+# Dexxon gdium netbook, based on loongson 2F and SM502 -+# -+ -+obj-$(CONFIG_DEXXON_GDIUM) += gdium/ -+ -+# - # All Loongson-3 family machines - # - -diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform -index 0ac20eb..cd957dd 100644 ---- a/arch/mips/loongson/Platform -+++ b/arch/mips/loongson/Platform -@@ -30,4 +30,5 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/ - cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely - load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 - load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 -+load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000 - load-$(CONFIG_LOONGSON_MACH3X) += 0xffffffff80200000 -diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c -index 72fed00..96d5919 100644 ---- a/arch/mips/loongson/common/cmdline.c -+++ b/arch/mips/loongson/common/cmdline.c -@@ -17,10 +17,15 @@ - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -+#include - #include - - #include - -+/* the kernel command line copied from arcs_cmdline */ -+char loongson_cmdline[COMMAND_LINE_SIZE]; -+EXPORT_SYMBOL(loongson_cmdline); -+ - void __init prom_init_cmdline(void) - { - int prom_argc; -@@ -45,4 +50,31 @@ void __init prom_init_cmdline(void) - } - - prom_init_machtype(); -+ -+ /* append machine specific command line */ -+ switch (mips_machtype) { -+ case MACH_LEMOTE_LL2F: -+ if ((strstr(arcs_cmdline, "video=")) == NULL) -+ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60"); -+ break; -+ case MACH_LEMOTE_FL2F: -+ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL) -+ strcat(arcs_cmdline, " ide_core.ignore_cable=0"); -+ break; -+ case MACH_LEMOTE_ML2F7: -+ /* Mengloong-2F has a 800x480 screen */ -+ if ((strstr(arcs_cmdline, "vga=")) == NULL) -+ strcat(arcs_cmdline, " vga=0x313"); -+ break; -+ case MACH_DEXXON_GDIUM2F10: -+ /* gdium has a 1024x600 screen */ -+ if ((strstr(arcs_cmdline, "video=")) == NULL) -+ strcat(arcs_cmdline, " video=sm501fb:1024x600@60"); -+ break; -+ default: -+ break; -+ } -+ -+ /* copy arcs_cmdline into loongson_cmdline */ -+ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE); - } -diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c -index 045ea3d..1d1db80 100644 ---- a/arch/mips/loongson/common/env.c -+++ b/arch/mips/loongson/common/env.c -@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap; - struct loongson_system_configuration loongson_sysconf; - - u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; -+EXPORT_SYMBOL_GPL(loongson_chipcfg); - u64 loongson_freqctrl[MAX_PACKAGES]; - - unsigned long long smp_group[4]; -diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile -new file mode 100644 -index 0000000..f3f4f51 ---- /dev/null -+++ b/arch/mips/loongson/gdium/Makefile -@@ -0,0 +1,6 @@ -+# Makefile for gdium -+ -+obj-y += irq.o reset.o platform.o -+ -+obj-$(CONFIG_MFD_SM501) += sm501-pwm.o -+obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o -diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c -new file mode 100644 -index 0000000..fdbf42a ---- /dev/null -+++ b/arch/mips/loongson/gdium/gdium-clock.c -@@ -0,0 +1,234 @@ -+/* -+ * Doesn't work really well. When used, the clocksource is producing -+ * bad timings and the clockevent can't be used (don't have one shot feature -+ * thus can't switch on the fly and the pwm is initialised too late to be able -+ * to use it at boot time). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define CLOCK_PWM 1 -+#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */ -+#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ) -+#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */ -+#define CLOCK_PWM_DUTY 50 -+#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4) -+ -+static const char drv_name[] = "gdium-clock"; -+ -+static struct pwm_device *clock_pwm; -+ -+static DEFINE_SPINLOCK(clock_pwm_lock); -+static uint64_t clock_tick; -+ -+static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id) -+{ -+ struct clock_event_device *cd = dev_id; -+ unsigned long flag; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ clock_tick++; -+ /* wait intn2 to finish */ -+ do { -+ LOONGSON_INTENCLR = (1 << 13); -+ } while (LOONGSON_INTISR & (1 << 13)); -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ -+ if (cd && cd->event_handler) -+ cd->event_handler(cd); -+ -+ return IRQ_HANDLED; -+} -+ -+static cycle_t gdium_pwm_clock_read(struct clocksource *cs) -+{ -+ unsigned long flag; -+ uint32_t jifs; -+ uint64_t ticks; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ jifs = jiffies; -+ ticks = clock_tick; -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ /* return (cycle_t)ticks; */ -+ return (cycle_t)(CLOCK_LATCH * jifs); -+} -+ -+static struct clocksource gdium_pwm_clock_clocksource = { -+ .name = "gdium_csrc", -+ .read = gdium_pwm_clock_read, -+ .mask = CLOCKSOURCE_MASK(64), -+ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, -+ .shift = 20, -+}; -+ -+/* Debug fs */ -+static int gdium_pwm_clock_show(struct seq_file *s, void *p) -+{ -+ unsigned long flag; -+ uint64_t ticks; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ ticks = clock_tick; -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ seq_printf(s, "%lld\n", ticks); -+ return 0; -+} -+ -+static int gdium_pwm_clock_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, gdium_pwm_clock_show, inode->i_private); -+} -+ -+static const struct file_operations gdium_pwm_clock_fops = { -+ .open = gdium_pwm_clock_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+static struct dentry *debugfs_file; -+ -+static void gdium_pwm_clock_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *evt) -+{ -+ /* Nothing to do ... */ -+} -+ -+static struct clock_event_device gdium_pwm_clock_cevt = { -+ .name = "gdium_cevt", -+ .features = CLOCK_EVT_FEAT_PERIODIC, -+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ -+ .rating = 299, -+ .irq = CLOCK_PWM_IRQ, -+ .set_mode = gdium_pwm_clock_set_mode, -+}; -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "gdium-pwmclk", -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver gdium_pwm_clock_driver = { -+ .driver = { -+ .name = drv_name, -+ .owner = THIS_MODULE, -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int gdium_pwm_clock_drvinit(void) -+{ -+ int ret; -+ struct clocksource *cs = &gdium_pwm_clock_clocksource; -+ struct clock_event_device *cd = &gdium_pwm_clock_cevt; -+ unsigned int cpu = smp_processor_id(); -+ -+ clock_tick = 0; -+ -+ clock_pwm = pwm_request(CLOCK_PWM, drv_name); -+ if (clock_pwm == NULL) { -+ pr_err("unable to request PWM for Gdium clock\n"); -+ return -EBUSY; -+ } -+ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD); -+ if (ret) { -+ pr_err("unable to configure PWM for Gdium clock\n"); -+ goto err_pwm_request; -+ } -+ ret = pwm_enable(clock_pwm); -+ if (ret) { -+ pr_err("unable to enable PWM for Gdium clock\n"); -+ goto err_pwm_request; -+ } -+ -+ cd->cpumask = cpumask_of(cpu); -+ -+ cd->shift = 22; -+ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift); -+ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd); -+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd); -+ clockevents_register_device(&gdium_pwm_clock_cevt); -+ -+ /* SM501 PWM1 connected to intn2 <->ip4 */ -+ LOONGSON_INTPOL = (1 << 13); -+ LOONGSON_INTEDGE &= ~(1 << 13); -+ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt); -+ if (ret) { -+ pr_err("Can't claim irq\n"); -+ goto err_pwm_disable; -+ } -+ -+ cs->rating = 200; -+ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift); -+ ret = clocksource_register(&gdium_pwm_clock_clocksource); -+ if (ret) { -+ pr_err("Can't register clocksource\n"); -+ goto err_irq; -+ } -+ pr_info("Clocksource registered with shift %d and mult %d\n", -+ cs->shift, cs->mult); -+ -+ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO, -+ NULL, NULL, &gdium_pwm_clock_fops); -+ -+ return 0; -+ -+err_irq: -+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); -+err_pwm_disable: -+ pwm_disable(clock_pwm); -+err_pwm_request: -+ pwm_free(clock_pwm); -+ return ret; -+} -+ -+static void gdium_pwm_clock_drvexit(void) -+{ -+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); -+ pwm_disable(clock_pwm); -+ pwm_free(clock_pwm); -+} -+ -+ -+static int __devinit gdium_pwm_clock_init(void) -+{ -+ int ret = gdium_pwm_clock_drvinit(); -+ -+ if (ret) { -+ pr_err("Fail to register gdium clock driver\n"); -+ return ret; -+ } -+ -+ return platform_driver_register(&gdium_pwm_clock_driver); -+} -+ -+static void __exit gdium_pwm_clock_cleanup(void) -+{ -+ gdium_pwm_clock_drvexit(); -+ platform_driver_unregister(&gdium_pwm_clock_driver); -+} -+ -+module_init(gdium_pwm_clock_init); -+module_exit(gdium_pwm_clock_cleanup); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("Gdium PWM clock driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:gdium-pwmclk"); -diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c -new file mode 100644 -index 0000000..2415d20 ---- /dev/null -+++ b/arch/mips/loongson/gdium/irq.c -@@ -0,0 +1,55 @@ -+/* -+ * Copyright (C) 2007 Lemote Inc. -+ * Author: Fuxin Zhang, zhangfx@lemote.com -+ * -+ * Copyright (c) 2010 yajin -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+ -+#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */ -+#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */ -+#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */ -+ -+void mach_irq_dispatch(unsigned int pending) -+{ -+ if (pending & CAUSEF_IP7) -+ do_IRQ(LOONGSON_TIMER_IRQ); -+ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ -+ do_perfcnt_IRQ(); -+ bonito_irqdispatch(); -+ } else if (pending & CAUSEF_IP3) /* CPU UART */ -+ do_IRQ(LOONGSON_UART_IRQ); -+#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE) -+ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */ -+ do_IRQ(MIPS_CPU_IRQ_BASE + 4); -+#endif -+ else -+ spurious_interrupt(); -+} -+ -+static irqreturn_t ip6_action(int cpl, void *dev_id) -+{ -+ return IRQ_HANDLED; -+} -+ -+struct irqaction ip6_irqaction = { -+ .handler = ip6_action, -+ .name = "cascade", -+ .flags = IRQF_SHARED, -+}; -+ -+void __init mach_init_irq(void) -+{ -+ /* setup north bridge irq (bonito) */ -+ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction); -+} -diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c -new file mode 100644 -index 0000000..ffafba4 ---- /dev/null -+++ b/arch/mips/loongson/gdium/platform.c -@@ -0,0 +1,135 @@ -+/* -+ * Copyright (c) 2009 Philippe Vachon -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define GDIUM_GPIO_BASE 224 -+ -+static struct i2c_board_info __initdata sm502dev_i2c_devices[] = { -+ { -+ I2C_BOARD_INFO("lm75", 0x48), -+ }, -+ { -+ I2C_BOARD_INFO("m41t83", 0x68), -+ }, -+ { -+ I2C_BOARD_INFO("gdium-laptop", 0x40), -+ }, -+}; -+ -+static int sm502dev_backlight_init(struct device *dev) -+{ -+ /* Add gpio request stuff here */ -+ return 0; -+} -+ -+static void sm502dev_backlight_exit(struct device *dev) -+{ -+ /* Add gpio free stuff here */ -+} -+ -+static struct platform_pwm_backlight_data backlight_data = { -+ .pwm_id = 0, -+ .max_brightness = 15, -+ .dft_brightness = 8, -+ .pwm_period_ns = 50000, /* 20 kHz */ -+ .init = sm502dev_backlight_init, -+ .exit = sm502dev_backlight_exit, -+}; -+ -+static struct platform_device backlight = { -+ .name = "pwm-backlight", -+ .dev = { -+ .platform_data = &backlight_data, -+ }, -+ .id = -1, -+}; -+ -+/* -+ * Warning this stunt is very dangerous -+ * as the sm501 gpio have dynamic numbers... -+ */ -+/* bus 0 is the one for the ST7, DS75 etc... */ -+static struct i2c_gpio_platform_data i2c_gpio0_data = { -+#if CONFIG_GDIUM_VERSION > 2 -+ .sda_pin = GDIUM_GPIO_BASE + 13, -+ .scl_pin = GDIUM_GPIO_BASE + 6, -+#else -+ .sda_pin = 192+15, -+ .scl_pin = 192+14, -+#endif -+ .udelay = 5, -+ .timeout = HZ / 10, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+}; -+ -+static struct platform_device i2c_gpio0_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { .platform_data = &i2c_gpio0_data, }, -+}; -+ -+/* bus 1 is for the CRT/VGA external screen */ -+static struct i2c_gpio_platform_data i2c_gpio1_data = { -+ .sda_pin = GDIUM_GPIO_BASE + 10, -+ .scl_pin = GDIUM_GPIO_BASE + 9, -+ .udelay = 5, -+ .timeout = HZ / 10, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+}; -+ -+static struct platform_device i2c_gpio1_device = { -+ .name = "i2c-gpio", -+ .id = 1, -+ .dev = { .platform_data = &i2c_gpio1_data, }, -+}; -+ -+static struct platform_device gdium_clock = { -+ .name = "gdium-pwmclk", -+ .id = -1, -+}; -+ -+static struct platform_device *devices[] __initdata = { -+ &i2c_gpio0_device, -+ &i2c_gpio1_device, -+ &backlight, -+ &gdium_clock, -+}; -+ -+static int __init gdium_platform_devices_setup(void) -+{ -+ int ret; -+ -+ pr_info("Registering gdium platform devices\n"); -+ -+ ret = i2c_register_board_info(0, sm502dev_i2c_devices, -+ ARRAY_SIZE(sm502dev_i2c_devices)); -+ -+ if (ret != 0) { -+ pr_info("Error while registering platform devices: %d\n", ret); -+ return ret; -+ } -+ -+ platform_add_devices(devices, ARRAY_SIZE(devices)); -+ -+ return 0; -+} -+ -+/* -+ * some devices are on the pwm stuff which is behind the mfd which is -+ * behind the pci bus so arch_initcall can't work because too early -+ */ -+late_initcall(gdium_platform_devices_setup); -diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c -new file mode 100644 -index 0000000..8289f95 ---- /dev/null -+++ b/arch/mips/loongson/gdium/reset.c -@@ -0,0 +1,22 @@ -+/* Board-specific reboot/shutdown routines -+ * -+ * Copyright (C) 2010 yajin -+ * -+ * 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. -+ */ -+#include -+ -+void mach_prepare_shutdown(void) -+{ -+ LOONGSON_GPIOIE &= ~(1<<1); -+ LOONGSON_GPIODATA |= (1<<1); -+} -+ -+void mach_prepare_reboot(void) -+{ -+ LOONGSON_GPIOIE &= ~(1<<2); -+ LOONGSON_GPIODATA &= ~(1<<2); -+} -diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c -new file mode 100644 -index 0000000..5af3b23 ---- /dev/null -+++ b/arch/mips/loongson/gdium/sm501-pwm.c -@@ -0,0 +1,465 @@ -+/* -+ * SM501 PWM clock -+ * Copyright (C) 2009-2010 Arnaud Patard -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static const char drv_name[] = "sm501-pwm"; -+ -+#define INPUT_CLOCK 96 /* MHz */ -+#define PWM_COUNT 3 -+ -+#define SM501PWM_HIGH_COUNTER (1<<20) -+#define SM501PWM_LOW_COUNTER (1<<8) -+#define SM501PWM_CLOCK_DIVIDE (1>>4) -+#define SM501PWM_IP (1<<3) -+#define SM501PWM_I (1<<2) -+#define SM501PWM_E (1<<0) -+ -+struct pwm_device { -+ struct list_head node; -+ struct device *dev; -+ void __iomem *regs; -+ int duty_ns; -+ int period_ns; -+ char enabled; -+ void (*handler)(struct pwm_device *pwm); -+ -+ const char *label; -+ unsigned int use_count; -+ unsigned int pwm_id; -+}; -+ -+struct sm501pwm_info { -+ void __iomem *regs; -+ int irq; -+ struct resource *res; -+ struct device *dev; -+ struct dentry *debugfs; -+ -+ struct pwm_device pwm[3]; -+}; -+ -+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -+{ -+ unsigned int high, low, divider; -+ int divider1, divider2; -+ unsigned long long delay; -+ -+ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns) -+ return -EINVAL; -+ -+ /* Get delay -+ * We're loosing some precision but multiplying then dividing -+ * will overflow -+ */ -+ if (period_ns > 1000) { -+ delay = period_ns / 1000; -+ delay *= INPUT_CLOCK; -+ } else { -+ delay = period_ns * 96; -+ delay /= 1000; -+ } -+ -+ /* Get the number of clock low and high */ -+ high = delay * duty_ns / period_ns; -+ low = delay - high; -+ -+ /* Get divider to make 'low' and 'high' fit into 12 bits */ -+ /* No need to say that the divider must be >= 0 */ -+ divider1 = fls(low)-12; -+ divider2 = fls(high)-12; -+ -+ if (divider1 < 0) -+ divider1 = 0; -+ if (divider2 < 0) -+ divider2 = 0; -+ -+ divider = max(divider1, divider2); -+ -+ low >>= divider; -+ high >>= divider; -+ -+ pwm->duty_ns = duty_ns; -+ pwm->period_ns = period_ns; -+ -+ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_config); -+ -+int pwm_enable(struct pwm_device *pwm) -+{ -+ u32 reg; -+ -+ if (!pwm) -+ return -EINVAL; -+ -+ switch (pwm->pwm_id) { -+ case 0: -+ sm501_configure_gpio(pwm->dev->parent, 29, 1); -+ break; -+ case 1: -+ sm501_configure_gpio(pwm->dev->parent, 30, 1); -+ break; -+ case 2: -+ sm501_configure_gpio(pwm->dev->parent, 31, 1); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ reg = readl(pwm->regs); -+ reg |= (SM501PWM_IP | SM501PWM_E); -+ writel(reg, pwm->regs); -+ pwm->enabled = 1; -+ -+ return 0; -+} -+EXPORT_SYMBOL(pwm_enable); -+ -+void pwm_disable(struct pwm_device *pwm) -+{ -+ u32 reg; -+ -+ if (!pwm) -+ return; -+ -+ reg = readl(pwm->regs); -+ reg &= ~(SM501PWM_IP | SM501PWM_E); -+ writel(reg, pwm->regs); -+ -+ switch (pwm->pwm_id) { -+ case 0: -+ sm501_configure_gpio(pwm->dev->parent, 29, 0); -+ break; -+ case 1: -+ sm501_configure_gpio(pwm->dev->parent, 30, 0); -+ break; -+ case 2: -+ sm501_configure_gpio(pwm->dev->parent, 31, 0); -+ break; -+ default: -+ break; -+ } -+ pwm->enabled = 0; -+} -+EXPORT_SYMBOL(pwm_disable); -+ -+static DEFINE_MUTEX(pwm_lock); -+static LIST_HEAD(pwm_list); -+ -+struct pwm_device *pwm_request(int pwm_id, const char *label) -+{ -+ struct pwm_device *pwm; -+ int found = 0; -+ -+ mutex_lock(&pwm_lock); -+ -+ list_for_each_entry(pwm, &pwm_list, node) { -+ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) { -+ pwm->use_count++; -+ pwm->label = label; -+ found = 1; -+ break; -+ } -+ } -+ -+ mutex_unlock(&pwm_lock); -+ -+ return (found) ? pwm : NULL; -+} -+EXPORT_SYMBOL(pwm_request); -+ -+void pwm_free(struct pwm_device *pwm) -+{ -+ mutex_lock(&pwm_lock); -+ -+ if (pwm->use_count) { -+ pwm->use_count--; -+ pwm->label = NULL; -+ } else -+ dev_warn(pwm->dev, "PWM device already freed\n"); -+ -+ mutex_unlock(&pwm_lock); -+} -+EXPORT_SYMBOL(pwm_free); -+ -+int pwm_int_enable(struct pwm_device *pwm) -+{ -+ unsigned long conf; -+ -+ if (!pwm || !pwm->regs || !pwm->handler) -+ return -EINVAL; -+ -+ conf = readl(pwm->regs); -+ conf |= SM501PWM_I; -+ writel(conf, pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_int_enable); -+ -+int pwm_int_disable(struct pwm_device *pwm) -+{ -+ unsigned long conf; -+ -+ if (!pwm || !pwm->regs || !pwm->handler) -+ return -EINVAL; -+ -+ conf = readl(pwm->regs); -+ conf &= ~SM501PWM_I; -+ writel(conf, pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_int_disable); -+ -+int pwm_set_handler(struct pwm_device *pwm, -+ void (*handler)(struct pwm_device *pwm)) -+{ -+ if (!pwm || !handler) -+ return -EINVAL; -+ pwm->handler = handler; -+ return 0; -+} -+EXPORT_SYMBOL(pwm_set_handler); -+ -+static irqreturn_t sm501pwm_irq(int irq, void *dev_id) -+{ -+ unsigned long value; -+ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id; -+ struct pwm_device *pwm; -+ int i; -+ -+ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0); -+ -+ /* Check is the interrupt is for us */ -+ if (value & (1<<22)) { -+ for (i = 0 ; i < PWM_COUNT ; i++) { -+ /* -+ * Find which pwm triggered the interrupt -+ * and ack -+ */ -+ value = readl(info->regs + i*4); -+ if (value & SM501PWM_IP) -+ writel(value | SM501PWM_IP, info->regs + i*4); -+ -+ pwm = &info->pwm[i]; -+ if (pwm->handler) -+ pwm->handler(pwm); -+ } -+ return IRQ_HANDLED; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static void add_pwm(int id, struct sm501pwm_info *info) -+{ -+ struct pwm_device *pwm = &info->pwm[id]; -+ -+ pwm->use_count = 0; -+ pwm->pwm_id = id; -+ pwm->dev = info->dev; -+ pwm->regs = info->regs + id * 4; -+ -+ mutex_lock(&pwm_lock); -+ list_add_tail(&pwm->node, &pwm_list); -+ mutex_unlock(&pwm_lock); -+} -+ -+static void del_pwm(int id, struct sm501pwm_info *info) -+{ -+ struct pwm_device *pwm = &info->pwm[id]; -+ -+ pwm->use_count = 0; -+ pwm->pwm_id = -1; -+ mutex_lock(&pwm_lock); -+ list_del(&pwm->node); -+ mutex_unlock(&pwm_lock); -+} -+ -+/* Debug fs */ -+static int sm501pwm_show(struct seq_file *s, void *p) -+{ -+ struct pwm_device *pwm; -+ -+ mutex_lock(&pwm_lock); -+ list_for_each_entry(pwm, &pwm_list, node) { -+ if (pwm->use_count) { -+ seq_printf(s, "pwm-%d (%12s) %d %d %s\n", -+ pwm->pwm_id, pwm->label, -+ pwm->duty_ns, pwm->period_ns, -+ pwm->enabled ? "on" : "off"); -+ seq_printf(s, " %08x\n", readl(pwm->regs)); -+ } -+ } -+ mutex_unlock(&pwm_lock); -+ -+ return 0; -+} -+ -+static int sm501pwm_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, sm501pwm_show, inode->i_private); -+} -+ -+static const struct file_operations sm501pwm_fops = { -+ .open = sm501pwm_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init sm501pwm_probe(struct platform_device *pdev) -+{ -+ struct sm501pwm_info *info; -+ struct device *dev = &pdev->dev; -+ struct resource *res; -+ int ret = 0; -+ int res_len; -+ int i; -+ -+ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL); -+ if (!info) { -+ dev_err(dev, "Allocation failure\n"); -+ ret = -ENOMEM; -+ goto err; -+ } -+ info->dev = dev; -+ platform_set_drvdata(pdev, info); -+ -+ /* Get irq number */ -+ info->irq = platform_get_irq(pdev, 0); -+ if (!info->irq) { -+ dev_err(dev, "no irq found\n"); -+ ret = -ENODEV; -+ goto err_alloc; -+ } -+ -+ /* Get regs address */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res == NULL) { -+ dev_err(dev, "No memory resource found\n"); -+ ret = -ENODEV; -+ goto err_alloc; -+ } -+ info->res = res; -+ res_len = (res->end - res->start)+1; -+ -+ if (!request_mem_region(res->start, res_len, drv_name)) { -+ dev_err(dev, "Can't request iomem resource\n"); -+ ret = -EBUSY; -+ goto err_alloc; -+ } -+ -+ info->regs = ioremap(res->start, res_len); -+ if (!info->regs) { -+ dev_err(dev, "ioremap failed\n"); -+ ret = -ENOMEM; -+ goto err_mem; -+ } -+ -+ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info); -+ if (ret != 0) { -+ dev_err(dev, "can't get irq\n"); -+ goto err_map; -+ } -+ -+ -+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1); -+ -+ for (i = 0; i < 3; i++) -+ add_pwm(i, info); -+ -+ dev_info(dev, "SM501 PWM Found at %lx irq %d\n", -+ (unsigned long)info->res->start, info->irq); -+ -+ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO, -+ NULL, info, &sm501pwm_fops); -+ -+ -+ return 0; -+ -+err_map: -+ iounmap(info->regs); -+ -+err_mem: -+ release_mem_region(res->start, res_len); -+ -+err_alloc: -+ kfree(info); -+ platform_set_drvdata(pdev, NULL); -+err: -+ return ret; -+} -+ -+static int sm501pwm_remove(struct platform_device *pdev) -+{ -+ struct sm501pwm_info *info = platform_get_drvdata(pdev); -+ int i; -+ -+ if (info->debugfs) -+ debugfs_remove(info->debugfs); -+ -+ for (i = 0; i < 3; i++) { -+ pwm_disable(&info->pwm[i]); -+ del_pwm(i, info); -+ } -+ -+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0); -+ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22); -+ -+ free_irq(info->irq, info); -+ iounmap(info->regs); -+ release_mem_region(info->res->start, -+ (info->res->end - info->res->start)+1); -+ kfree(info); -+ platform_set_drvdata(pdev, NULL); -+ -+ return 0; -+} -+ -+static struct platform_driver sm501pwm_driver = { -+ .probe = sm501pwm_probe, -+ .remove = sm501pwm_remove, -+ .driver = { -+ .name = drv_name, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __devinit sm501pwm_init(void) -+{ -+ return platform_driver_register(&sm501pwm_driver); -+} -+ -+static void __exit sm501pwm_cleanup(void) -+{ -+ platform_driver_unregister(&sm501pwm_driver); -+} -+ -+module_init(sm501pwm_init); -+module_exit(sm501pwm_cleanup); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("SM501 PWM driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:sm501-pwm"); -diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile -index 4f9eaa3..f945bd7a 100644 ---- a/arch/mips/loongson/lemote-2f/Makefile -+++ b/arch/mips/loongson/lemote-2f/Makefile -@@ -2,7 +2,7 @@ - # Makefile for lemote loongson2f family machines - # - --obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o -+obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o platform.o - - # - # Suspend Support -diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c -new file mode 100644 -index 0000000..5316360 ---- /dev/null -+++ b/arch/mips/loongson/lemote-2f/platform.c -@@ -0,0 +1,48 @@ -+/* -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+ -+static struct platform_device yeeloong_pdev = { -+ .name = "yeeloong_laptop", -+ .id = -1, -+}; -+ -+static struct platform_device lynloong_pdev = { -+ .name = "lynloong_pc", -+ .id = -1, -+}; -+ -+static int __init lemote2f_platform_init(void) -+{ -+ struct platform_device *pdev = NULL; -+ -+ switch (mips_machtype) { -+ case MACH_LEMOTE_YL2F89: -+ pdev = &yeeloong_pdev; -+ break; -+ case MACH_LEMOTE_LL2F: -+ pdev = &lynloong_pdev; -+ break; -+ default: -+ break; -+ -+ } -+ -+ if (pdev != NULL) -+ return platform_device_register(pdev); -+ -+ return -ENODEV; -+} -+ -+arch_initcall(lemote2f_platform_init); -diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c -index b30bf65..c0177cb 100644 ---- a/arch/mips/math-emu/cp1emu.c -+++ b/arch/mips/math-emu/cp1emu.c -@@ -7,6 +7,9 @@ - * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. - * -+ * Loongson instruction support -+ * Copyright (C) 2011 Mark H Weaver -+ * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. -@@ -60,6 +63,11 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, - static int fpux_emu(struct pt_regs *, - struct mips_fpu_struct *, mips_instruction, void *__user *); - -+#ifdef CONFIG_MACH_LOONGSON -+static int loongson_spec2_emu(struct pt_regs *, -+ struct mips_fpu_struct *, mips_instruction, void *__user *); -+#endif -+ - /* Control registers */ - - #define FPCREG_RID 0 /* $0 = revision id */ -@@ -842,6 +850,14 @@ do { \ - #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) - #define DPTOREG(dp, x) DITOREG((dp).bits, x) - -+/* Support for Loongson paired single floating-point format */ -+#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \ -+ (si1) = (u32)di; (si2) = (u32)(di >> 32); }) -+#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x) -+ -+#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x) -+#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x) -+ - /* - * Emulate the single floating point instruction pointed at by EPC. - * Two instructions if the instruction is in a branch delay slot. -@@ -1235,6 +1251,16 @@ emul: - xcp->regs[MIPSInst_RD(ir)] = - xcp->regs[MIPSInst_RS(ir)]; - break; -+ -+#ifdef CONFIG_MACH_LOONGSON -+ case spec2_op:{ -+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr); -+ if (sig) -+ return sig; -+ break; -+ } -+#endif -+ - default: - sigill: - return SIGILL; -@@ -1312,6 +1338,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); - DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); - DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); - -+#ifdef CONFIG_MACH_LOONGSON -+static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, -+ mips_instruction ir, void *__user *fault_addr) -+{ -+ int rfmt; /* resulting format */ -+ unsigned rcsr = 0; /* resulting csr */ -+ union { -+ union ieee754dp d; -+ struct { -+ union ieee754sp s; -+ union ieee754sp s2; -+ }; -+ } rv; /* resulting value */ -+ -+ /* XXX maybe add a counter for loongson spec2 fp instructions? */ -+ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */ -+ -+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { -+ case s_fmt:{ -+ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); -+ union ieee754sp fd, fs, ft; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_sp_madd; -+ goto scoptop; -+ case loongson_msub_op: -+ handler = fpemu_sp_msub; -+ goto scoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_sp_nmadd; -+ goto scoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_sp_nmsub; -+ goto scoptop; -+ -+ scoptop: -+ SPFROMREG(fd, MIPSInst_FD(ir)); -+ SPFROMREG(fs, MIPSInst_FS(ir)); -+ SPFROMREG(ft, MIPSInst_FT(ir)); -+ rv.s = (*handler) (fd, fs, ft); -+ -+ copcsr: -+ if (ieee754_cxtest(IEEE754_INEXACT)) -+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; -+ if (ieee754_cxtest(IEEE754_UNDERFLOW)) -+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; -+ if (ieee754_cxtest(IEEE754_OVERFLOW)) -+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; -+ if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) -+ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; -+ -+ break; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ case d_fmt:{ -+ union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); -+ union ieee754dp fd, fs, ft; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_dp_madd; -+ goto dcoptop; -+ case loongson_msub_op: -+ handler = fpemu_dp_msub; -+ goto dcoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_dp_nmadd; -+ goto dcoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_dp_nmsub; -+ goto dcoptop; -+ -+ dcoptop: -+ DPFROMREG(fd, MIPSInst_FD(ir)); -+ DPFROMREG(fs, MIPSInst_FS(ir)); -+ DPFROMREG(ft, MIPSInst_FT(ir)); -+ rv.d = (*handler) (fd, fs, ft); -+ goto copcsr; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ case ps_fmt:{ -+ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fd1, fs1, ft1; -+ union ieee754sp fd2, fs2, ft2; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_sp_madd; -+ goto pscoptop; -+ case loongson_msub_op: -+ handler = fpemu_sp_msub; -+ goto pscoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_sp_nmadd; -+ goto pscoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_sp_nmsub; -+ goto pscoptop; -+ -+ pscoptop: -+ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir)); -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); -+ rv.s = (*handler) (fd1, fs1, ft1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler) (fd2, fs2, ft2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ default: -+ return SIGILL; -+ } -+ -+ /* -+ * Update the fpu CSR register for this operation. -+ * If an exception is required, generate a tidy SIGFPE exception, -+ * without updating the result register. -+ * Note: cause exception bits do not accumulate, they are rewritten -+ * for each op; only the flag/sticky bits accumulate. -+ */ -+ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; -+ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { -+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ -+ return SIGFPE; -+ } -+ -+ /* -+ * Now we can safely write the result back to the register file. -+ */ -+ switch (rfmt) { -+ case d_fmt: -+ DPTOREG(rv.d, MIPSInst_FD(ir)); -+ break; -+ case s_fmt: -+ SPTOREG(rv.s, MIPSInst_FD(ir)); -+ break; -+ case ps_fmt: -+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); -+ break; -+ default: -+ return SIGILL; -+ } -+ -+ return 0; -+} -+#endif -+ - static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - mips_instruction ir, void *__user *fault_addr) - { -@@ -1413,7 +1605,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - break; - - default: -- return SIGILL; -+ goto SIGILL_unless_prefx_op; - } - break; - } -@@ -1483,7 +1675,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - goto copcsr; - - default: -- return SIGILL; -+ goto SIGILL_unless_prefx_op; - } - break; - } -@@ -1496,6 +1688,11 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - break; - - default: -+ SIGILL_unless_prefx_op: -+ if (MIPSInst_FUNC(ir) == prefx_op) { -+ /* ignore prefx operation */ -+ break; -+ } - return SIGILL; - } - -@@ -1517,7 +1714,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - unsigned cond; - union { - union ieee754dp d; -- union ieee754sp s; -+ struct { -+ union ieee754sp s; -+#ifdef CONFIG_MACH_LOONGSON -+ union ieee754sp s2; /* for Loongson paired singles */ -+#endif -+ }; - int w; - s64 l; - } rv; /* resulting value */ -@@ -1614,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - case fmov_op: - /* an easy one */ - SPFROMREG(rv.s, MIPSInst_FS(ir)); -- goto copcsr; -+ break; - - /* binary op on handler */ - scopbop: -@@ -1811,7 +2013,7 @@ copcsr: - case fmov_op: - /* an easy one */ - DPFROMREG(rv.d, MIPSInst_FS(ir)); -- goto copcsr; -+ break; - - /* binary op on handler */ - dcopbop: -@@ -1928,6 +2130,83 @@ dcopuop: - break; - } - -+#ifdef CONFIG_MACH_LOONGSON -+ case ps_fmt:{ /* 6 */ -+ /* Support for Loongson paired single fp instructions */ -+ union { -+ union ieee754sp(*b) (union ieee754sp, union ieee754sp); -+ union ieee754sp(*u) (union ieee754sp); -+ } handler; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ /* binary ops */ -+ case fadd_op: -+ handler.b = ieee754sp_add; -+ goto pscopbop; -+ case fsub_op: -+ handler.b = ieee754sp_sub; -+ goto pscopbop; -+ case fmul_op: -+ handler.b = ieee754sp_mul; -+ goto pscopbop; -+ -+ /* unary ops */ -+ case fabs_op: -+ handler.u = ieee754sp_abs; -+ goto pscopuop; -+ case fneg_op: -+ handler.u = ieee754sp_neg; -+ goto pscopuop; -+ case fmov_op: -+ /* an easy one */ -+ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir)); -+ break; -+ -+ pscopbop: /* paired binary op handler */ -+ { -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fs1, ft1; -+ union ieee754sp fs2, ft2; -+ -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); -+ rv.s = (*handler.b) (fs1, ft1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler.b) (fs2, ft2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ } -+ pscopuop: /* paired unary op handler */ -+ { -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fs1; -+ union ieee754sp fs2; -+ -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ rv.s = (*handler.u) (fs1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler.u) (fs2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ } -+ break; -+ -+ default: -+ if (MIPSInst_FUNC(ir) >= fcmp_op) { -+ /* Loongson fp hardware handles all -+ cases of fp compare insns, so we -+ shouldn't have to */ -+ printk ("Loongson paired-single fp compare" -+ " unimplemented in cp1emu.c\n"); -+ } -+ return SIGILL; -+ } -+ break; -+ } -+#endif -+ - case l_fmt: - - if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) -@@ -1999,6 +2278,11 @@ dcopuop: - - DITOREG(rv.l, MIPSInst_FD(ir)); - break; -+#ifdef CONFIG_MACH_LOONGSON -+ case ps_fmt: -+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); -+ break; -+#endif - default: - return SIGILL; - } -diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile -index 300591c..ed272e2 100644 ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -30,6 +30,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o - obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o - obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o - obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o -+obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o - obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3.o - obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o - obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o -diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c -new file mode 100644 -index 0000000..b296220 ---- /dev/null -+++ b/arch/mips/pci/fixup-gdium.c -@@ -0,0 +1,90 @@ -+/* -+ * Copyright (C) 2010 yajin -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+/* -+ * http://www.pcidatabase.com -+ * GDIUM has different PCI mapping -+ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI -+ * slog 14 (0x126f/0x0501) -> sm501 -+ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers -+ * plus Single EHCI controller -+ * slot 16 (0x10ec/0x8139) -> Realtek 8139c -+ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller -+ */ -+ -+#undef INT_IRQA -+#undef INT_IRQB -+#undef INT_IRQC -+#undef INT_IRQD -+#define INT_IRQA 36 -+#define INT_IRQB 37 -+#define INT_IRQC 38 -+#define INT_IRQD 39 -+ -+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ int irq = 0; -+ -+ switch (slot) { -+ case 13: -+ irq = INT_IRQC + ((pin - 1) & 3); -+ break; -+ case 14: -+ irq = INT_IRQA; -+ break; -+ case 15: -+#if CONFIG_GDIUM_VERSION > 2 -+ irq = INT_IRQB; -+#else -+ irq = INT_IRQA + ((pin - 1) & 3); -+#endif -+ break; -+ case 16: -+ irq = INT_IRQD; -+ break; -+#if CONFIG_GDIUM_VERSION > 2 -+ case 17: -+ irq = INT_IRQC; -+ break; -+#endif -+ default: -+ pr_info(" strange pci slot number %d on gdium.\n", slot); -+ break; -+ } -+ return irq; -+} -+ -+/* Do platform specific device initialization at pci_enable_device() time */ -+int pcibios_plat_dev_init(struct pci_dev *dev) -+{ -+ return 0; -+} -+ -+/* Fixups for the USB host controllers */ -+static void __init gdium_usb_host_fixup(struct pci_dev *dev) -+{ -+ unsigned int val; -+ pci_read_config_dword(dev, 0xe0, &val); -+#if CONFIG_GDIUM_VERSION > 2 -+ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3); -+#else -+ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5); -+ pci_write_config_dword(dev, 0xe4, 1<<5); -+#endif -+} -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, -+ gdium_usb_host_fixup); -+#if CONFIG_GDIUM_VERSION > 2 -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550, -+ gdium_usb_host_fixup); -+#endif -diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S -index 32a7c82..3a89502 100644 ---- a/arch/mips/power/hibernate.S -+++ b/arch/mips/power/hibernate.S -@@ -43,7 +43,9 @@ LEAF(swsusp_arch_resume) - bne t1, t3, 1b - PTR_L t0, PBE_NEXT(t0) - bnez t0, 0b -+#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit 771004298d broke Loongson2. */ - jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */ -+#endif - PTR_LA t0, saved_regs - PTR_L ra, PT_R31(t0) - PTR_L sp, PT_R29(t0) -diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c -index fc897ba..ac60f6b 100644 ---- a/drivers/cpufreq/loongson2_cpufreq.c -+++ b/drivers/cpufreq/loongson2_cpufreq.c -@@ -161,20 +161,32 @@ static int __init cpufreq_init(void) - /* Register platform stuff */ - ret = platform_driver_register(&platform_driver); - if (ret) -- return ret; -+ goto err_return; - - pr_info("cpufreq: Loongson-2F CPU frequency driver.\n"); - -- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, -- CPUFREQ_TRANSITION_NOTIFIER); -+ ret = cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, -+ CPUFREQ_TRANSITION_NOTIFIER); -+ if (ret) -+ goto err_platform_driver_unregister; - - ret = cpufreq_register_driver(&loongson2_cpufreq_driver); -+ if (ret) -+ goto err_cpufreq_unregister_notifier; - -- if (!ret && !nowait) { -+ if (!nowait) { - saved_cpu_wait = cpu_wait; - cpu_wait = loongson2_cpu_wait; - } - -+ return 0; -+ -+ err_cpufreq_unregister_notifier: -+ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block, -+ CPUFREQ_TRANSITION_NOTIFIER); -+ err_platform_driver_unregister: -+ platform_driver_unregister(&platform_driver); -+ err_return: - return ret; - } - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 152b006..767d8de 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -871,6 +871,13 @@ config HID_ZYDACRON - ---help--- - Support for Zydacron remote control. - -+config HID_GDIUM -+ bool "Gdium Fn keys support" if EMBEDDED -+ depends on USB_HID && DEXXON_GDIUM -+ default !EMBEDDED -+ ---help--- -+ Support for Functions keys available on Gdiums. -+ - config HID_SENSOR_HUB - tristate "HID Sensors framework support" - depends on HID && HAS_IOMEM -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 6f19958..2740ff0 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -99,6 +99,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o - wacom-objs := wacom_wac.o wacom_sys.o - obj-$(CONFIG_HID_WACOM) += wacom.o - obj-$(CONFIG_HID_WALTOP) += hid-waltop.o -+obj-$(CONFIG_HID_GDIUM) += hid-gdium.o - obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o - obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o - -diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c -new file mode 100644 -index 0000000..67cc095 ---- /dev/null -+++ b/drivers/hid/hid-gdium.c -@@ -0,0 +1,210 @@ -+/* -+ * hid-gdium -- Gdium laptop function keys -+ * -+ * Arnaud Patard -+ * -+ * Based on hid-apple.c -+ * -+ * 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. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+ -+#include "hid-ids.h" -+ -+#define GDIUM_FN_ON 1 -+ -+static int fnmode = GDIUM_FN_ON; -+module_param(fnmode, int, 0644); -+MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)"); -+ -+struct gdium_data { -+ unsigned int fn_on; -+}; -+ -+ -+struct gdium_key_translation { -+ u16 from; -+ u16 to; -+}; -+ -+static struct gdium_key_translation gdium_fn_keys[] = { -+ { KEY_F1, KEY_CAMERA }, -+ { KEY_F2, KEY_CONNECT }, -+ { KEY_F3, KEY_MUTE }, -+ { KEY_F4, KEY_VOLUMEUP}, -+ { KEY_F5, KEY_VOLUMEDOWN }, -+ { KEY_F6, KEY_SWITCHVIDEOMODE }, -+ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */ -+ { KEY_F8, KEY_BRIGHTNESSUP }, -+ { KEY_F9, KEY_BRIGHTNESSDOWN }, -+ { KEY_F10, KEY_SLEEP }, -+ { KEY_F11, KEY_PROG1 }, -+ { KEY_F12, KEY_PROG2 }, -+ { KEY_UP, KEY_PAGEUP }, -+ { KEY_DOWN, KEY_PAGEDOWN }, -+ { KEY_INSERT, KEY_NUMLOCK }, -+ { KEY_DELETE, KEY_SCROLLLOCK }, -+ { KEY_T, KEY_STOPCD }, -+ { KEY_F, KEY_PREVIOUSSONG }, -+ { KEY_H, KEY_NEXTSONG }, -+ { KEY_G, KEY_PLAYPAUSE }, -+ { } -+}; -+ -+static struct gdium_key_translation *gdium_find_translation( -+ struct gdium_key_translation *table, u16 from) -+{ -+ struct gdium_key_translation *trans; -+ -+ /* Look for the translation */ -+ for (trans = table; trans->from; trans++) -+ if (trans->from == from) -+ return trans; -+ return NULL; -+} -+ -+static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input, -+ struct hid_usage *usage, __s32 value) -+{ -+ struct gdium_data *data = hid_get_drvdata(hid); -+ struct gdium_key_translation *trans; -+ int do_translate; -+ -+ if (usage->type != EV_KEY) -+ return 0; -+ -+ if ((usage->code == KEY_FN)) { -+ data->fn_on = !!value; -+ input_event(input, usage->type, usage->code, value); -+ return 1; -+ } -+ -+ if (fnmode) { -+ trans = gdium_find_translation(gdium_fn_keys, usage->code); -+ if (trans) { -+ do_translate = data->fn_on; -+ if (do_translate) { -+ input_event(input, usage->type, trans->to, value); -+ return 1; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int gdium_input_event(struct hid_device *hdev, struct hid_field *field, -+ struct hid_usage *usage, __s32 value) -+{ -+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type) -+ return 0; -+ -+ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value)) -+ return 1; -+ -+ return 0; -+} -+ -+ -+static void gdium_input_setup(struct input_dev *input) -+{ -+ struct gdium_key_translation *trans; -+ -+ set_bit(KEY_NUMLOCK, input->keybit); -+ -+ /* Enable all needed keys */ -+ for (trans = gdium_fn_keys; trans->from; trans++) -+ set_bit(trans->to, input->keybit); -+} -+ -+static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi, -+ struct hid_field *field, struct hid_usage *usage, -+ unsigned long **bit, int *max) -+{ -+ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) -+ && ((usage->hid & HID_USAGE) == 0x82)) { -+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); -+ gdium_input_setup(hi->input); -+ return 1; -+ } -+ return 0; -+} -+ -+static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id) -+{ -+ struct gdium_data *data; -+ int ret; -+ -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) { -+ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n"); -+ return -ENOMEM; -+ } -+ -+ hid_set_drvdata(hdev, data); -+ -+ ret = hid_parse(hdev); -+ if (ret) { -+ dev_err(&hdev->dev, "parse failed\n"); -+ goto err_free; -+ } -+ -+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); -+ if (ret) { -+ dev_err(&hdev->dev, "hw start failed\n"); -+ goto err_free; -+ } -+ -+ return 0; -+err_free: -+ kfree(data); -+ return ret; -+} -+static void gdium_input_remove(struct hid_device *hdev) -+{ -+ hid_hw_stop(hdev); -+ kfree(hid_get_drvdata(hdev)); -+} -+ -+static const struct hid_device_id gdium_input_devices[] = { -+ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) }, -+ {} -+}; -+MODULE_DEVICE_TABLE(hid, gdium_input_devices); -+ -+static struct hid_driver gdium_input_driver = { -+ .name = "gdium-fnkeys", -+ .id_table = gdium_input_devices, -+ .probe = gdium_input_probe, -+ .remove = gdium_input_remove, -+ .event = gdium_input_event, -+ .input_mapping = gdium_input_mapping, -+}; -+ -+static int gdium_input_init(void) -+{ -+ int ret; -+ -+ ret = hid_register_driver(&gdium_input_driver); -+ if (ret) -+ pr_err("can't register gdium keyboard driver\n"); -+ -+ return ret; -+} -+static void gdium_input_exit(void) -+{ -+ hid_unregister_driver(&gdium_input_driver); -+} -+ -+module_init(gdium_input_init); -+module_exit(gdium_input_exit); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 9c47867..a3e1258 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -1021,6 +1021,9 @@ - #define USB_VENDOR_ID_ZYTRONIC 0x14c8 - #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 - -+#define USB_VENDOR_ID_GDIUM 0x04B4 -+#define USB_DEVICE_ID_GDIUM 0xe001 -+ - #define USB_VENDOR_ID_PRIMAX 0x0461 - #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 - -diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c -index 376f2dc..b576801 100644 ---- a/drivers/ide/ide-iops.c -+++ b/drivers/ide/ide-iops.c -@@ -27,6 +27,10 @@ - #include - #include - -+#ifdef CONFIG_LEMOTE_MACH2F -+#include -+#endif -+ - void SELECT_MASK(ide_drive_t *drive, int mask) - { - const struct ide_port_ops *port_ops = drive->hwif->port_ops; -@@ -300,6 +304,11 @@ void ide_check_nien_quirk_list(ide_drive_t *drive) - { - const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; - -+#ifdef CONFIG_LEMOTE_MACH2F -+ if (mips_machtype != MACH_LEMOTE_YL2F89) -+ return; -+#endif -+ - for (list = nien_quirk_list; *list != NULL; list++) - if (strstr(m, *list) != NULL) { - drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; -diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c -index 91077ef..2cfd9ff 100644 ---- a/drivers/mfd/sm501.c -+++ b/drivers/mfd/sm501.c -@@ -58,7 +58,7 @@ struct sm501_gpio { - struct sm501_gpio { - /* no gpio support, empty definition for sm501_devdata. */ - }; --#endif -+#endif /* CONFIG_MFD_SM501_GPIO */ - - struct sm501_devdata { - spinlock_t reg_lock; -@@ -1124,6 +1124,22 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) - { - return sm->gpio.registered; - } -+ -+void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned -+ char mode) -+{ -+ unsigned long set, reg, offset = gpio; -+ -+ if (offset >= 32) { -+ reg = SM501_GPIO63_32_CONTROL; -+ offset = gpio - 32; -+ } else -+ reg = SM501_GPIO31_0_CONTROL; -+ -+ set = mode ? 1 << offset : 0; -+ -+ sm501_modify_reg(dev, reg, set, 0); -+} - #else - static inline int sm501_register_gpio(struct sm501_devdata *sm) - { -@@ -1143,7 +1159,13 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) - { - return 0; - } --#endif -+ -+void sm501_configure_gpio(struct device *dev, unsigned int gpio, -+ unsigned char mode) -+{ -+} -+#endif /* CONFIG_MFD_SM501_GPIO */ -+EXPORT_SYMBOL_GPL(sm501_configure_gpio); - - static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, - struct sm501_platdata_gpio_i2c *iic) -@@ -1198,6 +1220,20 @@ static int sm501_register_gpio_i2c(struct sm501_devdata *sm, - return 0; - } - -+/* register sm501 PWM device */ -+static int sm501_register_pwm(struct sm501_devdata *sm) -+{ -+ struct platform_device *pdev; -+ -+ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0); -+ if (!pdev) -+ return -ENOMEM; -+ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC); -+ sm501_create_irq(sm, &pdev->resource[1]); -+ -+ return sm501_register_device(sm, pdev); -+} -+ - /* sm501_dbg_regs - * - * Debug attribute to attach to parent device to show core registers -@@ -1356,6 +1392,8 @@ static int sm501_init_dev(struct sm501_devdata *sm) - sm501_register_uart(sm, idata->devices); - if (idata->devices & SM501_USE_GPIO) - sm501_register_gpio(sm); -+ if (idata->devices & SM501_USE_PWM) -+ sm501_register_pwm(sm); - } - - if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { -@@ -1542,10 +1580,15 @@ static struct sm501_initdata sm501_pci_initdata = { - .devices = SM501_USE_ALL, - - /* Errata AB-3 says that 72MHz is the fastest available -- * for 33MHZ PCI with proper bus-mastering operation */ -- -+ * for 33MHZ PCI with proper bus-mastering operation -+ * For gdium, it works under 84&112M clock freq.*/ -+#ifdef CONFIG_DEXXON_GDIUM -+ .mclk = 84 * MHZ, -+ .m1xclk = 112 * MHZ, -+#else - .mclk = 72 * MHZ, - .m1xclk = 144 * MHZ, -+#endif - }; - - static struct sm501_platdata_fbsub sm501_pdata_fbsub = { -diff --git a/drivers/net/titan_ge.c b/drivers/net/titan_ge.c -new file mode 100644 -index 0000000..dc137bf8 ---- /dev/null -+++ b/drivers/net/titan_ge.c -@@ -0,0 +1,2069 @@ -+/* -+ * drivers/net/titan_ge.c - Driver for Titan ethernet ports -+ * -+ * Copyright (C) 2003 PMC-Sierra Inc. -+ * Author : Manish Lachwani (lachwani@pmc-sierra.com) -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+/* -+ * The MAC unit of the Titan consists of the following: -+ * -+ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO -+ * -> FIFO is where the incoming and outgoing data is placed -+ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes -+ * the data into the FIFO for Rx -+ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. -+ * -> AFX is the address filtering block -+ * -> GMII block to communicate with the PHY -+ * -+ * Rx will look like the following: -+ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory -+ * -+ * Tx will look like the following: -+ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII -+ * -+ * The Titan driver has support for the following performance features: -+ * -> Rx side checksumming -+ * -> Jumbo Frames -+ * -> Interrupt Coalscing -+ * -> Rx NAPI -+ * -> SKB Recycling -+ * -> Transmit/Receive descriptors in SRAM -+ * -> Fast routing for IP forwarding -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* For MII specifc registers, titan_mdio.h should be included */ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "titan_ge.h" -+#include "titan_mdio.h" -+ -+/* Static Function Declarations */ -+static int titan_ge_eth_open(struct net_device *); -+static void titan_ge_eth_stop(struct net_device *); -+static struct net_device_stats *titan_ge_get_stats(struct net_device *); -+static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int, -+ unsigned long, unsigned long, -+ unsigned long); -+static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int, -+ unsigned long, unsigned long); -+ -+static int titan_ge_open(struct net_device *); -+static int titan_ge_start_xmit(struct sk_buff *, struct net_device *); -+static int titan_ge_stop(struct net_device *); -+ -+static unsigned long titan_ge_tx_coal(unsigned long, int); -+ -+static void titan_ge_port_reset(unsigned int); -+static int titan_ge_free_tx_queue(titan_ge_port_info *); -+static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *); -+static int titan_ge_port_start(struct net_device *, titan_ge_port_info *); -+ -+static int titan_ge_return_tx_desc(titan_ge_port_info *, int); -+ -+/* -+ * Some configuration for the FIFO and the XDMA channel needs -+ * to be done only once for all the ports. This flag controls -+ * that -+ */ -+static unsigned long config_done; -+ -+/* -+ * One time out of memory flag -+ */ -+static unsigned int oom_flag; -+ -+static int titan_ge_poll(struct net_device *netdev, int *budget); -+ -+static int titan_ge_receive_queue(struct net_device *, unsigned int); -+ -+static struct platform_device *titan_ge_device[3]; -+ -+/* MAC Address */ -+extern unsigned char titan_ge_mac_addr_base[6]; -+ -+unsigned long titan_ge_base; -+static unsigned long titan_ge_sram; -+ -+static char titan_string[] = "titan"; -+ -+/* -+ * The Titan GE has two alignment requirements: -+ * -> skb->data to be cacheline aligned (32 byte) -+ * -> IP header alignment to 16 bytes -+ * -+ * The latter is not implemented. So, that results in an extra copy on -+ * the Rx. This is a big performance hog. For the former case, the -+ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size -+ * requested is calculated: -+ * -+ * Ethernet Frame Size : 1518 -+ * Ethernet Header : 14 -+ * Future Titan change for IP header alignment : 2 -+ * -+ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header -+ * alignment, we use skb_reserve(). -+ */ -+ -+#define ALIGNED_RX_SKB_ADDR(addr) \ -+ ((((unsigned long)(addr) + (64UL - 1UL)) \ -+ & ~(64UL - 1UL)) - (unsigned long)(addr)) -+ -+#define titan_ge_alloc_skb(__length, __gfp_flags) \ -+({ struct sk_buff *__skb; \ -+ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \ -+ if(__skb) { \ -+ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \ -+ if(__offset) \ -+ skb_reserve(__skb, __offset); \ -+ } \ -+ __skb; \ -+}) -+ -+/* -+ * Configure the GMII block of the Titan based on what the PHY tells us -+ */ -+static void titan_ge_gmii_config(int port_num) -+{ -+ unsigned int reg_data = 0, phy_reg; -+ int err; -+ -+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); -+ -+ if (err == TITAN_GE_MDIO_ERROR) { -+ printk(KERN_ERR -+ "Could not read PHY control register 0x11 \n"); -+ printk(KERN_ERR -+ "Setting speed to 1000 Mbps and Duplex to Full \n"); -+ -+ return; -+ } -+ -+ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0); -+ -+ if (phy_reg & 0x8000) { -+ if (phy_reg & 0x2000) { -+ /* Full Duplex and 1000 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x201); -+ } else { -+ /* Half Duplex and 1000 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x2201); -+ } -+ } -+ if (phy_reg & 0x4000) { -+ if (phy_reg & 0x2000) { -+ /* Full Duplex and 100 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x100); -+ } else { -+ /* Half Duplex and 100 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x2100); -+ } -+ } -+ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL + -+ (port_num << 12)); -+ reg_data |= 0x3; -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL + -+ (port_num << 12)), reg_data); -+} -+ -+/* -+ * Enable the TMAC if it is not -+ */ -+static void titan_ge_enable_tx(unsigned int port_num) -+{ -+ unsigned long reg_data; -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); -+ if (!(reg_data & 0x8000)) { -+ printk("TMAC disabled for port %d!! \n", port_num); -+ -+ reg_data |= 0x0001; /* Enable TMAC */ -+ reg_data |= 0x4000; /* CRC Check Enable */ -+ reg_data |= 0x2000; /* Padding enable */ -+ reg_data |= 0x0800; /* CRC Add enable */ -+ reg_data |= 0x0080; /* PAUSE frame */ -+ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ } -+} -+ -+/* -+ * Tx Timeout function -+ */ -+static void titan_ge_tx_timeout(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ printk(KERN_INFO "%s: TX timeout ", netdev->name); -+ printk(KERN_INFO "Resetting card \n"); -+ -+ /* Do the reset outside of interrupt context */ -+ schedule_work(&titan_ge_eth->tx_timeout_task); -+} -+ -+/* -+ * Update the AFX tables for UC and MC for slice 0 only -+ */ -+static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth) -+{ -+ int port = titan_ge_eth->port_num; -+ unsigned int i; -+ volatile unsigned long reg_data = 0; -+ u8 p_addr[6]; -+ -+ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6); -+ -+ /* Set the MAC address here for TMAC and RMAC */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1); -+ /* Configure the eight address filters */ -+ for (i = 0; i < 8; i++) { -+ /* Select each of the eight filters */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 + -+ (port << 12)), i); -+ -+ /* Configure the match */ -+ reg_data = 0x9; /* Forward Enable Bit */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 + -+ (port << 12)), reg_data); -+ -+ /* Finally, AFX Exact Match Address Registers */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ -+ /* VLAN id set to 0 */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + -+ (port << 12)), 0); -+ } -+} -+ -+/* -+ * Actual Routine to reset the adapter when the timeout occurred -+ */ -+static void titan_ge_tx_timeout_task(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ int port = titan_ge_eth->port_num; -+ -+ printk("Titan GE: Transmit timed out. Resetting ... \n"); -+ -+ /* Dump debug info */ -+ printk(KERN_ERR "TRTG cause : %x \n", -+ TITAN_GE_READ(0x100c + (port << 12))); -+ -+ /* Fix this for the other ports */ -+ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c)); -+ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040)); -+ printk(KERN_ERR "XDMA GDI ERROR : %x \n", -+ TITAN_GE_READ(0x5008 + (port << 8))); -+ printk(KERN_ERR "CHANNEL ERROR: %x \n", -+ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT -+ + (port << 8))); -+ -+ netif_device_detach(netdev); -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ titan_ge_port_start(netdev, titan_ge_eth); -+ netif_device_attach(netdev); -+} -+ -+/* -+ * Change the MTU of the Ethernet Device -+ */ -+static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned long flags; -+ -+ if ((new_mtu > 9500) || (new_mtu < 64)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ netdev->mtu = new_mtu; -+ -+ /* Now we have to reopen the interface so that SKBs with the new -+ * size will be allocated */ -+ -+ if (netif_running(netdev)) { -+ titan_ge_eth_stop(netdev); -+ -+ if (titan_ge_eth_open(netdev) != TITAN_OK) { -+ printk(KERN_ERR -+ "%s: Fatal error on opening device\n", -+ netdev->name); -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ return -1; -+ } -+ } -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ return 0; -+} -+ -+/* -+ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line -+ * only. Once an interrupt is triggered, figure out the port and then check -+ * the channel. -+ */ -+static irqreturn_t titan_ge_int_handler(int irq, void *dev_id) -+{ -+ struct net_device *netdev = (struct net_device *) dev_id; -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int reg_data; -+ unsigned int eth_int_cause_error = 0, is; -+ unsigned long eth_int_cause1; -+ int err = 0; -+#ifdef CONFIG_SMP -+ unsigned long eth_int_cause2; -+#endif -+ -+ /* Ack the CPU interrupt */ -+ switch (port_num) { -+ case 0: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is); -+#endif -+ break; -+ -+ case 1: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is); -+#endif -+ break; -+ -+ case 2: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is); -+#endif -+ } -+ -+ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); -+#ifdef CONFIG_SMP -+ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B); -+#endif -+ -+ /* Spurious interrupt */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) { -+#else -+ if (eth_int_cause1 == 0) { -+#endif -+ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT + -+ (port_num << 8)); -+ -+ if (eth_int_cause_error == 0) -+ return IRQ_NONE; -+ } -+ -+ /* Handle Tx first. No need to ack interrupts */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 & 0x20202) || -+ (eth_int_cause2 & 0x20202) ) -+#else -+ if (eth_int_cause1 & 0x20202) -+#endif -+ titan_ge_free_tx_queue(titan_ge_eth); -+ -+ /* Handle the Rx next */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 & 0x10101) || -+ (eth_int_cause2 & 0x10101)) { -+#else -+ if (eth_int_cause1 & 0x10101) { -+#endif -+ if (netif_rx_schedule_prep(netdev)) { -+ unsigned int ack; -+ -+ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ /* Disable Tx and Rx both */ -+ if (port_num == 0) -+ ack &= ~(0x3); -+ if (port_num == 1) -+ ack &= ~(0x300); -+ -+ if (port_num == 2) -+ ack &= ~(0x30000); -+ -+ /* Interrupts have been disabled */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack); -+ -+ __netif_rx_schedule(netdev); -+ } -+ } -+ -+ /* Handle error interrupts */ -+ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) { -+ printk(KERN_ERR -+ "XDMA Channel Error : %x on port %d\n", -+ eth_int_cause_error, port_num); -+ -+ printk(KERN_ERR -+ "XDMA GDI Hardware error : %x on port %d\n", -+ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num); -+ -+ printk(KERN_ERR -+ "XDMA currently has %d Rx descriptors \n", -+ TITAN_GE_READ(0x5048 + (port_num << 8))); -+ -+ printk(KERN_ERR -+ "XDMA currently has prefetcted %d Rx descriptors \n", -+ TITAN_GE_READ(0x505c + (port_num << 8))); -+ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + -+ (port_num << 8)), eth_int_cause_error); -+ } -+ -+ /* -+ * PHY interrupt to inform abt the changes. Reading the -+ * PHY Status register will clear the interrupt -+ */ -+ if ((!(eth_int_cause1 & 0x30303)) && -+ (eth_int_cause_error == 0)) { -+ err = -+ titan_ge_mdio_read(port_num, -+ TITAN_GE_MDIO_PHY_IS, ®_data); -+ -+ if (reg_data & 0x0400) { -+ /* Link status change */ -+ titan_ge_mdio_read(port_num, -+ TITAN_GE_MDIO_PHY_STATUS, ®_data); -+ if (!(reg_data & 0x0400)) { -+ /* Link is down */ -+ netif_carrier_off(netdev); -+ netif_stop_queue(netdev); -+ } else { -+ /* Link is up */ -+ netif_carrier_on(netdev); -+ netif_wake_queue(netdev); -+ -+ /* Enable the queue */ -+ titan_ge_enable_tx(port_num); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Multicast and Promiscuous mode set. The -+ * set_multi entry point is called whenever the -+ * multicast address list or the network interface -+ * flags are updated. -+ */ -+static void titan_ge_set_multi(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned long reg_data; -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + -+ (port_num << 12)); -+ -+ if (netdev->flags & IFF_PROMISC) { -+ reg_data |= 0x2; -+ } -+ else if (netdev->flags & IFF_ALLMULTI) { -+ reg_data |= 0x01; -+ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */ -+ } -+ else { -+ reg_data = 0x2; -+ } -+ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + -+ (port_num << 12)), reg_data); -+ if (reg_data & 0x01) { -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI + -+ (port_num << 12)), 0xffff); -+ } -+} -+ -+/* -+ * Open the network device -+ */ -+static int titan_ge_open(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num; -+ int retval; -+ -+ retval = request_irq(irq, titan_ge_int_handler, -+ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev); -+ -+ if (retval != 0) { -+ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n"); -+ return -1; -+ } -+ -+ netdev->irq = irq; -+ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num); -+ -+ spin_lock_irq(&(titan_ge_eth->lock)); -+ -+ if (titan_ge_eth_open(netdev) != TITAN_OK) { -+ spin_unlock_irq(&(titan_ge_eth->lock)); -+ printk("%s: Error opening interface \n", netdev->name); -+ free_irq(netdev->irq, netdev); -+ return -EBUSY; -+ } -+ -+ spin_unlock_irq(&(titan_ge_eth->lock)); -+ -+ return 0; -+} -+ -+/* -+ * Allocate the SKBs for the Rx ring. Also used -+ * for refilling the queue -+ */ -+static int titan_ge_rx_task(struct net_device *netdev, -+ titan_ge_port_info *titan_ge_port) -+{ -+ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev; -+ volatile titan_ge_rx_desc *rx_desc; -+ struct sk_buff *skb; -+ int rx_used_desc; -+ int count = 0; -+ -+ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) { -+ -+ /* First try to get the skb from the recycler */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC); -+#else -+ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC); -+#endif -+ if (unlikely(!skb)) { -+ /* OOM, set the flag */ -+ printk("OOM \n"); -+ oom_flag = 1; -+ break; -+ } -+ count++; -+ skb->dev = netdev; -+ -+ titan_ge_port->rx_ring_skbs++; -+ -+ rx_used_desc = titan_ge_port->rx_used_desc_q; -+ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]); -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ rx_desc->buffer_addr = dma_map_single(device, skb->data, -+ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE); -+#else -+ rx_desc->buffer_addr = dma_map_single(device, skb->data, -+ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE); -+#endif -+ -+ titan_ge_port->rx_skb[rx_used_desc] = skb; -+ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED; -+ -+ titan_ge_port->rx_used_desc_q = -+ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE; -+ } -+ -+ return count; -+} -+ -+/* -+ * Actual init of the Tital GE port. There is one register for -+ * the channel configuration -+ */ -+static void titan_port_init(struct net_device *netdev, -+ titan_ge_port_info * titan_ge_eth) -+{ -+ unsigned long reg_data; -+ -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ -+ /* First reset the TMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data |= 0x80000000; -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ udelay(30); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data &= ~(0xc0000000); -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ /* Now reset the RMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data |= 0x00080000; -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ udelay(30); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data &= ~(0x000c0000); -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+} -+ -+/* -+ * Start the port. All the hardware specific configuration -+ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX -+ * go here -+ */ -+static int titan_ge_port_start(struct net_device *netdev, -+ titan_ge_port_info * titan_port) -+{ -+ volatile unsigned long reg_data, reg_data1; -+ int port_num = titan_port->port_num; -+ int count = 0; -+ unsigned long reg_data_1; -+ -+ if (config_done == 0) { -+ reg_data = TITAN_GE_READ(0x0004); -+ reg_data |= 0x100; -+ TITAN_GE_WRITE(0x0004, reg_data); -+ -+ reg_data &= ~(0x100); -+ TITAN_GE_WRITE(0x0004, reg_data); -+ -+ /* Turn on GMII/MII mode and turn off TBI mode */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1); -+ reg_data |= 0x00000700; -+ reg_data &= ~(0x00800000); /* Fencing */ -+ -+ TITAN_GE_WRITE(0x000c, 0x00001100); -+ -+ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data); -+ -+ /* Set the CPU Resource Limit register */ -+ TITAN_GE_WRITE(0x00f8, 0x8); -+ -+ /* Be conservative when using the BIU buffers */ -+ TITAN_GE_WRITE(0x0068, 0x4); -+ } -+ -+ titan_port->tx_threshold = 0; -+ titan_port->rx_threshold = 0; -+ -+ /* We need to write the descriptors for Tx and Rx */ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)), -+ (unsigned long) titan_port->tx_dma); -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)), -+ (unsigned long) titan_port->rx_dma); -+ -+ if (config_done == 0) { -+ /* Step 1: XDMA config */ -+ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG); -+ reg_data &= ~(0x80000000); /* clear reset */ -+ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */ -+ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */ -+ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */ -+ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */ -+ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data); -+ } -+ -+ /* IR register for the XDMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)); -+ reg_data |= 0x80068000; /* No Rx_OOD */ -+ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data); -+ -+ /* Start the Tx and Rx XDMA controller */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)); -+ reg_data &= 0x4fffffff; /* Clear tx reset */ -+ reg_data &= 0xfff4ffff; /* Clear rx reset */ -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ reg_data |= 0xa0 | 0x30030000; -+#else -+ reg_data |= 0x40 | 0x20030000; -+#endif -+ -+#ifndef CONFIG_SMP -+ reg_data &= ~(0x10); -+ reg_data |= 0x0f; /* All of the packet */ -+#endif -+ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data); -+ -+ /* Rx desc count */ -+ count = titan_ge_rx_task(netdev, titan_port); -+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count); -+ count = TITAN_GE_READ(0x5048 + (port_num << 8)); -+ -+ udelay(30); -+ -+ /* -+ * Step 2: Configure the SDQPF, i.e. FIFO -+ */ -+ if (config_done == 0) { -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); -+ reg_data = 0x1; -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ reg_data &= ~(0x1); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); -+ reg_data = 0x1; -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ reg_data &= ~(0x1); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ } -+ /* -+ * Enable RX FIFO 0, 4 and 8 -+ */ -+ if (port_num == 0) { -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10); -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4844); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x4844, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ reg_data |= (0xff << 10); -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4944); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x4944, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ } -+ -+ if (port_num == 1) { -+ reg_data = TITAN_GE_READ(0x4870); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (0xff + 1); -+ -+ TITAN_GE_WRITE(0x4870, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4874); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x4874, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4870, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x494c); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x494c, reg_data); -+ reg_data |= (0xff << 10) | (0xff + 1); -+ TITAN_GE_WRITE(0x494c, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4950); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x4950, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x494c, reg_data); -+ } -+ -+ /* -+ * Titan 1.2 revision does support port #2 -+ */ -+ if (port_num == 2) { -+ /* -+ * Put the descriptors in the SRAM -+ */ -+ reg_data = TITAN_GE_READ(0x48a0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x48a4); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x48a4, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x4958); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ TITAN_GE_WRITE(0x4958, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x495c); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x495c, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ } -+ -+ if (port_num == 2) { -+ reg_data = TITAN_GE_READ(0x48a0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x48a4); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x48a4, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x4958); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ TITAN_GE_WRITE(0x4958, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x495c); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x495c, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ } -+ -+ /* -+ * Step 3: TRTG block enable -+ */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12)); -+ -+ /* -+ * This is the 1.2 revision of the chip. It has fix for the -+ * IP header alignment. Now, the IP header begins at an -+ * aligned address and this wont need an extra copy in the -+ * driver. This performance drawback existed in the previous -+ * versions of the silicon -+ */ -+ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12)); -+ reg_data_1 |= 0x40000000; -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ reg_data_1 |= 0x04000000; -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ mdelay(5); -+ -+ reg_data_1 &= ~(0x04000000); -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ mdelay(5); -+ -+ reg_data |= 0x0001; -+ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data); -+ -+ /* -+ * Step 4: Start the Tx activity -+ */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197); -+#ifdef TITAN_GE_JUMBO_FRAMES -+ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000); -+#endif -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); -+ reg_data |= 0x0001; /* Enable TMAC */ -+ reg_data |= 0x6c70; /* PAUSE also set */ -+ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ udelay(30); -+ -+ /* Destination Address drop bit */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)); -+ reg_data |= 0x218; /* DA_DROP bit and pause */ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data); -+ -+ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3); -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000); -+#endif -+ /* Start the Rx activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); -+ reg_data |= 0x0001; /* RMAC Enable */ -+ reg_data |= 0x0010; /* CRC Check enable */ -+ reg_data |= 0x0040; /* Min Frame check enable */ -+ reg_data |= 0x4400; /* Max Frame check enable */ -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ udelay(30); -+ -+ /* -+ * Enable the Interrupts for Tx and Rx -+ */ -+ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ -+ if (port_num == 0) { -+ reg_data1 |= 0x3; -+#ifdef CONFIG_SMP -+ TITAN_GE_WRITE(0x0038, 0x003); -+#else -+ TITAN_GE_WRITE(0x0038, 0x303); -+#endif -+ } -+ -+ if (port_num == 1) { -+ reg_data1 |= 0x300; -+ } -+ -+ if (port_num == 2) -+ reg_data1 |= 0x30000; -+ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1); -+ TITAN_GE_WRITE(0x003c, 0x300); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */ -+ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */ -+ } -+ -+ /* Priority */ -+ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12)); -+ reg_data &= ~(0x00f00000); -+ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data); -+ -+ /* Step 5: GMII config */ -+ titan_ge_gmii_config(port_num); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(0x1a80, 0); -+ config_done = 1; -+ } -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Function to queue the packet for the Ethernet device -+ */ -+static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth, -+ struct sk_buff * skb) -+{ -+ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev; -+ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q; -+ volatile titan_ge_tx_desc *tx_curr; -+ int port_num = titan_ge_eth->port_num; -+ -+ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]); -+ tx_curr->buffer_addr = -+ dma_map_single(device, skb->data, skb_headlen(skb), -+ DMA_TO_DEVICE); -+ -+ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb; -+ tx_curr->buffer_len = skb_headlen(skb); -+ -+ /* Last descriptor enables interrupt and changes ownership */ -+ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5); -+ -+ /* Kick the XDMA to start the transfer from memory to the FIFO */ -+ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1); -+ -+ /* Current descriptor updated */ -+ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE; -+ -+ /* Prefetch the next descriptor */ -+ prefetch((const void *) -+ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]); -+} -+ -+/* -+ * Actually does the open of the Ethernet device -+ */ -+static int titan_ge_eth_open(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ struct device *device = &titan_ge_device[port_num]->dev; -+ unsigned long reg_data; -+ unsigned int phy_reg; -+ int err = 0; -+ -+ /* Stop the Rx activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ /* Clear the port interrupts */ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0); -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0); -+ } -+ -+ /* Set the MAC Address */ -+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); -+ -+ if (config_done == 0) -+ titan_port_init(netdev, titan_ge_eth); -+ -+ titan_ge_update_afx(titan_ge_eth); -+ -+ /* Allocate the Tx ring now */ -+ titan_ge_eth->tx_ring_skbs = 0; -+ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE; -+ -+ /* Allocate space in the SRAM for the descriptors */ -+ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *) -+ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num); -+ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num; -+ -+ if (!titan_ge_eth->tx_desc_area) { -+ printk(KERN_ERR -+ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n", -+ netdev->name, TITAN_TX_RING_BYTES, port_num); -+ return -ENOMEM; -+ } -+ -+ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size); -+ -+ /* Now initialize the Tx descriptor ring */ -+ titan_ge_init_tx_desc_ring(titan_ge_eth, -+ titan_ge_eth->tx_ring_size, -+ (unsigned long) titan_ge_eth->tx_desc_area, -+ (unsigned long) titan_ge_eth->tx_dma); -+ -+ /* Allocate the Rx ring now */ -+ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE; -+ titan_ge_eth->rx_ring_skbs = 0; -+ -+ titan_ge_eth->rx_desc_area = -+ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num); -+ -+ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num; -+ -+ if (!titan_ge_eth->rx_desc_area) { -+ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", -+ netdev->name, TITAN_RX_RING_BYTES); -+ -+ printk(KERN_ERR "%s: Freeing previously allocated TX queues...", -+ netdev->name); -+ -+ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size, -+ (void *) titan_ge_eth->tx_desc_area, -+ titan_ge_eth->tx_dma); -+ -+ return -ENOMEM; -+ } -+ -+ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size); -+ -+ /* Now initialize the Rx ring */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ if ((titan_ge_init_rx_desc_ring -+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE, -+ (unsigned long) titan_ge_eth->rx_desc_area, 0, -+ (unsigned long) titan_ge_eth->rx_dma)) == 0) -+#else -+ if ((titan_ge_init_rx_desc_ring -+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE, -+ (unsigned long) titan_ge_eth->rx_desc_area, 0, -+ (unsigned long) titan_ge_eth->rx_dma)) == 0) -+#endif -+ panic("%s: Error initializing RX Ring\n", netdev->name); -+ -+ /* Fill the Rx ring with the SKBs */ -+ titan_ge_port_start(netdev, titan_ge_eth); -+ -+ /* -+ * Check if Interrupt Coalscing needs to be turned on. The -+ * values specified in the register is multiplied by -+ * (8 x 64 nanoseconds) to determine when an interrupt should -+ * be sent to the CPU. -+ */ -+ -+ if (TITAN_GE_TX_COAL) { -+ titan_ge_eth->tx_int_coal = -+ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num); -+ } -+ -+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); -+ if (err == TITAN_GE_MDIO_ERROR) { -+ printk(KERN_ERR -+ "Could not read PHY control register 0x11 \n"); -+ return TITAN_ERROR; -+ } -+ if (!(phy_reg & 0x0400)) { -+ netif_carrier_off(netdev); -+ netif_stop_queue(netdev); -+ return TITAN_ERROR; -+ } else { -+ netif_carrier_on(netdev); -+ netif_start_queue(netdev); -+ } -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Queue the packet for Tx. Currently no support for zero copy, -+ * checksum offload and Scatter Gather. The chip does support -+ * Scatter Gather only. But, that wont help here since zero copy -+ * requires support for Tx checksumming also. -+ */ -+int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned long flags; -+ struct net_device_stats *stats; -+//printk("titan_ge_start_xmit\n"); -+ -+ stats = &titan_ge_eth->stats; -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <= -+ (skb_shinfo(skb)->nr_frags + 1)) { -+ netif_stop_queue(netdev); -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ printk(KERN_ERR "Tx OOD \n"); -+ return 1; -+ } -+ -+ titan_ge_tx_queue(titan_ge_eth, skb); -+ titan_ge_eth->tx_ring_skbs++; -+ -+ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) { -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ titan_ge_free_tx_queue(titan_ge_eth); -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ } -+ -+ stats->tx_bytes += skb->len; -+ stats->tx_packets++; -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ netdev->trans_start = jiffies; -+ -+ return 0; -+} -+ -+/* -+ * Actually does the Rx. Rx side checksumming supported. -+ */ -+static int titan_ge_rx(struct net_device *netdev, int port_num, -+ titan_ge_port_info * titan_ge_port, -+ titan_ge_packet * packet) -+{ -+ int rx_curr_desc, rx_used_desc; -+ volatile titan_ge_rx_desc *rx_desc; -+ -+ rx_curr_desc = titan_ge_port->rx_curr_desc_q; -+ rx_used_desc = titan_ge_port->rx_used_desc_q; -+ -+ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) -+ return TITAN_ERROR; -+ -+ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]); -+ -+ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) -+ return TITAN_ERROR; -+ -+ packet->skb = titan_ge_port->rx_skb[rx_curr_desc]; -+ packet->len = (rx_desc->cmd_sts & 0x7fff); -+ -+ /* -+ * At this point, we dont know if the checksumming -+ * actually helps relieve CPU. So, keep it for -+ * port 0 only -+ */ -+ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16); -+ packet->cmd_sts = rx_desc->cmd_sts; -+ -+ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE; -+ -+ /* Prefetch the next descriptor */ -+ prefetch((const void *) -+ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Free the Tx queue of the used SKBs -+ */ -+static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth) -+{ -+ unsigned long flags; -+ -+ /* Take the lock */ -+ spin_lock_irqsave(&(titan_ge_eth->lock), flags); -+ -+ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) -+ if (titan_ge_eth->tx_ring_skbs != 1) -+ titan_ge_eth->tx_ring_skbs--; -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Threshold beyond which we do the cleaning of -+ * Tx queue and new allocation for the Rx -+ * queue -+ */ -+#define TX_THRESHOLD 4 -+#define RX_THRESHOLD 10 -+ -+/* -+ * Receive the packets and send it to the kernel. -+ */ -+static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ titan_ge_packet packet; -+ struct net_device_stats *stats; -+ struct sk_buff *skb; -+ unsigned long received_packets = 0; -+ unsigned int ack; -+ -+ stats = &titan_ge_eth->stats; -+ -+ while ((--max) -+ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) { -+ skb = (struct sk_buff *) packet.skb; -+ -+ titan_ge_eth->rx_ring_skbs--; -+ -+ if (--titan_ge_eth->rx_work_limit < 0) -+ break; -+ received_packets++; -+ -+ stats->rx_packets++; -+ stats->rx_bytes += packet.len; -+ -+ if ((packet.cmd_sts & TITAN_GE_RX_PERR) || -+ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) || -+ (packet.cmd_sts & TITAN_GE_RX_TRUNC) || -+ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) { -+ stats->rx_dropped++; -+ dev_kfree_skb_any(skb); -+ -+ continue; -+ } -+ /* -+ * Either support fast path or slow path. Decision -+ * making can really slow down the performance. The -+ * idea is to cut down the number of checks and improve -+ * the fastpath. -+ */ -+ -+ skb_put(skb, packet.len - 2); -+ -+ /* -+ * Increment data pointer by two since thats where -+ * the MAC starts -+ */ -+ skb_reserve(skb, 2); -+ skb->protocol = eth_type_trans(skb, netdev); -+ netif_receive_skb(skb); -+ -+ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) { -+ ack = titan_ge_rx_task(netdev, titan_ge_eth); -+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack); -+ titan_ge_eth->rx_threshold = 0; -+ } else -+ titan_ge_eth->rx_threshold++; -+ -+ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) { -+ titan_ge_eth->tx_threshold = 0; -+ titan_ge_free_tx_queue(titan_ge_eth); -+ } -+ else -+ titan_ge_eth->tx_threshold++; -+ -+ } -+ return received_packets; -+} -+ -+ -+/* -+ * Enable the Rx side interrupts -+ */ -+static void titan_ge_enable_int(unsigned int port_num, -+ titan_ge_port_info *titan_ge_eth, -+ struct net_device *netdev) -+{ -+ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ -+ if (port_num == 0) -+ reg_data |= 0x3; -+ if (port_num == 1) -+ reg_data |= 0x300; -+ if (port_num == 2) -+ reg_data |= 0x30000; -+ -+ /* Re-enable interrupts */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data); -+} -+ -+/* -+ * Main function to handle the polling for Rx side NAPI. -+ * Receive interrupts have been disabled at this point. -+ * The poll schedules the transmit followed by receive. -+ */ -+static int titan_ge_poll(struct net_device *netdev, int *budget) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ int port_num = titan_ge_eth->port_num; -+ int work_done = 0; -+ unsigned long flags, status; -+ -+ titan_ge_eth->rx_work_limit = *budget; -+ if (titan_ge_eth->rx_work_limit > netdev->quota) -+ titan_ge_eth->rx_work_limit = netdev->quota; -+ -+ do { -+ /* Do the transmit cleaning work here */ -+ titan_ge_free_tx_queue(titan_ge_eth); -+ -+ /* Ack the Rx interrupts */ -+ if (port_num == 0) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3); -+ if (port_num == 1) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300); -+ if (port_num == 2) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000); -+ -+ work_done += titan_ge_receive_queue(netdev, 0); -+ -+ /* Out of quota and there is work to be done */ -+ if (titan_ge_eth->rx_work_limit < 0) -+ goto not_done; -+ -+ /* Receive alloc_skb could lead to OOM */ -+ if (oom_flag == 1) { -+ oom_flag = 0; -+ goto oom; -+ } -+ -+ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); -+ } while (status & 0x30300); -+ -+ /* If we are here, then no more interrupts to process */ -+ goto done; -+ -+not_done: -+ *budget -= work_done; -+ netdev->quota -= work_done; -+ return 1; -+ -+oom: -+ printk(KERN_ERR "OOM \n"); -+ netif_rx_complete(netdev); -+ return 0; -+ -+done: -+ /* -+ * No more packets on the poll list. Turn the interrupts -+ * back on and we should be able to catch the new -+ * packets in the interrupt handler -+ */ -+ if (!work_done) -+ work_done = 1; -+ -+ *budget -= work_done; -+ netdev->quota -= work_done; -+ -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ /* Remove us from the poll list */ -+ netif_rx_complete(netdev); -+ -+ /* Re-enable interrupts */ -+ titan_ge_enable_int(port_num, titan_ge_eth, netdev); -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ return 0; -+} -+ -+/* -+ * Close the network device -+ */ -+int titan_ge_stop(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ spin_lock_irq(&(titan_ge_eth->lock)); -+ titan_ge_eth_stop(netdev); -+ free_irq(netdev->irq, netdev); -+ spin_unlock_irq(&titan_ge_eth->lock); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Free the Tx ring -+ */ -+static void titan_ge_free_tx_rings(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int curr; -+ unsigned long reg_data; -+ -+ /* Stop the Tx DMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)); -+ reg_data |= 0xc0000000; -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)), reg_data); -+ -+ /* Disable the TMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ for (curr = 0; -+ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE); -+ curr++) { -+ if (titan_ge_eth->tx_skb[curr]) { -+ dev_kfree_skb(titan_ge_eth->tx_skb[curr]); -+ titan_ge_eth->tx_ring_skbs--; -+ } -+ } -+ -+ if (titan_ge_eth->tx_ring_skbs != 0) -+ printk -+ ("%s: Error on Tx descriptor free - could not free %d" -+ " descriptors\n", netdev->name, -+ titan_ge_eth->tx_ring_skbs); -+ -+#ifndef TITAN_RX_RING_IN_SRAM -+ dma_free_coherent(&titan_ge_device[port_num]->dev, -+ titan_ge_eth->tx_desc_area_size, -+ (void *) titan_ge_eth->tx_desc_area, -+ titan_ge_eth->tx_dma); -+#endif -+} -+ -+/* -+ * Free the Rx ring -+ */ -+static void titan_ge_free_rx_rings(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int curr; -+ unsigned long reg_data; -+ -+ /* Stop the Rx DMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)); -+ reg_data |= 0x000c0000; -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)), reg_data); -+ -+ /* Disable the RMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ for (curr = 0; -+ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE); -+ curr++) { -+ if (titan_ge_eth->rx_skb[curr]) { -+ dev_kfree_skb(titan_ge_eth->rx_skb[curr]); -+ titan_ge_eth->rx_ring_skbs--; -+ } -+ } -+ -+ if (titan_ge_eth->rx_ring_skbs != 0) -+ printk(KERN_ERR -+ "%s: Error in freeing Rx Ring. %d skb's still" -+ " stuck in RX Ring - ignoring them\n", netdev->name, -+ titan_ge_eth->rx_ring_skbs); -+ -+#ifndef TITAN_RX_RING_IN_SRAM -+ dma_free_coherent(&titan_ge_device[port_num]->dev, -+ titan_ge_eth->rx_desc_area_size, -+ (void *) titan_ge_eth->rx_desc_area, -+ titan_ge_eth->rx_dma); -+#endif -+} -+ -+/* -+ * Actually does the stop of the Ethernet device -+ */ -+static void titan_ge_eth_stop(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ netif_stop_queue(netdev); -+ -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ -+ titan_ge_free_tx_rings(netdev); -+ titan_ge_free_rx_rings(netdev); -+ -+ /* Disable the Tx and Rx Interrupts for all channels */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0); -+} -+ -+/* -+ * Update the MAC address. Note that we have to write the -+ * address in three station registers, 16 bits each. And this -+ * has to be done for TMAC and RMAC -+ */ -+static void titan_ge_update_mac_address(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ u8 p_addr[6]; -+ -+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); -+ memcpy(p_addr, netdev->dev_addr, 6); -+ -+ /* Update the Address Filtering Match tables */ -+ titan_ge_update_afx(titan_ge_eth); -+ -+ printk("Station MAC : %d %d %d %d %d %d \n", -+ p_addr[5], p_addr[4], p_addr[3], -+ p_addr[2], p_addr[1], p_addr[0]); -+ -+ /* Set the MAC address here for TMAC and RMAC */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+} -+ -+/* -+ * Set the MAC address of the Ethernet device -+ */ -+static int titan_ge_set_mac_address(struct net_device *dev, void *addr) -+{ -+ titan_ge_port_info *tp = netdev_priv(dev); -+ struct sockaddr *sa = addr; -+ -+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); -+ -+ spin_lock_irq(&tp->lock); -+ titan_ge_update_mac_address(dev); -+ spin_unlock_irq(&tp->lock); -+ -+ return 0; -+} -+ -+/* -+ * Get the Ethernet device stats -+ */ -+static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ return &titan_ge_eth->stats; -+} -+ -+/* -+ * Initialize the Rx descriptor ring for the Titan Ge -+ */ -+static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port, -+ int rx_desc_num, -+ int rx_buff_size, -+ unsigned long rx_desc_base_addr, -+ unsigned long rx_buff_base_addr, -+ unsigned long rx_dma) -+{ -+ volatile titan_ge_rx_desc *rx_desc; -+ unsigned long buffer_addr; -+ int index; -+ unsigned long titan_ge_rx_desc_bus = rx_dma; -+ -+ buffer_addr = rx_buff_base_addr; -+ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr; -+ -+ /* Check alignment */ -+ if (rx_buff_base_addr & 0xF) -+ return 0; -+ -+ /* Check Rx buffer size */ -+ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER)) -+ return 0; -+ -+ /* 64-bit alignment -+ if ((rx_buff_base_addr + rx_buff_size) & 0x7) -+ return 0; */ -+ -+ /* Initialize the Rx desc ring */ -+ for (index = 0; index < rx_desc_num; index++) { -+ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc); -+ rx_desc[index].cmd_sts = 0; -+ rx_desc[index].buffer_addr = buffer_addr; -+ titan_eth_port->rx_skb[index] = NULL; -+ buffer_addr += rx_buff_size; -+ } -+ -+ titan_eth_port->rx_curr_desc_q = 0; -+ titan_eth_port->rx_used_desc_q = 0; -+ -+ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr; -+ titan_eth_port->rx_desc_area_size = -+ rx_desc_num * sizeof(titan_ge_rx_desc); -+ -+ titan_eth_port->rx_dma = rx_dma; -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Initialize the Tx descriptor ring. Descriptors in the SRAM -+ */ -+static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port, -+ int tx_desc_num, -+ unsigned long tx_desc_base_addr, -+ unsigned long tx_dma) -+{ -+ titan_ge_tx_desc *tx_desc; -+ int index; -+ unsigned long titan_ge_tx_desc_bus = tx_dma; -+ -+ if (tx_desc_base_addr & 0xF) -+ return 0; -+ -+ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr; -+ -+ for (index = 0; index < tx_desc_num; index++) { -+ titan_ge_port->tx_dma_array[index] = -+ (dma_addr_t) titan_ge_tx_desc_bus; -+ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc); -+ tx_desc[index].cmd_sts = 0x0000; -+ tx_desc[index].buffer_len = 0; -+ tx_desc[index].buffer_addr = 0x00000000; -+ titan_ge_port->tx_skb[index] = NULL; -+ } -+ -+ titan_ge_port->tx_curr_desc_q = 0; -+ titan_ge_port->tx_used_desc_q = 0; -+ -+ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr; -+ titan_ge_port->tx_desc_area_size = -+ tx_desc_num * sizeof(titan_ge_tx_desc); -+ -+ titan_ge_port->tx_dma = tx_dma; -+ return TITAN_OK; -+} -+ -+/* -+ * Initialize the device as an Ethernet device -+ */ -+static int __init titan_ge_probe(struct device *device) -+{ -+ titan_ge_port_info *titan_ge_eth; -+ struct net_device *netdev; -+ int port = to_platform_device(device)->id; -+ int err; -+ -+ netdev = alloc_etherdev(sizeof(titan_ge_port_info)); -+ if (!netdev) { -+ err = -ENODEV; -+ goto out; -+ } -+ -+ netdev->open = titan_ge_open; -+ netdev->stop = titan_ge_stop; -+ netdev->hard_start_xmit = titan_ge_start_xmit; -+ netdev->get_stats = titan_ge_get_stats; -+ netdev->set_multicast_list = titan_ge_set_multi; -+ netdev->set_mac_address = titan_ge_set_mac_address; -+ -+ /* Tx timeout */ -+ netdev->tx_timeout = titan_ge_tx_timeout; -+ netdev->watchdog_timeo = 2 * HZ; -+ -+ /* Set these to very high values */ -+ netdev->poll = titan_ge_poll; -+ netdev->weight = 64; -+ -+ netdev->tx_queue_len = TITAN_GE_TX_QUEUE; -+ netif_carrier_off(netdev); -+ netdev->base_addr = 0; -+ -+ netdev->change_mtu = titan_ge_change_mtu; -+ -+ titan_ge_eth = netdev_priv(netdev); -+ /* Allocation of memory for the driver structures */ -+ -+ titan_ge_eth->port_num = port; -+ -+ /* Configure the Tx timeout handler */ -+ INIT_WORK(&titan_ge_eth->tx_timeout_task, -+ (void (*)(void *)) titan_ge_tx_timeout_task, netdev); -+ -+ spin_lock_init(&titan_ge_eth->lock); -+ -+ /* set MAC addresses */ -+ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6); -+ netdev->dev_addr[5] += port; -+ -+ err = register_netdev(netdev); -+ -+ if (err) -+ goto out_free_netdev; -+ -+ printk(KERN_NOTICE -+ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", -+ netdev->name, port, netdev->dev_addr[0], -+ netdev->dev_addr[1], netdev->dev_addr[2], -+ netdev->dev_addr[3], netdev->dev_addr[4], -+ netdev->dev_addr[5]); -+ -+ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n"); -+ -+ return 0; -+ -+out_free_netdev: -+ kfree(netdev); -+ -+out: -+ return err; -+} -+ -+static void __devexit titan_device_remove(struct device *device) -+{ -+} -+ -+/* -+ * Reset the Ethernet port -+ */ -+static void titan_ge_port_reset(unsigned int port_num) -+{ -+ unsigned int reg_data; -+ -+ /* Stop the Tx port activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x0001); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ /* Stop the Rx port activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x0001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ return; -+} -+ -+/* -+ * Return the Tx desc after use by the XDMA -+ */ -+static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port) -+{ -+ int tx_desc_used; -+ struct sk_buff *skb; -+ -+ tx_desc_used = titan_ge_eth->tx_used_desc_q; -+ -+ /* return right away */ -+ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q) -+ return TITAN_ERROR; -+ -+ /* Now the critical stuff */ -+ skb = titan_ge_eth->tx_skb[tx_desc_used]; -+ -+ dev_kfree_skb_any(skb); -+ -+ titan_ge_eth->tx_skb[tx_desc_used] = NULL; -+ titan_ge_eth->tx_used_desc_q = -+ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE; -+ -+ return 0; -+} -+ -+/* -+ * Coalescing for the Tx path -+ */ -+static unsigned long titan_ge_tx_coal(unsigned long delay, int port) -+{ -+ unsigned long rx_delay; -+ -+ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING); -+ delay = (delay << 16) | rx_delay; -+ -+ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay); -+ TITAN_GE_WRITE(0x5038, delay); -+ -+ return delay; -+} -+ -+static struct device_driver titan_soc_driver = { -+ .name = titan_string, -+ .bus = &platform_bus_type, -+ .probe = titan_ge_probe, -+ .remove = __devexit_p(titan_device_remove), -+}; -+ -+static void titan_platform_release (struct device *device) -+{ -+ struct platform_device *pldev; -+ -+ /* free device */ -+ pldev = to_platform_device (device); -+ kfree (pldev); -+} -+ -+/* -+ * Register the Titan GE with the kernel -+ */ -+static int __init titan_ge_init_module(void) -+{ -+ struct platform_device *pldev; -+ unsigned int version, device; -+ int i; -+ -+ printk(KERN_NOTICE -+ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n"); -+ -+ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE); -+ if (!titan_ge_base) { -+ printk("Mapping Titan GE failed\n"); -+ goto out; -+ } -+ -+ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID); -+ version = (device & 0x000f0000) >> 16; -+ device &= 0x0000ffff; -+ -+ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version); -+ -+#ifdef TITAN_RX_RING_IN_SRAM -+ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE, -+ TITAN_SRAM_SIZE); -+ if (!titan_ge_sram) { -+ printk("Mapping Titan SRAM failed\n"); -+ goto out_unmap_ge; -+ } -+#endif -+ -+ if (driver_register(&titan_soc_driver)) { -+ printk(KERN_ERR "Driver registration failed\n"); -+ goto out_unmap_sram; -+ } -+ -+ for (i = 0; i < 3; i++) { -+ titan_ge_device[i] = NULL; -+ -+ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) -+ continue; -+ -+ memset (pldev, 0, sizeof (*pldev)); -+ pldev->name = titan_string; -+ pldev->id = i; -+ pldev->dev.release = titan_platform_release; -+ titan_ge_device[i] = pldev; -+ -+ if (platform_device_register (pldev)) { -+ kfree (pldev); -+ titan_ge_device[i] = NULL; -+ continue; -+ } -+ -+ if (!pldev->dev.driver) { -+ /* -+ * The driver was not bound to this device, there was -+ * no hardware at this address. Unregister it, as the -+ * release fuction will take care of freeing the -+ * allocated structure -+ */ -+ titan_ge_device[i] = NULL; -+ platform_device_unregister (pldev); -+ } -+ } -+ -+ return 0; -+ -+out_unmap_sram: -+ iounmap((void *)titan_ge_sram); -+ -+out_unmap_ge: -+ iounmap((void *)titan_ge_base); -+ -+out: -+ return -ENOMEM; -+} -+ -+/* -+ * Unregister the Titan GE from the kernel -+ */ -+static void __exit titan_ge_cleanup_module(void) -+{ -+ int i; -+ -+ driver_unregister(&titan_soc_driver); -+ -+ for (i = 0; i < 3; i++) { -+ if (titan_ge_device[i]) { -+ platform_device_unregister (titan_ge_device[i]); -+ titan_ge_device[i] = NULL; -+ } -+ } -+ -+ iounmap((void *)titan_ge_sram); -+ iounmap((void *)titan_ge_base); -+} -+ -+MODULE_AUTHOR("Manish Lachwani "); -+MODULE_DESCRIPTION("Titan GE Ethernet driver"); -+MODULE_LICENSE("GPL"); -+ -+module_init(titan_ge_init_module); -+module_exit(titan_ge_cleanup_module); -diff --git a/drivers/net/titan_ge.h b/drivers/net/titan_ge.h -new file mode 100644 -index 0000000..3719f78 ---- /dev/null -+++ b/drivers/net/titan_ge.h -@@ -0,0 +1,415 @@ -+#ifndef _TITAN_GE_H_ -+#define _TITAN_GE_H_ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * These functions should be later moved to a more generic location since there -+ * will be others accessing it also -+ */ -+ -+/* -+ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in -+ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 -+ * register. -+ */ -+ -+#define TITAN_GE_BASE 0xfe000000UL -+#define TITAN_GE_SIZE 0x10000UL -+ -+extern unsigned long titan_ge_base; -+ -+#define TITAN_GE_WRITE(offset, data) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) = (data) -+ -+#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset)) -+ -+#ifndef msec_delay -+#define msec_delay(x) do { if(in_interrupt()) { \ -+ /* Don't mdelay in interrupt context! */ \ -+ BUG(); \ -+ } else { \ -+ set_current_state(TASK_UNINTERRUPTIBLE); \ -+ schedule_timeout((x * HZ)/1000); \ -+ } } while(0) -+#endif -+ -+#define TITAN_GE_PORT_0 -+ -+#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4) -+#define TITAN_SRAM_SIZE 0x2000UL -+ -+/* -+ * We may need these constants -+ */ -+#define TITAN_BIT0 0x00000001 -+#define TITAN_BIT1 0x00000002 -+#define TITAN_BIT2 0x00000004 -+#define TITAN_BIT3 0x00000008 -+#define TITAN_BIT4 0x00000010 -+#define TITAN_BIT5 0x00000020 -+#define TITAN_BIT6 0x00000040 -+#define TITAN_BIT7 0x00000080 -+#define TITAN_BIT8 0x00000100 -+#define TITAN_BIT9 0x00000200 -+#define TITAN_BIT10 0x00000400 -+#define TITAN_BIT11 0x00000800 -+#define TITAN_BIT12 0x00001000 -+#define TITAN_BIT13 0x00002000 -+#define TITAN_BIT14 0x00004000 -+#define TITAN_BIT15 0x00008000 -+#define TITAN_BIT16 0x00010000 -+#define TITAN_BIT17 0x00020000 -+#define TITAN_BIT18 0x00040000 -+#define TITAN_BIT19 0x00080000 -+#define TITAN_BIT20 0x00100000 -+#define TITAN_BIT21 0x00200000 -+#define TITAN_BIT22 0x00400000 -+#define TITAN_BIT23 0x00800000 -+#define TITAN_BIT24 0x01000000 -+#define TITAN_BIT25 0x02000000 -+#define TITAN_BIT26 0x04000000 -+#define TITAN_BIT27 0x08000000 -+#define TITAN_BIT28 0x10000000 -+#define TITAN_BIT29 0x20000000 -+#define TITAN_BIT30 0x40000000 -+#define TITAN_BIT31 0x80000000 -+ -+/* Flow Control */ -+#define TITAN_GE_FC_NONE 0x0 -+#define TITAN_GE_FC_FULL 0x1 -+#define TITAN_GE_FC_TX_PAUSE 0x2 -+#define TITAN_GE_FC_RX_PAUSE 0x3 -+ -+/* Duplex Settings */ -+#define TITAN_GE_FULL_DUPLEX 0x1 -+#define TITAN_GE_HALF_DUPLEX 0x2 -+ -+/* Speed settings */ -+#define TITAN_GE_SPEED_1000 0x1 -+#define TITAN_GE_SPEED_100 0x2 -+#define TITAN_GE_SPEED_10 0x3 -+ -+/* Debugging info only */ -+#undef TITAN_DEBUG -+ -+/* Keep the rings in the Titan's SSRAM */ -+#define TITAN_RX_RING_IN_SRAM -+ -+#ifdef CONFIG_64BIT -+#define TITAN_GE_IE_MASK 0xfffffffffb001b64 -+#define TITAN_GE_IE_STATUS 0xfffffffffb001b60 -+#else -+#define TITAN_GE_IE_MASK 0xfb001b64 -+#define TITAN_GE_IE_STATUS 0xfb001b60 -+#endif -+ -+/* Support for Jumbo Frames */ -+#undef TITAN_GE_JUMBO_FRAMES -+ -+/* Rx buffer size */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+#define TITAN_GE_JUMBO_BUFSIZE 9080 -+#else -+#define TITAN_GE_STD_BUFSIZE 1580 -+#endif -+ -+/* -+ * Tx and Rx Interrupt Coalescing parameter. These values are -+ * for 1 Ghz processor. Rx coalescing can be taken care of -+ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing -+ * is not adaptive. Hence, these values need to be adjusted -+ * based on load, CPU speed etc. -+ */ -+#define TITAN_GE_RX_COAL 150 -+#define TITAN_GE_TX_COAL 300 -+ -+#if defined(__BIG_ENDIAN) -+ -+/* Define the Rx descriptor */ -+typedef struct eth_rx_desc { -+ u32 reserved; /* Unused */ -+ u32 buffer_addr; /* CPU buffer address */ -+ u32 cmd_sts; /* Command and Status */ -+ u32 buffer; /* XDMA buffer address */ -+} titan_ge_rx_desc; -+ -+/* Define the Tx descriptor */ -+typedef struct eth_tx_desc { -+ u16 cmd_sts; /* Command, Status and Buffer count */ -+ u16 buffer_len; /* Length of the buffer */ -+ u32 buffer_addr; /* Physical address of the buffer */ -+} titan_ge_tx_desc; -+ -+#elif defined(__LITTLE_ENDIAN) -+ -+/* Define the Rx descriptor */ -+typedef struct eth_rx_desc { -+ u32 buffer_addr; /* CPU buffer address */ -+ u32 reserved; /* Unused */ -+ u32 buffer; /* XDMA buffer address */ -+ u32 cmd_sts; /* Command and Status */ -+} titan_ge_rx_desc; -+ -+/* Define the Tx descriptor */ -+typedef struct eth_tx_desc { -+ u32 buffer_addr; /* Physical address of the buffer */ -+ u16 buffer_len; /* Length of the buffer */ -+ u16 cmd_sts; /* Command, Status and Buffer count */ -+} titan_ge_tx_desc; -+#endif -+ -+/* Default Tx Queue Size */ -+#define TITAN_GE_TX_QUEUE 128 -+#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc)) -+ -+/* Default Rx Queue Size */ -+#define TITAN_GE_RX_QUEUE 64 -+#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc)) -+ -+/* Packet Structure */ -+typedef struct _pkt_info { -+ unsigned int len; -+ unsigned int cmd_sts; -+ unsigned int buffer; -+ struct sk_buff *skb; -+ unsigned int checksum; -+} titan_ge_packet; -+ -+ -+#define PHYS_CNT 3 -+ -+/* Titan Port specific data structure */ -+typedef struct _eth_port_ctrl { -+ unsigned int port_num; -+ u8 port_mac_addr[6]; -+ -+ /* Rx descriptor pointers */ -+ int rx_curr_desc_q, rx_used_desc_q; -+ -+ /* Tx descriptor pointers */ -+ int tx_curr_desc_q, tx_used_desc_q; -+ -+ /* Rx descriptor area */ -+ volatile titan_ge_rx_desc *rx_desc_area; -+ unsigned int rx_desc_area_size; -+ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE]; -+ -+ /* Tx Descriptor area */ -+ volatile titan_ge_tx_desc *tx_desc_area; -+ unsigned int tx_desc_area_size; -+ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE]; -+ -+ /* Timeout task */ -+ struct work_struct tx_timeout_task; -+ -+ /* DMA structures and handles */ -+ dma_addr_t tx_dma; -+ dma_addr_t rx_dma; -+ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE]; -+ -+ /* Device lock */ -+ spinlock_t lock; -+ -+ unsigned int tx_ring_skbs; -+ unsigned int rx_ring_size; -+ unsigned int tx_ring_size; -+ unsigned int rx_ring_skbs; -+ -+ struct net_device_stats stats; -+ -+ /* Tx and Rx coalescing */ -+ unsigned long rx_int_coal; -+ unsigned long tx_int_coal; -+ -+ /* Threshold for replenishing the Rx and Tx rings */ -+ unsigned int tx_threshold; -+ unsigned int rx_threshold; -+ -+ /* NAPI work limit */ -+ unsigned int rx_work_limit; -+} titan_ge_port_info; -+ -+/* Titan specific constants */ -+#define TITAN_ETH_PORT_IRQ 3 -+ -+/* Max Rx buffer */ -+#define TITAN_GE_MAX_RX_BUFFER 65536 -+ -+/* Tx and Rx Error */ -+#define TITAN_GE_ERROR -+ -+/* Rx Descriptor Command and Status */ -+ -+#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */ -+#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */ -+#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */ -+#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */ -+#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */ -+#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */ -+#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */ -+#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */ -+#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */ -+#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */ -+ -+/* Tx Descriptor Command */ -+#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */ -+#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */ -+ -+/* Return Status */ -+#define TITAN_OK 0x1 /* Good Status */ -+#define TITAN_ERROR 0x2 /* Error Status */ -+ -+/* MIB specific register offset */ -+#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */ -+#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */ -+#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */ -+#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */ -+#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */ -+ -+/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */ -+#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040 -+#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050 -+#define TITAN_GE_MSTATX_RXFRAMES 0x0060 -+#define TITAN_GE_MSTATX_RXOCTETS 0x0070 -+#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080 -+#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090 -+#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0 -+#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0 -+#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0 -+#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0 -+#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0 -+#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0 -+#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100 -+#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110 -+#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120 -+#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130 -+#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140 -+#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150 -+#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160 -+#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170 -+#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180 -+#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190 -+#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0 -+#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0 -+#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0 -+#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0 -+#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0 -+#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0 -+#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200 -+#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210 -+#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220 -+#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230 -+#define TITAN_GE_MSTATX_HASHFILTERED 0x0240 -+#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250 -+#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260 -+#define TITAN_GE_MSTATX_TXOCTETS 0x0270 -+#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280 -+#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290 -+#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0 -+#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0 -+#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0 -+#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0 -+#define TITAN_GE_MSTATX_TXMACERROR 0x02E0 -+#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0 -+#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300 -+#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310 -+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320 -+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330 -+#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340 -+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350 -+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360 -+#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370 -+#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380 -+#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390 -+#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0 -+#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0 -+#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0 -+#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0 -+#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0 -+#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0 -+#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400 -+#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410 -+#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420 -+#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430 -+#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440 -+ -+/* Interrupt specific defines */ -+#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */ -+#define TITAN_GE_RESET 0x0004 /* Reset reg */ -+#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */ -+#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */ -+#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */ -+#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/ -+#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/ -+#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */ -+#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */ -+#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/ -+#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */ -+#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/ -+#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */ -+#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */ -+#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */ -+#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */ -+#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */ -+#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */ -+#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */ -+#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */ -+ -+/* Rx MAC defines */ -+#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */ -+#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */ -+#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */ -+#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */ -+#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */ -+#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */ -+#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */ -+ -+/* Tx MAC defines */ -+#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */ -+#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */ -+#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */ -+#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */ -+#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */ -+#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */ -+#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */ -+#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */ -+#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */ -+#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */ -+ -+/* GMII register */ -+#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */ -+#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */ -+#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */ -+ -+/* Tx and Rx XDMA defines */ -+#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */ -+#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */ -+#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */ -+#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */ -+#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */ -+#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */ -+#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */ -+#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */ -+ -+/* AFX (Address Filter Exact) register offsets for Slice 0 */ -+#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/ -+#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/ -+#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */ -+#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */ -+#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */ -+#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */ -+#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */ -+#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */ -+ -+/* Traffic Groomer block */ -+#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */ -+ -+#endif /* _TITAN_GE_H_ */ -+ -diff --git a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c -new file mode 100644 -index 0000000..8a8785b ---- /dev/null -+++ b/drivers/net/titan_mdio.c -@@ -0,0 +1,217 @@ -+/* -+ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports -+ * -+ * Copyright (C) 2003 PMC-Sierra Inc. -+ * Author : Manish Lachwani (lachwani@pmc-sierra.com) -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY -+ * on the Titan. No support for the TBI as yet. -+ * -+ */ -+ -+#include "titan_mdio.h" -+ -+#define MDIO_DEBUG -+ -+/* -+ * Local constants -+ */ -+#define MAX_CLKA 1023 -+#define MAX_PHY_DEV 31 -+#define MAX_PHY_REG 31 -+#define WRITEADDRS_OPCODE 0x0 -+#define READ_OPCODE 0x2 -+#define WRITE_OPCODE 0x1 -+#define MAX_MDIO_POLL 100 -+ -+/* -+ * Titan MDIO and SCMB registers -+ */ -+#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */ -+#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */ -+#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */ -+#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */ -+#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */ -+#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */ -+ -+/* -+ * Function to poll the MDIO -+ */ -+static int titan_ge_mdio_poll(void) -+{ -+ int i, val; -+ -+ for (i = 0; i < MAX_MDIO_POLL; i++) { -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ -+ if (!(val & 0x8000)) -+ return TITAN_GE_MDIO_GOOD; -+ } -+ -+ return TITAN_GE_MDIO_ERROR; -+} -+ -+ -+/* -+ * Initialize and configure the MDIO -+ */ -+int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio) -+{ -+ unsigned long val; -+ -+ /* Reset the SCMB and program into MDIO mode*/ -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000); -+ -+ /* CLK A */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA); -+ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val); -+ -+ /* Preamble Suppresion */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ /* MDIO mode */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Set the PHY address in indirect mode -+ */ -+int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr) -+{ -+ volatile unsigned long val; -+ -+ /* Setup the PHY device */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ /* Write the new address */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Read the MDIO register. This is what the individual parametes mean: -+ * -+ * dev_addr : PHY ID -+ * reg_addr : register offset -+ * -+ * See the spec for the Titan MAC. We operate in the Direct Mode. -+ */ -+ -+#define MAX_RETRIES 2 -+ -+int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata) -+{ -+ volatile unsigned long val; -+ int retries = 0; -+ -+ /* Setup the PHY device */ -+ -+again: -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ val |= 0x4000; -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ udelay(30); -+ -+ /* Issue the read command */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ udelay(30); -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA); -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); -+ -+ udelay(30); -+ -+ if (val & 0x2) { -+ if (retries == MAX_RETRIES) -+ return TITAN_GE_MDIO_ERROR; -+ else { -+ retries++; -+ goto again; -+ } -+ } -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Write to the MDIO register -+ * -+ * dev_addr : PHY ID -+ * reg_addr : register that needs to be written to -+ * -+ */ -+int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data) -+{ -+ volatile unsigned long val; -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ /* Setup the PHY device */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ val |= 0x4000; -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ udelay(30); -+ -+ /* Setup the data to write */ -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data); -+ -+ udelay(30); -+ -+ /* Issue the write command */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ udelay(30); -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); -+ if (val & 0x2) -+ return TITAN_GE_MDIO_ERROR; -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -diff --git a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h -new file mode 100644 -index 0000000..5d23344 ---- /dev/null -+++ b/drivers/net/titan_mdio.h -@@ -0,0 +1,56 @@ -+/* -+ * MDIO used to interact with the PHY when using GMII/MII -+ */ -+#ifndef _TITAN_MDIO_H -+#define _TITAN_MDIO_H -+ -+#include -+#include -+#include -+#include "titan_ge.h" -+ -+ -+#define TITAN_GE_MDIO_ERROR (-9000) -+#define TITAN_GE_MDIO_GOOD 0 -+ -+#define TITAN_GE_MDIO_BASE titan_ge_base -+ -+#define TITAN_GE_MDIO_READ(offset) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) -+ -+#define TITAN_GE_MDIO_WRITE(offset, data) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) = (data) -+ -+ -+/* GMII specific registers */ -+#define TITAN_GE_MARVEL_PHY_ID 0x00 -+#define TITAN_PHY_AUTONEG_ADV 0x04 -+#define TITAN_PHY_LP_ABILITY 0x05 -+#define TITAN_GE_MDIO_MII_CTRL 0x09 -+#define TITAN_GE_MDIO_MII_EXTENDED 0x0f -+#define TITAN_GE_MDIO_PHY_CTRL 0x10 -+#define TITAN_GE_MDIO_PHY_STATUS 0x11 -+#define TITAN_GE_MDIO_PHY_IE 0x12 -+#define TITAN_GE_MDIO_PHY_IS 0x13 -+#define TITAN_GE_MDIO_PHY_LED 0x18 -+#define TITAN_GE_MDIO_PHY_LED_OVER 0x19 -+#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */ -+ -+/* -+ * MDIO Config Structure -+ */ -+typedef struct { -+ unsigned int clka; -+ int mdio_spre; -+ int mdio_mode; -+} titan_ge_mdio_config; -+ -+/* -+ * Function Prototypes -+ */ -+int titan_ge_mdio_setup(titan_ge_mdio_config *); -+int titan_ge_mdio_inaddrs(int, int); -+int titan_ge_mdio_read(int, int, unsigned int *); -+int titan_ge_mdio_write(int, int, unsigned int); -+ -+#endif /* _TITAN_MDIO_H */ -diff --git a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -index 3411671..4d252c1 100644 ---- a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -+++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -@@ -22,6 +22,10 @@ - - static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) - { -+#ifdef CONFIG_LEMOTE_MACH2F -+ /* Allow users to activate rfkill through only the /sys interface */ -+ return 1; -+#else - u8 gpio; - - gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); -@@ -29,6 +33,7 @@ static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) - gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); - - return gpio & priv->rfkill_mask; -+#endif - } - - void rtl8187_rfkill_init(struct ieee80211_hw *hw) -diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig -index 09fde58..eacabd1 100644 ---- a/drivers/platform/Kconfig -+++ b/drivers/platform/Kconfig -@@ -4,5 +4,8 @@ endif - if GOLDFISH - source "drivers/platform/goldfish/Kconfig" - endif -+if MIPS -+source "drivers/platform/mips/Kconfig" -+endif - - source "drivers/platform/chrome/Kconfig" -diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile -index 3656b7b..ca26925 100644 ---- a/drivers/platform/Makefile -+++ b/drivers/platform/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_X86) += x86/ -+obj-$(CONFIG_MIPS) += mips/ - obj-$(CONFIG_OLPC) += olpc/ - obj-$(CONFIG_GOLDFISH) += goldfish/ - obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ -diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig -new file mode 100644 -index 0000000..722d690 ---- /dev/null -+++ b/drivers/platform/mips/Kconfig -@@ -0,0 +1,60 @@ -+# -+# MIPS Platform Specific Drivers -+# -+ -+menuconfig MIPS_PLATFORM_DEVICES -+ bool "MIPS Platform Specific Device Drivers" -+ default y -+ help -+ Say Y here to get to see options for device drivers of various -+ MIPS platforms, including vendor-specific netbook/laptop/pc extension -+ drivers. This option alone does not add any kernel code. -+ -+ If you say N, all options in this submenu will be skipped and disabled. -+ -+if MIPS_PLATFORM_DEVICES -+ -+config LEMOTE_YEELOONG2F -+ tristate "Lemote YeeLoong Laptop" -+ depends on LEMOTE_MACH2F -+ select BACKLIGHT_LCD_SUPPORT -+ select LCD_CLASS_DEVICE -+ select BACKLIGHT_CLASS_DEVICE -+ select POWER_SUPPLY -+ select HWMON -+ select VIDEO_OUTPUT_CONTROL -+ select INPUT_SPARSEKMAP -+ select INPUT_EVDEV -+ depends on INPUT -+ default m -+ help -+ YeeLoong netbook is a mini laptop made by Lemote, which is basically -+ compatible to FuLoong2F mini PC, but it has an extra Embedded -+ Controller(kb3310b) for battery, hotkey, backlight, temperature and -+ fan management. -+ -+config LEMOTE_LYNLOONG2F -+ tristate "Lemote LynLoong PC" -+ depends on LEMOTE_MACH2F -+ select BACKLIGHT_LCD_SUPPORT -+ select BACKLIGHT_CLASS_DEVICE -+ select VIDEO_OUTPUT_CONTROL -+ default m -+ help -+ LynLoong PC is an AllINONE machine made by Lemote, which is basically -+ compatible to FuLoong2F Mini PC, the only difference is that it has a -+ size-fixed screen: 1360x768 with sisfb video driver. and also, it has -+ its own specific suspend support. -+ -+config GDIUM_LAPTOP -+ tristate "GDIUM laptop extras" -+ depends on DEXXON_GDIUM -+ select POWER_SUPPLY -+ select I2C -+ select INPUT_POLLDEV -+ default m -+ help -+ This mini-driver drives the ST7 chipset present in the Gdium laptops. -+ This gives battery support, wlan rfkill. -+ -+endif # MIPS_PLATFORM_DEVICES -diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile -new file mode 100644 -index 0000000..f013e78 ---- /dev/null -+++ b/drivers/platform/mips/Makefile -@@ -0,0 +1,9 @@ -+# -+# Makefile for MIPS Platform-Specific Drivers -+# -+ -+obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o # yeeloong_ecrom.o -+CFLAGS_yeeloong_laptop.o = -I$(srctree)/arch/mips/loongson/lemote-2f -+ -+obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o -+obj-$(CONFIG_GDIUM_LAPTOP) += gdium_laptop.o -diff --git a/drivers/platform/mips/gdium_laptop.c b/drivers/platform/mips/gdium_laptop.c -new file mode 100644 -index 0000000..41a65ad ---- /dev/null -+++ b/drivers/platform/mips/gdium_laptop.c -@@ -0,0 +1,927 @@ -+/* -+ * gdium_laptop -- Gdium laptop extras -+ * -+ * Arnaud Patard -+ * -+ * 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. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* For input device */ -+#define SCAN_INTERVAL 150 -+ -+/* For battery status */ -+#define BAT_SCAN_INTERVAL 500 -+ -+#define EC_FIRM_VERSION 0 -+ -+#if CONFIG_GDIUM_VERSION > 2 -+#define EC_REG_BASE 1 -+#else -+#define EC_REG_BASE 0 -+#endif -+ -+#define EC_STATUS (EC_REG_BASE+0) -+#define EC_STATUS_LID (1<<0) -+#define EC_STATUS_PWRBUT (1<<1) -+#define EC_STATUS_BATID (1<<2) /* this bit has no real meaning on v2. */ -+ /* Same as EC_STATUS_ADAPT */ -+ /* but on v3 it's BATID which mean bat present */ -+#define EC_STATUS_SYS_POWER (1<<3) -+#define EC_STATUS_WLAN (1<<4) -+#define EC_STATUS_ADAPT (1<<5) -+ -+#define EC_CTRL (EC_REG_BASE+1) -+#define EC_CTRL_DDR_CLK (1<<0) -+#define EC_CTRL_CHARGE_LED (1<<1) -+#define EC_CTRL_BEEP (1<<2) -+#define EC_CTRL_SUSB (1<<3) /* memory power */ -+#define EC_CTRL_TRICKLE (1<<4) -+#define EC_CTRL_WLAN_EN (1<<5) -+#define EC_CTRL_SUSC (1<<6) /* main power */ -+#define EC_CTRL_CHARGE_EN (1<<7) -+ -+#define EC_BAT_LOW (EC_REG_BASE+2) -+#define EC_BAT_HIGH (EC_REG_BASE+3) -+ -+#define EC_SIGN (EC_REG_BASE+4) -+#define EC_SIGN_OS 0xAE /* write 0xae to control pm stuff */ -+#define EC_SIGN_EC 0x00 /* write 0x00 to let the st7 manage pm stuff */ -+ -+#if 0 -+#define EC_TEST (EC_REG_BASE+5) /* Depending on firmware version this register */ -+ /* may be the programmation register so don't play */ -+ /* with it */ -+#endif -+ -+#define BAT_VOLT_PRESENT 500000 /* Min voltage to consider battery present uV */ -+#define BAT_MIN 7000000 /* Min battery voltage in uV */ -+#define BAT_MIN_MV 7000 /* Min battery voltage in mV */ -+#define BAT_TRICKLE_EN 8000000 /* Charging at 1.4A before 8.0V and then charging at 0.25A */ -+#define BAT_MAX 7950000 /* Max battery voltage ~8V in V */ -+#define BAT_MAX_MV 7950 /* Max battery voltage ~8V in V */ -+#define BAT_READ_ERROR 300000 /* battery read error of 0.3V */ -+#define BAT_READ_ERROR_MV 300 /* battery read error of 0.3V */ -+ -+#define SM502_WLAN_ON (224+16)/* SM502 GPIO16 may be used on gdium v2 (v3?) as wlan_on */ -+ /* when R422 is connected */ -+ -+static unsigned char verbose; -+static unsigned char gpio16; -+static unsigned char ec; -+module_param(verbose, byte, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(verbose, "Add some debugging messages"); -+module_param(gpio16, byte, S_IRUGO); -+MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502"); -+module_param(ec, byte, S_IRUGO); -+MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)"); -+ -+struct gdium_laptop_data { -+ struct i2c_client *client; -+ struct input_polled_dev *input_polldev; -+ struct dentry *debugfs; -+ struct mutex mutex; -+ struct platform_device *bat_pdev; -+ struct power_supply gdium_ac; -+ struct power_supply gdium_battery; -+ struct workqueue_struct *workqueue; -+ struct delayed_work work; -+ char charge_cmd; -+ /* important registers value */ -+ char status; -+ char ctrl; -+ /* mV */ -+ int battery_level; -+ char version; -+}; -+ -+/**********************************************************************/ -+/* Low level I2C functions */ -+/* All are supposed to be called with mutex held */ -+/**********************************************************************/ -+/* -+ * Return battery voltage in mV -+ * >= 0 battery voltage -+ * < 0 error -+ */ -+static s32 ec_read_battery(struct i2c_client *client) -+{ -+ unsigned char bat_low, bat_high; -+ s32 data; -+ unsigned int ret; -+ -+ /* -+ * a = battery high -+ * b = battery low -+ * bat = a << 2 | b & 0x03; -+ * battery voltage = (bat / 1024) * 5 * 2 -+ */ -+ data = i2c_smbus_read_byte_data(client, EC_BAT_LOW); -+ if (data < 0) { -+ dev_err(&client->dev, "ec_read_bat: read bat_low failed\n"); -+ return data; -+ } -+ bat_low = data & 0xff; -+ if (verbose) -+ dev_info(&client->dev, "bat_low %x\n", bat_low); -+ -+ data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH); -+ if (data < 0) { -+ dev_err(&client->dev, "ec_read_bat: read bat_high failed\n"); -+ return data; -+ } -+ bat_high = data & 0xff; -+ if (verbose) -+ dev_info(&client->dev, "bat_high %x\n", bat_high); -+ -+ ret = (bat_high << 2) | (bat_low & 3); -+ /* -+ * mV -+ */ -+ ret = (ret * 5 * 2) * 1000 / 1024; -+ -+ return ret; -+} -+ -+static s32 ec_read_version(struct i2c_client *client) -+{ -+#if CONFIG_GDIUM_VERSION > 2 -+ return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION); -+#else -+ return 0; -+#endif -+} -+ -+static s32 ec_read_status(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_STATUS); -+} -+ -+static s32 ec_read_ctrl(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_CTRL); -+} -+ -+static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue) -+{ -+ return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue); -+} -+ -+static s32 ec_read_sign(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_SIGN); -+} -+ -+static s32 ec_write_sign(struct i2c_client *client, unsigned char sign) -+{ -+ unsigned char value; -+ s32 ret; -+ -+ ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign); -+ if (ret < 0) { -+ dev_err(&client->dev, "ec_set_control: write failed\n"); -+ return ret; -+ } -+ -+ value = ec_read_sign(client); -+ if (value != sign) { -+ dev_err(&client->dev, "Failed to set control to %s\n", -+ sign == EC_SIGN_OS ? "OS" : "EC"); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+#if 0 -+static int ec_power_off(struct i2c_client *client) -+{ -+ char value; -+ int ret; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) { -+ dev_err(&client->dev, "ec_power_off: read failed\n"); -+ return value; -+ } -+ value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC); -+ ret = ec_write_ctrl(client, value); -+ if (ret < 0) { -+ dev_err(&client->dev, "ec_power_off: write failed\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+#endif -+ -+static s32 ec_wlan_status(struct i2c_client *client) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ return (value & EC_CTRL_WLAN_EN) ? 1 : 0; -+} -+ -+static s32 ec_wlan_en(struct i2c_client *client, int on) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ value &= ~EC_CTRL_WLAN_EN; -+ if (on) -+ value |= EC_CTRL_WLAN_EN; -+ -+ return ec_write_ctrl(client, value&0xff); -+} -+ -+#if 0 -+static s32 ec_led_status(struct i2c_client *client) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ return (value & EC_CTRL_CHARGE_LED) ? 1 : 0; -+} -+#endif -+ -+/* Changing the charging led status has never worked */ -+static s32 ec_led_en(struct i2c_client *client, int on) -+{ -+#if 0 -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ value &= ~EC_CTRL_CHARGE_LED; -+ if (on) -+ value |= EC_CTRL_CHARGE_LED; -+ return ec_write_ctrl(client, value&0xff); -+#else -+ return 0; -+#endif -+} -+ -+static s32 ec_charge_en(struct i2c_client *client, int on, int trickle) -+{ -+ s32 value; -+ s32 set = 0; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ if (on) -+ set |= EC_CTRL_CHARGE_EN; -+ if (trickle) -+ set |= EC_CTRL_TRICKLE; -+ -+ /* Be clever : don't change values if you don't need to */ -+ if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set) -+ return 0; -+ -+ value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE); -+ value |= set; -+ ec_led_en(client, on); -+ return ec_write_ctrl(client, (unsigned char)(value&0xff)); -+ -+} -+ -+/**********************************************************************/ -+/* Input functions */ -+/**********************************************************************/ -+struct gdium_keys { -+ int last_state; -+ int key_code; -+ int mask; -+ int type; -+}; -+ -+static struct gdium_keys gkeys[] = { -+ { -+ .key_code = KEY_WLAN, -+ .mask = EC_STATUS_WLAN, -+ .type = EV_KEY, -+ }, -+ { -+ .key_code = KEY_POWER, -+ .mask = EC_STATUS_PWRBUT, -+ .type = EV_KEY, /*EV_PWR,*/ -+ }, -+ { -+ .key_code = SW_LID, -+ .mask = EC_STATUS_LID, -+ .type = EV_SW, -+ }, -+}; -+ -+static void gdium_laptop_keys_poll(struct input_polled_dev *dev) -+{ -+ int state, i; -+ struct gdium_laptop_data *data = dev->private; -+ struct i2c_client *client = data->client; -+ struct input_dev *input = dev->input; -+ s32 status; -+ -+ mutex_lock(&data->mutex); -+ status = ec_read_status(client); -+ mutex_unlock(&data->mutex); -+ -+ if (status < 0) { -+ /* -+ * Don't know exactly which version of the firmware -+ * has this bug but when the power button is pressed -+ * there are i2c read errors :( -+ */ -+ if ((data->version >= 0x13) && !gkeys[1].last_state) { -+ input_event(input, EV_KEY, KEY_POWER, 1); -+ input_sync(input); -+ gkeys[1].last_state = 1; -+ } -+ return; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(gkeys); i++) { -+ state = status & gkeys[i].mask; -+ if (state != gkeys[i].last_state) { -+ gkeys[i].last_state = state; -+ /* for power key, we want power & key press/release event */ -+ if (gkeys[i].type == EV_PWR) { -+ input_event(input, EV_KEY, gkeys[i].key_code, !!state); -+ input_sync(input); -+ } -+ /* Disable wifi on key press but not key release */ -+ /* -+ * On firmware >= 0x13 the EC_STATUS_WLAN has it's -+ * original meaning of Wifi status and no more the -+ * wifi button status so we have to ignore the event -+ * on theses versions -+ */ -+ if (state && (gkeys[i].key_code == KEY_WLAN) && (data->version < 0x13)) { -+ mutex_lock(&data->mutex); -+ ec_wlan_en(client, !ec_wlan_status(client)); -+ if (gpio16) -+ gpio_set_value(SM502_WLAN_ON, !ec_wlan_status(client)); -+ mutex_unlock(&data->mutex); -+ } -+ -+ input_event(input, gkeys[i].type, gkeys[i].key_code, !!state); -+ input_sync(input); -+ } -+ } -+} -+ -+static int gdium_laptop_input_init(struct gdium_laptop_data *data) -+{ -+ struct i2c_client *client = data->client; -+ struct input_dev *input; -+ int ret, i; -+ -+ data->input_polldev = input_allocate_polled_device(); -+ if (!data->input_polldev) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ input = data->input_polldev->input; -+ input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW); -+ data->input_polldev->poll = gdium_laptop_keys_poll; -+ data->input_polldev->poll_interval = SCAN_INTERVAL; -+ data->input_polldev->private = data; -+ input->name = "gdium-keys"; -+ input->dev.parent = &client->dev; -+ -+ input->id.bustype = BUS_HOST; -+ input->id.vendor = 0x0001; -+ input->id.product = 0x0001; -+ input->id.version = 0x0100; -+ -+ for (i = 0; i < ARRAY_SIZE(gkeys); i++) -+ input_set_capability(input, gkeys[i].type, gkeys[i].key_code); -+ -+ ret = input_register_polled_device(data->input_polldev); -+ if (ret) { -+ dev_err(&client->dev, "Unable to register button device\n"); -+ goto err_poll_dev; -+ } -+ -+ return 0; -+ -+err_poll_dev: -+ input_free_polled_device(data->input_polldev); -+err: -+ return ret; -+} -+ -+static void gdium_laptop_input_exit(struct gdium_laptop_data *data) -+{ -+ input_unregister_polled_device(data->input_polldev); -+ input_free_polled_device(data->input_polldev); -+} -+ -+/**********************************************************************/ -+/* Battery management */ -+/**********************************************************************/ -+static int gdium_ac_get_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ char status; -+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_ac); -+ int ret = 0; -+ -+ if (!data) { -+ pr_err("gdium-ac: gdium_laptop_data not found\n"); -+ return -EINVAL; -+ } -+ -+ status = data->status; -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ val->intval = !!(status & EC_STATUS_ADAPT); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+#undef RET -+#define RET (val->intval) -+ -+static int gdium_battery_get_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ char status, ctrl; -+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_battery); -+ int percentage_capacity = 0, charge_now = 0, time_to_empty = 0; -+ int ret = 0, tmp; -+ -+ if (!data) { -+ pr_err("gdium-battery: gdium_laptop_data not found\n"); -+ return -EINVAL; -+ } -+ -+ status = data->status; -+ ctrl = data->ctrl; -+ switch (psp) { -+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: -+ /* uAh */ -+ RET = 5000000; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: -+ /* This formula is gotten by gnuplot with the statistic data */ -+ time_to_empty = (data->battery_level - BAT_MIN_MV + BAT_READ_ERROR_MV) * 113 - 29870; -+ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) { -+ /* seconds */ -+ RET = time_to_empty / 10; -+ break; -+ } -+ /* fall through */ -+ case POWER_SUPPLY_PROP_CHARGE_NOW: -+ case POWER_SUPPLY_PROP_CAPACITY: { -+ tmp = data->battery_level * 1000; -+ /* > BAT_MIN to avoid negative values */ -+ percentage_capacity = 0; -+ if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN)) -+ percentage_capacity = (tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN); -+ -+ if (percentage_capacity > 100) -+ percentage_capacity = 100; -+ -+ if (psp == POWER_SUPPLY_PROP_CAPACITY) { -+ RET = percentage_capacity; -+ break; -+ } -+ charge_now = 50000 * percentage_capacity; -+ if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) { -+ /* uAh */ -+ RET = charge_now; -+ break; -+ } -+ } /* fall through */ -+ case POWER_SUPPLY_PROP_STATUS: { -+ if (status & EC_STATUS_ADAPT) -+ if (ctrl & EC_CTRL_CHARGE_EN) -+ RET = POWER_SUPPLY_STATUS_CHARGING; -+ else -+ RET = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ else -+ RET = POWER_SUPPLY_STATUS_DISCHARGING; -+ -+ if (psp == POWER_SUPPLY_PROP_STATUS) -+ break; -+ /* mAh -> µA */ -+ switch (RET) { -+ case POWER_SUPPLY_STATUS_CHARGING: -+ RET = -(data->charge_cmd == 2) ? 1400000 : 250000; -+ break; -+ case POWER_SUPPLY_STATUS_DISCHARGING: -+ RET = charge_now / time_to_empty * 36000; -+ break; -+ case POWER_SUPPLY_STATUS_NOT_CHARGING: -+ default: -+ RET = 0; -+ break; -+ } -+ } break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ RET = BAT_MAX+BAT_READ_ERROR; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: -+ RET = BAT_MIN-BAT_READ_ERROR; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ /* mV -> uV */ -+ RET = data->battery_level * 1000; -+ break; -+ case POWER_SUPPLY_PROP_PRESENT: -+#if CONFIG_GDIUM_VERSION > 2 -+ RET = !!(status & EC_STATUS_BATID); -+#else -+ RET = !!(data->battery_level > BAT_VOLT_PRESENT); -+#endif -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: -+ tmp = data->battery_level * 1000; -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ if (status & EC_STATUS_BATID) { -+ if (tmp >= BAT_MAX) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; -+ if (tmp >= BAT_MAX+BAT_READ_ERROR) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; -+ } else if (tmp <= BAT_MIN+BAT_READ_ERROR) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; -+ if (tmp <= BAT_MIN) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; -+ } else -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; -+ } -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_TYPE: -+ if (ctrl & EC_CTRL_TRICKLE) -+ RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; -+ else if (ctrl & EC_CTRL_CHARGE_EN) -+ RET = POWER_SUPPLY_CHARGE_TYPE_FAST; -+ else -+ RET = POWER_SUPPLY_CHARGE_TYPE_NONE; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_MAX: -+ /* 1.4A ? */ -+ RET = 1400000; -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+#undef RET -+ -+static enum power_supply_property gdium_ac_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static enum power_supply_property gdium_battery_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_MAX, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_CAPACITY_LEVEL, -+ POWER_SUPPLY_PROP_CHARGE_TYPE, -+}; -+ -+static void gdium_laptop_battery_work(struct work_struct *work) -+{ -+ struct gdium_laptop_data *data = container_of(work, struct gdium_laptop_data, work.work); -+ struct i2c_client *client; -+ int ret; -+ char old_status, old_charge_cmd; -+ char present; -+ s32 status; -+ -+ mutex_lock(&data->mutex); -+ client = data->client; -+ status = ec_read_status(client); -+ ret = ec_read_battery(client); -+ -+ if ((status < 0) || (ret < 0)) -+ goto i2c_read_error; -+ -+ old_status = data->status; -+ old_charge_cmd = data->charge_cmd; -+ data->status = status; -+ -+ /* -+ * Charge only if : -+ * - battery present -+ * - ac adapter plugged in -+ * - battery not fully charged -+ */ -+#if CONFIG_GDIUM_VERSION > 2 -+ present = !!(data->status & EC_STATUS_BATID); -+#else -+ present = !!(ret > BAT_VOLT_PRESENT); -+#endif -+ data->battery_level = 0; -+ if (present) { -+ data->battery_level = (unsigned int)ret; -+ if (data->status & EC_STATUS_ADAPT) -+ data->battery_level -= BAT_READ_ERROR_MV; -+ } -+ -+ data->charge_cmd = 0; -+ if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level <= BAT_MAX_MV)) -+ data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3; -+ -+ ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1); -+ -+ /* -+ * data->ctrl must be set _after_ calling ec_charge_en as this will change the -+ * control register content -+ */ -+ data->ctrl = ec_read_ctrl(client); -+ -+ if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) { -+ power_supply_changed(&data->gdium_ac); -+ /* Send charging/discharging state change */ -+ power_supply_changed(&data->gdium_battery); -+ } else if ((data->status & EC_STATUS_ADAPT) && -+ ((old_charge_cmd&2) != (data->charge_cmd&2))) -+ power_supply_changed(&data->gdium_battery); -+ -+i2c_read_error: -+ mutex_unlock(&data->mutex); -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+} -+ -+static int gdium_laptop_battery_init(struct gdium_laptop_data *data) -+{ -+ int ret; -+ -+ data->bat_pdev = platform_device_register_simple("gdium-battery", 0, NULL, 0); -+ if (IS_ERR(data->bat_pdev)) -+ return PTR_ERR(data->bat_pdev); -+ -+ data->gdium_battery.name = data->bat_pdev->name; -+ data->gdium_battery.properties = gdium_battery_props; -+ data->gdium_battery.num_properties = ARRAY_SIZE(gdium_battery_props); -+ data->gdium_battery.get_property = gdium_battery_get_props; -+ data->gdium_battery.use_for_apm = 1; -+ -+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery); -+ if (ret) -+ goto err_platform; -+ -+ data->gdium_ac.name = "gdium-ac"; -+ data->gdium_ac.type = POWER_SUPPLY_TYPE_MAINS; -+ data->gdium_ac.properties = gdium_ac_props; -+ data->gdium_ac.num_properties = ARRAY_SIZE(gdium_ac_props); -+ data->gdium_ac.get_property = gdium_ac_get_props; -+/* data->gdium_ac.use_for_apm_ac = 1, */ -+ -+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac); -+ if (ret) -+ goto err_battery; -+ -+ if (!ec) { -+ INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work); -+ data->workqueue = create_singlethread_workqueue("gdium-battery-work"); -+ if (!data->workqueue) { -+ ret = -ESRCH; -+ goto err_work; -+ } -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+ } -+ -+ return 0; -+ -+err_work: -+err_battery: -+ power_supply_unregister(&data->gdium_battery); -+err_platform: -+ platform_device_unregister(data->bat_pdev); -+ -+ return ret; -+} -+static void gdium_laptop_battery_exit(struct gdium_laptop_data *data) -+{ -+ if (!ec) { -+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); -+ destroy_workqueue(data->workqueue); -+ } -+ power_supply_unregister(&data->gdium_battery); -+ power_supply_unregister(&data->gdium_ac); -+ platform_device_unregister(data->bat_pdev); -+} -+ -+/* Debug fs */ -+static int gdium_laptop_regs_show(struct seq_file *s, void *p) -+{ -+ struct gdium_laptop_data *data = s->private; -+ struct i2c_client *client = data->client; -+ -+ mutex_lock(&data->mutex); -+ seq_printf(s, "Version : 0x%02x\n", (unsigned char)ec_read_version(client)); -+ seq_printf(s, "Status : 0x%02x\n", (unsigned char)ec_read_status(client)); -+ seq_printf(s, "Ctrl : 0x%02x\n", (unsigned char)ec_read_ctrl(client)); -+ seq_printf(s, "Sign : 0x%02x\n", (unsigned char)ec_read_sign(client)); -+ seq_printf(s, "Bat Lo : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_LOW)); -+ seq_printf(s, "Bat Hi : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH)); -+ seq_printf(s, "Battery : %d uV\n", (unsigned int)ec_read_battery(client) * 1000); -+ seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", data->charge_cmd & 1 ? "T" : " "); -+ -+ mutex_unlock(&data->mutex); -+ return 0; -+} -+ -+static int gdium_laptop_regs_open(struct inode *inode, -+ struct file *file) -+{ -+ return single_open(file, gdium_laptop_regs_show, inode->i_private); -+} -+ -+static const struct file_operations gdium_laptop_regs_fops = { -+ .open = gdium_laptop_regs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+ -+ -+static int gdium_laptop_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct gdium_laptop_data *data; -+ int ret; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -+ dev_err(&client->dev, -+ "%s: no smbus_byte support !\n", __func__); -+ return -ENODEV; -+ } -+ -+ data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(client, data); -+ data->client = client; -+ mutex_init(&data->mutex); -+ -+ ret = ec_read_version(client); -+ if (ret < 0) -+ goto err_alloc; -+ -+ data->version = (unsigned char)ret; -+ -+ ret = gdium_laptop_input_init(data); -+ if (ret) -+ goto err_alloc; -+ -+ ret = gdium_laptop_battery_init(data); -+ if (ret) -+ goto err_input; -+ -+ -+ if (!ec) { -+ ret = ec_write_sign(client, EC_SIGN_OS); -+ if (ret) -+ goto err_sign; -+ } -+ -+ if (gpio16) { -+ ret = gpio_request(SM502_WLAN_ON, "wlan-on"); -+ if (ret < 0) -+ goto err_sign; -+ gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client)); -+ gpio_direction_output(SM502_WLAN_ON, 1); -+ } -+ -+ dev_info(&client->dev, "Found firmware 0x%02x\n", data->version); -+ data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO, -+ NULL, data, &gdium_laptop_regs_fops); -+ -+ return 0; -+ -+err_sign: -+ gdium_laptop_battery_exit(data); -+err_input: -+ gdium_laptop_input_exit(data); -+err_alloc: -+ kfree(data); -+ return ret; -+} -+ -+static int gdium_laptop_remove(struct i2c_client *client) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (gpio16) -+ gpio_free(SM502_WLAN_ON); -+ ec_write_sign(client, EC_SIGN_EC); -+ if (data->debugfs) -+ debugfs_remove(data->debugfs); -+ -+ gdium_laptop_battery_exit(data); -+ gdium_laptop_input_exit(data); -+ -+ kfree(data); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (!ec) -+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); -+ return 0; -+} -+ -+static int gdium_laptop_resume(struct i2c_client *client) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (!ec) -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+ return 0; -+} -+#else -+#define gdium_laptop_suspend NULL -+#define gdium_laptop_resume NULL -+#endif -+static const struct i2c_device_id gdium_id[] = { -+ { "gdium-laptop" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(i2c, gdium_id); -+ -+static struct i2c_driver gdium_laptop_driver = { -+ .driver = { -+ .name = "gdium-laptop", -+ .owner = THIS_MODULE, -+ }, -+ .probe = gdium_laptop_probe, -+ .remove = gdium_laptop_remove, -+ .shutdown = gdium_laptop_remove, -+ .suspend = gdium_laptop_suspend, -+ .resume = gdium_laptop_resume, -+ .id_table = gdium_id, -+}; -+ -+static int __init gdium_laptop_init(void) -+{ -+ return i2c_add_driver(&gdium_laptop_driver); -+} -+ -+static void __exit gdium_laptop_exit(void) -+{ -+ i2c_del_driver(&gdium_laptop_driver); -+} -+ -+module_init(gdium_laptop_init); -+module_exit(gdium_laptop_exit); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("Gdium laptop extras"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/lynloong_pc.c b/drivers/platform/mips/lynloong_pc.c -new file mode 100644 -index 0000000..68f29e4 ---- /dev/null -+++ b/drivers/platform/mips/lynloong_pc.c -@@ -0,0 +1,515 @@ -+/* -+ * Driver for LynLoong PC extras -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin , Xiang Yu -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include /* for backlight subdriver */ -+#include -+#include /* for video output subdriver */ -+#include /* for suspend support */ -+ -+#include -+#include -+ -+#include -+ -+static u32 gpio_base, mfgpt_base; -+ -+static void set_gpio_reg_high(int gpio, int reg) -+{ -+ u32 val; -+ -+ val = inl(gpio_base + reg); -+ val |= (1 << gpio); -+ val &= ~(1 << (16 + gpio)); -+ outl(val, gpio_base + reg); -+ mmiowb(); -+} -+ -+static void set_gpio_reg_low(int gpio, int reg) -+{ -+ u32 val; -+ -+ val = inl(gpio_base + reg); -+ val |= (1 << (16 + gpio)); -+ val &= ~(1 << gpio); -+ outl(val, gpio_base + reg); -+ mmiowb(); -+} -+ -+static void set_gpio_output_low(int gpio) -+{ -+ set_gpio_reg_high(gpio, GPIOL_OUT_EN); -+ set_gpio_reg_low(gpio, GPIOL_OUT_VAL); -+} -+ -+static void set_gpio_output_high(int gpio) -+{ -+ set_gpio_reg_high(gpio, GPIOL_OUT_EN); -+ set_gpio_reg_high(gpio, GPIOL_OUT_VAL); -+} -+ -+/* backlight subdriver */ -+ -+#define MAX_BRIGHTNESS 100 -+#define DEFAULT_BRIGHTNESS 50 -+#define MIN_BRIGHTNESS 0 -+static unsigned int level; -+ -+DEFINE_SPINLOCK(backlight_lock); -+/* Tune the brightness */ -+static void setup_mfgpt2(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&backlight_lock, flags); -+ -+ /* Set MFGPT2 comparator 1,2 */ -+ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1); -+ outw(MAX_BRIGHTNESS, MFGPT2_CMP2); -+ /* Clear MFGPT2 UP COUNTER */ -+ outw(0, MFGPT2_CNT); -+ /* Enable counter, compare mode, 32k */ -+ outw(0x8280, MFGPT2_SETUP); -+ -+ spin_unlock_irqrestore(&backlight_lock, flags); -+} -+ -+static int lynloong_set_brightness(struct backlight_device *bd) -+{ -+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && -+ bd->props.power == FB_BLANK_UNBLANK) ? -+ bd->props.brightness : 0; -+ -+ if (level > MAX_BRIGHTNESS) -+ level = MAX_BRIGHTNESS; -+ else if (level < MIN_BRIGHTNESS) -+ level = MIN_BRIGHTNESS; -+ -+ setup_mfgpt2(); -+ -+ return 0; -+} -+ -+static int lynloong_get_brightness(struct backlight_device *bd) -+{ -+ return level; -+} -+ -+static struct backlight_ops backlight_ops = { -+ .get_brightness = lynloong_get_brightness, -+ .update_status = lynloong_set_brightness, -+}; -+ -+static struct backlight_device *lynloong_backlight_dev; -+ -+static int lynloong_backlight_init(void) -+{ -+ int ret; -+ u32 hi; -+ struct backlight_properties props; -+ -+ /* Get gpio_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); -+ /* Get mfgpt_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base); -+ /* Get gpio_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); -+ -+ /* Select for mfgpt */ -+ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL); -+ /* Enable brightness controlling */ -+ set_gpio_output_high(7); -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.max_brightness = MAX_BRIGHTNESS; -+ props.type = BACKLIGHT_PLATFORM; -+ lynloong_backlight_dev = backlight_device_register("backlight0", NULL, -+ NULL, &backlight_ops, &props); -+ -+ if (IS_ERR(lynloong_backlight_dev)) { -+ ret = PTR_ERR(lynloong_backlight_dev); -+ return ret; -+ } -+ -+ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS; -+ backlight_update_status(lynloong_backlight_dev); -+ -+ return 0; -+} -+ -+static void lynloong_backlight_exit(void) -+{ -+ if (lynloong_backlight_dev) { -+ backlight_device_unregister(lynloong_backlight_dev); -+ lynloong_backlight_dev = NULL; -+ } -+ /* Disable brightness controlling */ -+ set_gpio_output_low(7); -+} -+ -+/* video output driver */ -+static int vo_status = 1; -+ -+static int lcd_video_output_get(struct output_device *od) -+{ -+ return vo_status; -+} -+ -+static int lcd_video_output_set(struct output_device *od) -+{ -+ int i; -+ unsigned long status; -+ -+ status = !!od->request_state; -+ -+ if (status == 0) { -+ /* Set the current status as off */ -+ vo_status = 0; -+ /* Turn off the backlight */ -+ set_gpio_output_low(11); -+ for (i = 0; i < 0x500; i++) -+ delay(); -+ /* Turn off the LCD */ -+ set_gpio_output_high(8); -+ } else { -+ /* Turn on the LCD */ -+ set_gpio_output_low(8); -+ for (i = 0; i < 0x500; i++) -+ delay(); -+ /* Turn on the backlight */ -+ set_gpio_output_high(11); -+ /* Set the current status as on */ -+ vo_status = 1; -+ } -+ -+ return 0; -+} -+ -+static struct output_properties lcd_output_properties = { -+ .set_state = lcd_video_output_set, -+ .get_status = lcd_video_output_get, -+}; -+ -+static struct output_device *lcd_output_dev; -+ -+static void lynloong_lcd_vo_set(int status) -+{ -+ lcd_output_dev->request_state = status; -+ lcd_video_output_set(lcd_output_dev); -+} -+ -+static int lynloong_vo_init(void) -+{ -+ int ret; -+ -+ /* Register video output device: lcd */ -+ lcd_output_dev = video_output_register("LCD", NULL, NULL, -+ &lcd_output_properties); -+ -+ if (IS_ERR(lcd_output_dev)) { -+ ret = PTR_ERR(lcd_output_dev); -+ lcd_output_dev = NULL; -+ return ret; -+ } -+ /* Ensure LCD is on by default */ -+ lynloong_lcd_vo_set(1); -+ -+ return 0; -+} -+ -+static void lynloong_vo_exit(void) -+{ -+ if (lcd_output_dev) { -+ video_output_unregister(lcd_output_dev); -+ lcd_output_dev = NULL; -+ } -+} -+ -+/* suspend support */ -+ -+#ifdef CONFIG_PM -+ -+static u32 smb_base; -+ -+/* I2C operations */ -+ -+static int i2c_wait(void) -+{ -+ char c; -+ int i; -+ -+ udelay(1000); -+ for (i = 0; i < 20; i++) { -+ c = inb(smb_base | SMB_STS); -+ if (c & (SMB_STS_BER | SMB_STS_NEGACK)) -+ return -1; -+ if (c & SMB_STS_SDAST) -+ return 0; -+ udelay(100); -+ } -+ return -2; -+} -+ -+static void i2c_read_single(int addr, int regNo, char *value) -+{ -+ unsigned char c; -+ -+ /* Start condition */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ -+ /* Send slave address */ -+ outb(addr & 0xfe, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Send register index */ -+ outb(regNo, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Start condition again */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ -+ /* Send salve address again */ -+ outb(1 | addr, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Read data */ -+ *value = inb(smb_base | SMB_SDA); -+ -+ /* Stop condition */ -+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); -+ i2c_wait(); -+} -+ -+static void i2c_write_single(int addr, int regNo, char value) -+{ -+ unsigned char c; -+ -+ /* Start condition */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ /* Send slave address */ -+ outb(addr & 0xfe, smb_base | SMB_SDA); -+ i2c_wait();; -+ -+ /* Send register index */ -+ outb(regNo, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Write data */ -+ outb(value, smb_base | SMB_SDA); -+ i2c_wait(); -+ /* Stop condition */ -+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); -+ i2c_wait(); -+} -+ -+static void stop_clock(int clk_reg, int clk_sel) -+{ -+ u8 value; -+ -+ i2c_read_single(0xd3, clk_reg, &value); -+ value &= ~(1 << clk_sel); -+ i2c_write_single(0xd2, clk_reg, value); -+} -+ -+static void enable_clock(int clk_reg, int clk_sel) -+{ -+ u8 value; -+ -+ i2c_read_single(0xd3, clk_reg, &value); -+ value |= (1 << clk_sel); -+ i2c_write_single(0xd2, clk_reg, value); -+} -+ -+static char cached_clk_freq; -+static char cached_pci_fixed_freq; -+ -+static void decrease_clk_freq(void) -+{ -+ char value; -+ -+ i2c_read_single(0xd3, 1, &value); -+ cached_clk_freq = value; -+ -+ /* Select frequency by software */ -+ value |= (1 << 1); -+ /* CPU, 3V66, PCI : 100, 66, 33(1) */ -+ value |= (1 << 2); -+ i2c_write_single(0xd2, 1, value); -+ -+ /* Cache the pci frequency */ -+ i2c_read_single(0xd3, 14, &value); -+ cached_pci_fixed_freq = value; -+ -+ /* Enable PCI fix mode */ -+ value |= (1 << 5); -+ /* 3V66, PCI : 64MHz, 32MHz */ -+ value |= (1 << 3); -+ i2c_write_single(0xd2, 14, value); -+ -+} -+ -+static void resume_clk_freq(void) -+{ -+ i2c_write_single(0xd2, 1, cached_clk_freq); -+ i2c_write_single(0xd2, 14, cached_pci_fixed_freq); -+} -+ -+static void stop_clocks(void) -+{ -+ /* CPU Clock Register */ -+ stop_clock(2, 5); /* not used */ -+ stop_clock(2, 6); /* not used */ -+ stop_clock(2, 7); /* not used */ -+ -+ /* PCI Clock Register */ -+ stop_clock(3, 1); /* 8100 */ -+ stop_clock(3, 5); /* SIS */ -+ stop_clock(3, 0); /* not used */ -+ stop_clock(3, 6); /* not used */ -+ -+ /* PCI 48M Clock Register */ -+ stop_clock(4, 6); /* USB grounding */ -+ stop_clock(4, 5); /* REF(5536_14M) */ -+ -+ /* 3V66 Control Register */ -+ stop_clock(5, 0); /* VCH_CLK..., grounding */ -+} -+ -+static void enable_clocks(void) -+{ -+ enable_clock(3, 1); /* 8100 */ -+ enable_clock(3, 5); /* SIS */ -+ -+ enable_clock(4, 6); -+ enable_clock(4, 5); /* REF(5536_14M) */ -+ -+ enable_clock(5, 0); /* VCH_CLOCK, grounding */ -+} -+ -+static int lynloong_suspend(struct device *dev) -+{ -+ /* Disable AMP */ -+ set_gpio_output_high(6); -+ /* Turn off LCD */ -+ lynloong_lcd_vo_set(0); -+ -+ /* Stop the clocks of some devices */ -+ stop_clocks(); -+ -+ /* Decrease the external clock frequency */ -+ decrease_clk_freq(); -+ -+ return 0; -+} -+ -+static int lynloong_resume(struct device *dev) -+{ -+ /* Turn on the LCD */ -+ lynloong_lcd_vo_set(1); -+ -+ /* Resume clock frequency, enable the relative clocks */ -+ resume_clk_freq(); -+ enable_clocks(); -+ -+ /* Enable AMP */ -+ set_gpio_output_low(6); -+ -+ return 0; -+} -+ -+static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend, -+ lynloong_resume); -+#endif /* !CONFIG_PM */ -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "lynloong_pc", -+ }, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver platform_driver = { -+ .driver = { -+ .name = "lynloong_pc", -+ .owner = THIS_MODULE, -+#ifdef CONFIG_PM -+ .pm = &lynloong_pm_ops, -+#endif -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int __init lynloong_init(void) -+{ -+ int ret; -+ -+ pr_info("LynLoong platform specific driver loaded.\n"); -+ -+ /* Register platform stuff */ -+ ret = platform_driver_register(&platform_driver); -+ if (ret) { -+ pr_err("Failed to register LynLoong platform driver.\n"); -+ return ret; -+ } -+ -+ ret = lynloong_backlight_init(); -+ if (ret) { -+ pr_err("Failed to register LynLoong backlight driver.\n"); -+ return ret; -+ } -+ -+ ret = lynloong_vo_init(); -+ if (ret) { -+ pr_err("Failed to register LynLoong backlight driver.\n"); -+ lynloong_vo_exit(); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void __exit lynloong_exit(void) -+{ -+ lynloong_vo_exit(); -+ lynloong_backlight_exit(); -+ platform_driver_unregister(&platform_driver); -+ -+ pr_info("LynLoong platform specific driver unloaded.\n"); -+} -+ -+module_init(lynloong_init); -+module_exit(lynloong_exit); -+ -+MODULE_AUTHOR("Wu Zhangjin ; Xiang Yu "); -+MODULE_DESCRIPTION("LynLoong PC driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/yeeloong_ecrom.c b/drivers/platform/mips/yeeloong_ecrom.c -new file mode 100644 -index 0000000..1bfe4cf ---- /dev/null -+++ b/drivers/platform/mips/yeeloong_ecrom.c -@@ -0,0 +1,944 @@ -+/* -+ * Driver for flushing/dumping ROM of EC on YeeLoong laptop -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: liujl -+ * -+ * NOTE : -+ * The EC resources accessing and programming are supported. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define EC_MISC_DEV "ec_misc" -+#define EC_IOC_MAGIC 'E' -+ -+/* ec registers range */ -+#define EC_MAX_REGADDR 0xFFFF -+#define EC_MIN_REGADDR 0xF000 -+#define EC_RAM_ADDR 0xF800 -+ -+/* version burned address */ -+#define VER_ADDR 0xf7a1 -+#define VER_MAX_SIZE 7 -+#define EC_ROM_MAX_SIZE 0x10000 -+ -+/* ec internal register */ -+#define REG_POWER_MODE 0xF710 -+#define FLAG_NORMAL_MODE 0x00 -+#define FLAG_IDLE_MODE 0x01 -+#define FLAG_RESET_MODE 0x02 -+ -+/* ec update program flag */ -+#define PROGRAM_FLAG_NONE 0x00 -+#define PROGRAM_FLAG_IE 0x01 -+#define PROGRAM_FLAG_ROM 0x02 -+ -+/* XBI relative registers */ -+#define REG_XBISEG0 0xFEA0 -+#define REG_XBISEG1 0xFEA1 -+#define REG_XBIRSV2 0xFEA2 -+#define REG_XBIRSV3 0xFEA3 -+#define REG_XBIRSV4 0xFEA4 -+#define REG_XBICFG 0xFEA5 -+#define REG_XBICS 0xFEA6 -+#define REG_XBIWE 0xFEA7 -+#define REG_XBISPIA0 0xFEA8 -+#define REG_XBISPIA1 0xFEA9 -+#define REG_XBISPIA2 0xFEAA -+#define REG_XBISPIDAT 0xFEAB -+#define REG_XBISPICMD 0xFEAC -+#define REG_XBISPICFG 0xFEAD -+#define REG_XBISPIDATR 0xFEAE -+#define REG_XBISPICFG2 0xFEAF -+ -+/* commands definition for REG_XBISPICMD */ -+#define SPICMD_WRITE_STATUS 0x01 -+#define SPICMD_BYTE_PROGRAM 0x02 -+#define SPICMD_READ_BYTE 0x03 -+#define SPICMD_WRITE_DISABLE 0x04 -+#define SPICMD_READ_STATUS 0x05 -+#define SPICMD_WRITE_ENABLE 0x06 -+#define SPICMD_HIGH_SPEED_READ 0x0B -+#define SPICMD_POWER_DOWN 0xB9 -+#define SPICMD_SST_EWSR 0x50 -+#define SPICMD_SST_SEC_ERASE 0x20 -+#define SPICMD_SST_BLK_ERASE 0x52 -+#define SPICMD_SST_CHIP_ERASE 0x60 -+#define SPICMD_FRDO 0x3B -+#define SPICMD_SEC_ERASE 0xD7 -+#define SPICMD_BLK_ERASE 0xD8 -+#define SPICMD_CHIP_ERASE 0xC7 -+ -+/* bits definition for REG_XBISPICFG */ -+#define SPICFG_AUTO_CHECK 0x01 -+#define SPICFG_SPI_BUSY 0x02 -+#define SPICFG_DUMMY_READ 0x04 -+#define SPICFG_EN_SPICMD 0x08 -+#define SPICFG_LOW_SPICS 0x10 -+#define SPICFG_EN_SHORT_READ 0x20 -+#define SPICFG_EN_OFFSET_READ 0x40 -+#define SPICFG_EN_FAST_READ 0x80 -+ -+/* watchdog timer registers */ -+#define REG_WDTCFG 0xfe80 -+#define REG_WDTPF 0xfe81 -+#define REG_WDT 0xfe82 -+ -+/* lpc configure register */ -+#define REG_LPCCFG 0xfe95 -+ -+/* 8051 reg */ -+#define REG_PXCFG 0xff14 -+ -+/* Fan register in KB3310 */ -+#define REG_ECFAN_SPEED_LEVEL 0xf4e4 -+#define REG_ECFAN_SWITCH 0xf4d2 -+ -+/* the ec flash rom id number */ -+#define EC_ROM_PRODUCT_ID_SPANSION 0x01 -+#define EC_ROM_PRODUCT_ID_MXIC 0xC2 -+#define EC_ROM_PRODUCT_ID_AMIC 0x37 -+#define EC_ROM_PRODUCT_ID_EONIC 0x1C -+ -+/* misc ioctl operations */ -+#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int) -+#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int) -+#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int) -+#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int) -+#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int) -+ -+/* start address for programming of EC content or IE */ -+/* ec running code start address */ -+#define EC_START_ADDR 0x00000000 -+/* ec information element storing address */ -+#define IE_START_ADDR 0x00020000 -+ -+/* EC state */ -+#define EC_STATE_IDLE 0x00 /* ec in idle state */ -+#define EC_STATE_BUSY 0x01 /* ec in busy state */ -+ -+/* timeout value for programming */ -+#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */ -+/* command checkout timeout including cmd to port or state flag check */ -+#define EC_CMD_TIMEOUT 0x1000 -+#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */ -+#define EC_MAX_DELAY_UNIT (10) /* every time for polling */ -+#define SPI_FINISH_WAIT_TIME 10 -+/* EC content max size */ -+#define EC_CONTENT_MAX_SIZE (64 * 1024) -+#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR) -+ -+/* the register operation access struct */ -+struct ec_reg { -+ u32 addr; /* the address of kb3310 registers */ -+ u8 val; /* the register value */ -+}; -+ -+struct ec_info { -+ u32 start_addr; -+ u32 size; -+ u8 *buf; -+}; -+ -+/* open for using rom protection action */ -+#define EC_ROM_PROTECTION -+ -+/* enable the chip reset mode */ -+static int ec_init_reset_mode(void) -+{ -+ int timeout; -+ unsigned char status = 0; -+ int ret = 0; -+ -+ /* make chip goto reset mode */ -+ ret = ec_query_seq(CMD_INIT_RESET_MODE); -+ if (ret < 0) { -+ printk(KERN_ERR "ec init reset mode failed.\n"); -+ goto out; -+ } -+ -+ /* make the action take active */ -+ timeout = EC_CMD_TIMEOUT; -+ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; -+ while (timeout--) { -+ if (status) { -+ udelay(EC_REG_DELAY); -+ break; -+ } -+ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; -+ udelay(EC_REG_DELAY); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR "ec rom fixup : can't check reset status.\n"); -+ ret = -EINVAL; -+ } else -+ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout, -+ EC_CMD_TIMEOUT - timeout, status); -+ -+ /* set MCU to reset mode */ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_PXCFG); -+ status |= (1 << 0); -+ ec_write(REG_PXCFG, status); -+ udelay(EC_REG_DELAY); -+ -+ /* disable FWH/LPC */ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_LPCCFG); -+ status &= ~(1 << 7); -+ ec_write(REG_LPCCFG, status); -+ udelay(EC_REG_DELAY); -+ -+ printk(KERN_INFO "entering reset mode ok..............\n"); -+ -+ out: -+ return ret; -+} -+ -+/* make ec exit from reset mode */ -+static void ec_exit_reset_mode(void) -+{ -+ unsigned char regval; -+ -+ udelay(EC_REG_DELAY); -+ regval = ec_read(REG_LPCCFG); -+ regval |= (1 << 7); -+ ec_write(REG_LPCCFG, regval); -+ regval = ec_read(REG_PXCFG); -+ regval &= ~(1 << 0); -+ ec_write(REG_PXCFG, regval); -+ printk(KERN_INFO "exit reset mode ok..................\n"); -+ -+ return; -+} -+ -+/* make ec disable WDD */ -+static void ec_disable_WDD(void) -+{ -+ unsigned char status; -+ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_WDTCFG); -+ ec_write(REG_WDTPF, 0x03); -+ ec_write(REG_WDTCFG, (status & 0x80) | 0x48); -+ printk(KERN_INFO "Disable WDD ok..................\n"); -+ -+ return; -+} -+ -+/* make ec enable WDD */ -+static void ec_enable_WDD(void) -+{ -+ unsigned char status; -+ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_WDTCFG); -+ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */ -+ ec_write(REG_WDTCFG, (status & 0x80) | 0x03); -+ printk(KERN_INFO "Enable WDD ok..................\n"); -+ -+ return; -+} -+ -+/* make ec goto idle mode */ -+static int ec_init_idle_mode(void) -+{ -+ int timeout; -+ unsigned char status = 0; -+ int ret = 0; -+ -+ ec_query_seq(CMD_INIT_IDLE_MODE); -+ -+ /* make the action take active */ -+ timeout = EC_CMD_TIMEOUT; -+ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; -+ while (timeout--) { -+ if (status) { -+ udelay(EC_REG_DELAY); -+ break; -+ } -+ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; -+ udelay(EC_REG_DELAY); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR "ec rom fixup : can't check out the status.\n"); -+ ret = -EINVAL; -+ } else -+ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout, -+ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE)); -+ -+ printk(KERN_INFO "entering idle mode ok...................\n"); -+ -+ return ret; -+} -+ -+/* make ec exit from idle mode */ -+static int ec_exit_idle_mode(void) -+{ -+ -+ ec_query_seq(CMD_EXIT_IDLE_MODE); -+ -+ printk(KERN_INFO "exit idle mode ok...................\n"); -+ -+ return 0; -+} -+ -+static int ec_instruction_cycle(void) -+{ -+ unsigned long timeout; -+ int ret = 0; -+ -+ timeout = EC_FLASH_TIMEOUT; -+ while (timeout-- >= 0) { -+ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY)) -+ break; -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ return ret; -+} -+ -+/* To see if the ec is in busy state or not. */ -+static inline int ec_flash_busy(unsigned long timeout) -+{ -+ /* assurance the first command be going to rom */ -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+#if 1 -+ timeout = timeout / EC_MAX_DELAY_UNIT; -+ while (timeout-- > 0) { -+ /* check the rom's status of busy flag */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) -+ return EC_STATE_IDLE; -+ udelay(EC_MAX_DELAY_UNIT); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_FLASH_BUSY : timeout for check rom flag.\n"); -+ return EC_STATE_BUSY; -+ } -+#else -+ /* check the rom's status of busy flag */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+ -+ timeout = timeout / EC_MAX_DELAY_UNIT; -+ while (timeout-- > 0) { -+ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) -+ return EC_STATE_IDLE; -+ udelay(EC_MAX_DELAY_UNIT); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_FLASH_BUSY : timeout for check rom flag.\n"); -+ return EC_STATE_BUSY; -+ } -+#endif -+ -+ return EC_STATE_IDLE; -+} -+ -+static int rom_instruction_cycle(unsigned char cmd) -+{ -+ unsigned long timeout = 0; -+ -+ switch (cmd) { -+ case SPICMD_READ_STATUS: -+ case SPICMD_WRITE_ENABLE: -+ case SPICMD_WRITE_DISABLE: -+ case SPICMD_READ_BYTE: -+ case SPICMD_HIGH_SPEED_READ: -+ timeout = 0; -+ break; -+ case SPICMD_WRITE_STATUS: -+ timeout = 300 * 1000; -+ break; -+ case SPICMD_BYTE_PROGRAM: -+ timeout = 5 * 1000; -+ break; -+ case SPICMD_SST_SEC_ERASE: -+ case SPICMD_SEC_ERASE: -+ timeout = 1000 * 1000; -+ break; -+ case SPICMD_SST_BLK_ERASE: -+ case SPICMD_BLK_ERASE: -+ timeout = 3 * 1000 * 1000; -+ break; -+ case SPICMD_SST_CHIP_ERASE: -+ case SPICMD_CHIP_ERASE: -+ timeout = 20 * 1000 * 1000; -+ break; -+ default: -+ timeout = EC_SPICMD_STANDARD_TIMEOUT; -+ } -+ if (timeout == 0) -+ return ec_instruction_cycle(); -+ if (timeout < EC_SPICMD_STANDARD_TIMEOUT) -+ timeout = EC_SPICMD_STANDARD_TIMEOUT; -+ -+ return ec_flash_busy(timeout); -+} -+ -+/* delay for start/stop action */ -+static void delay_spi(int n) -+{ -+ while (n--) -+ inb(EC_IO_PORT_HIGH); -+} -+ -+/* start the action to spi rom function */ -+static void ec_start_spi(void) -+{ -+ unsigned char val; -+ -+ delay_spi(SPI_FINISH_WAIT_TIME); -+ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK; -+ ec_write(REG_XBISPICFG, val); -+ delay_spi(SPI_FINISH_WAIT_TIME); -+} -+ -+/* stop the action to spi rom function */ -+static void ec_stop_spi(void) -+{ -+ unsigned char val; -+ -+ delay_spi(SPI_FINISH_WAIT_TIME); -+ val = -+ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK)); -+ ec_write(REG_XBISPICFG, val); -+ delay_spi(SPI_FINISH_WAIT_TIME); -+} -+ -+/* read one byte from xbi interface */ -+static int ec_read_byte(unsigned int addr, unsigned char *byte) -+{ -+ int ret = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* write the address */ -+ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); -+ /* start action */ -+ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ); -+ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ *byte = ec_read(REG_XBISPIDAT); -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* write one byte to ec rom */ -+static int ec_write_byte(unsigned int addr, unsigned char byte) -+{ -+ int ret = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* write the address */ -+ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); -+ ec_write(REG_XBISPIDAT, byte); -+ /* start action */ -+ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM); -+ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* unprotect SPI ROM */ -+/* EC_ROM_unprotect function code */ -+static int EC_ROM_unprotect(void) -+{ -+ unsigned char status; -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); -+ return 1; -+ } -+ -+ /* unprotect the status register of rom */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n"); -+ return 1; -+ } -+ status = ec_read(REG_XBISPIDAT); -+ ec_write(REG_XBISPIDAT, status & 0x02); -+ if (ec_instruction_cycle() < 0) { -+ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n"); -+ return 1; -+ } -+ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); -+ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n"); -+ return 1; -+ } -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/* erase one block or chip or sector as needed */ -+static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr) -+{ -+ unsigned char status; -+ int ret = 0, i = 0; -+ int unprotect_count = 3; -+ int check_flag = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+#ifdef EC_ROM_PROTECTION -+ /* added for re-check SPICMD_READ_STATUS */ -+ while (unprotect_count-- > 0) { -+ if (EC_ROM_unprotect()) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* first time:500ms --> 5.5sec -->10.5sec */ -+ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++) -+ udelay(50000); -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) -+ == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); -+ } else { -+ status = ec_read(REG_XBISPIDAT); -+ printk(KERN_INFO "Read unprotect status : 0x%x\n", -+ status); -+ if ((status & 0x1C) == 0x00) { -+ printk(KERN_INFO -+ "Read unprotect status OK1 : 0x%x\n", -+ status & 0x1C); -+ check_flag = 1; -+ break; -+ } -+ } -+ } -+ -+ if (!check_flag) { -+ printk(KERN_INFO "SPI ROM unprotect fail.\n"); -+ return 1; -+ } -+#endif -+ -+ /* block address fill */ -+ if (erase_cmd == SPICMD_BLK_ERASE) { -+ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0); -+ } -+ -+ /* erase the whole chip first */ -+ ec_write(REG_XBISPICMD, erase_cmd); -+ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* update the whole rom content with H/W mode -+ * PLEASE USING ec_unit_erase() FIRSTLY -+ */ -+static int ec_program_rom(struct ec_info *info, int flag) -+{ -+ unsigned int addr = 0; -+ unsigned long size = 0; -+ unsigned char *ptr = NULL; -+ unsigned char data; -+ unsigned char val = 0; -+ int ret = 0; -+ int i, j; -+ unsigned char status; -+ -+ /* modify for program serial No. -+ * set IE_START_ADDR & use idle mode, -+ * disable WDD -+ */ -+ if (flag == PROGRAM_FLAG_ROM) { -+ ret = ec_init_reset_mode(); -+ addr = info->start_addr + EC_START_ADDR; -+ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n"); -+ } else if (flag == PROGRAM_FLAG_IE) { -+ ret = ec_init_idle_mode(); -+ ec_disable_WDD(); -+ addr = info->start_addr + IE_START_ADDR; -+ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n"); -+ } else { -+ return 0; -+ } -+ -+ if (ret < 0) { -+ if (flag == PROGRAM_FLAG_IE) -+ ec_enable_WDD(); -+ return ret; -+ } -+ -+ size = info->size; -+ ptr = info->buf; -+ printk(KERN_INFO "starting update ec ROM..............\n"); -+ -+ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr); -+ if (ret) { -+ printk(KERN_ERR "program ec : erase block failed.\n"); -+ goto out; -+ } -+ printk(KERN_ERR "program ec : erase block OK.\n"); -+ -+ i = 0; -+ while (i < size) { -+ data = *(ptr + i); -+ ec_write_byte(addr, data); -+ ec_read_byte(addr, &val); -+ if (val != data) { -+ ec_write_byte(addr, data); -+ ec_read_byte(addr, &val); -+ if (val != data) { -+ printk(KERN_INFO -+ "EC : Second flash program failed at:\t"); -+ printk(KERN_INFO -+ "addr : 0x%x, source : 0x%x, dest: 0x%x\n", -+ addr, data, val); -+ printk(KERN_INFO "This should not happen... STOP\n"); -+ break; -+ } -+ } -+ i++; -+ addr++; -+ } -+ -+#ifdef EC_ROM_PROTECTION -+ /* we should start spi access firstly */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n"); -+ goto out1; -+ } -+ -+ /* protect the status register of rom */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); -+ goto out1; -+ } -+ status = ec_read(REG_XBISPIDAT); -+ -+ ec_write(REG_XBISPIDAT, status | 0x1C); -+ if (ec_instruction_cycle() < 0) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : write status value failed.\n"); -+ goto out1; -+ } -+ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); -+ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n"); -+ goto out1; -+ } -+#endif -+ -+ /* disable the write action to spi rom */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n"); -+ goto out1; -+ } -+ -+ out1: -+ /* we should stop spi access firstly */ -+ ec_stop_spi(); -+ out: -+ /* for security */ -+ for (j = 0; j < 2000; j++) -+ udelay(1000); -+ -+ /* modify for program serial No. -+ * after program No exit idle mode -+ * and enable WDD -+ */ -+ if (flag == PROGRAM_FLAG_ROM) { -+ /* exit from the reset mode */ -+ ec_exit_reset_mode(); -+ } else { -+ /* ec exit from idle mode */ -+ ret = ec_exit_idle_mode(); -+ ec_enable_WDD(); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* ioctl */ -+static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd, -+ u_long arg) -+{ -+ struct ec_info ecinfo; -+ void __user *ptr = (void __user *)arg; -+ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); -+ int ret = 0; -+ -+ switch (cmd) { -+ case IOCTL_RDREG: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg read : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_MAX_REGADDR) -+ || (ecreg->addr < EC_MIN_REGADDR)) { -+ printk(KERN_ERR -+ "reg read : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ecreg->val = ec_read(ecreg->addr); -+ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg read : copy to user error.\n"); -+ return -EFAULT; -+ } -+ break; -+ case IOCTL_WRREG: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg write : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_MAX_REGADDR) -+ || (ecreg->addr < EC_MIN_REGADDR)) { -+ printk(KERN_ERR -+ "reg write : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ec_write(ecreg->addr, ecreg->val); -+ break; -+ case IOCTL_READ_EC: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "spi read : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_RAM_ADDR) -+ && (ecreg->addr < EC_MAX_REGADDR)) { -+ printk(KERN_ERR -+ "spi read : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ec_read_byte(ecreg->addr, &(ecreg->val)); -+ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "spi read : copy to user error.\n"); -+ return -EFAULT; -+ } -+ break; -+ case IOCTL_PROGRAM_IE: -+ ecinfo.start_addr = EC_START_ADDR; -+ ecinfo.size = EC_CONTENT_MAX_SIZE; -+ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); -+ if (ecinfo.buf == NULL) { -+ printk(KERN_ERR "program ie : kmalloc failed.\n"); -+ return -ENOMEM; -+ } -+ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size); -+ if (ret) { -+ printk(KERN_ERR "program ie : copy from user error.\n"); -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ return -EFAULT; -+ } -+ -+ /* use ec_program_rom to write serial No */ -+ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE); -+ -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ break; -+ case IOCTL_PROGRAM_EC: -+ ecinfo.start_addr = EC_START_ADDR; -+ if (get_user((ecinfo.size), (u32 *) ptr)) { -+ printk(KERN_ERR "program ec : get user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) { -+ printk(KERN_ERR "program ec : size out of limited.\n"); -+ return -EINVAL; -+ } -+ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); -+ if (ecinfo.buf == NULL) { -+ printk(KERN_ERR "program ec : kmalloc failed.\n"); -+ return -ENOMEM; -+ } -+ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size); -+ if (ret) { -+ printk(KERN_ERR "program ec : copy from user error.\n"); -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ return -EFAULT; -+ } -+ -+ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM); -+ -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ break; -+ -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static long misc_compat_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg); -+} -+ -+static int misc_open(struct inode *inode, struct file *filp) -+{ -+ struct ec_reg *ecreg = NULL; -+ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL); -+ if (ecreg) -+ filp->private_data = ecreg; -+ -+ return ecreg ? 0 : -ENOMEM; -+} -+ -+static int misc_release(struct inode *inode, struct file *filp) -+{ -+ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); -+ -+ filp->private_data = NULL; -+ kfree(ecreg); -+ -+ return 0; -+} -+ -+static const struct file_operations ecmisc_fops = { -+ .open = misc_open, -+ .release = misc_release, -+ .read = NULL, -+ .write = NULL, -+#ifdef CONFIG_64BIT -+ .compat_ioctl = misc_compat_ioctl, -+#else -+ .ioctl = misc_ioctl, -+#endif -+}; -+ -+static struct miscdevice ecmisc_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = EC_MISC_DEV, -+ .fops = &ecmisc_fops -+}; -+ -+static int __init ecmisc_init(void) -+{ -+ int ret; -+ -+ printk(KERN_INFO "EC misc device init.\n"); -+ ret = misc_register(&ecmisc_device); -+ -+ return ret; -+} -+ -+static void __exit ecmisc_exit(void) -+{ -+ printk(KERN_INFO "EC misc device exit.\n"); -+ misc_deregister(&ecmisc_device); -+} -+ -+module_init(ecmisc_init); -+module_exit(ecmisc_exit); -+ -+MODULE_AUTHOR("liujl "); -+MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c -new file mode 100644 -index 0000000..32a2bdb ---- /dev/null -+++ b/drivers/platform/mips/yeeloong_laptop.c -@@ -0,0 +1,1360 @@ -+/* -+ * Driver for YeeLoong laptop extras -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin , Liu Junliang -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include /* for backlight subdriver */ -+#include -+#include /* for hwmon subdriver */ -+#include -+#include /* for video output subdriver */ -+#include /* for lcd output subdriver */ -+#include /* for hotkey subdriver */ -+#include -+#include -+#include -+#include /* for AC & Battery subdriver */ -+#include /* for register_reboot_notifier */ -+#include /* for register_pm_notifier */ -+ -+#include -+ -+#include /* for loongson_cmdline */ -+#include -+ -+#define ON 1 -+#define OFF 0 -+#define EVENT_START EVENT_LID -+ -+/* common function */ -+#define EC_VER_LEN 64 -+ -+static int ec_version_before(char *version) -+{ -+ char *p, ec_ver[EC_VER_LEN]; -+ -+ p = strstr(loongson_cmdline, "EC_VER="); -+ if (!p) -+ memset(ec_ver, 0, EC_VER_LEN); -+ else { -+ strncpy(ec_ver, p, EC_VER_LEN); -+ p = strstr(ec_ver, " "); -+ if (p) -+ *p = '\0'; -+ } -+ -+ return (strncasecmp(ec_ver, version, 64) < 0); -+} -+ -+/* backlight subdriver */ -+#define MIN_BRIGHTNESS 1 -+#define MAX_BRIGHTNESS 8 -+ -+static int yeeloong_set_brightness(struct backlight_device *bd) -+{ -+ unsigned char level; -+ static unsigned char old_level; -+ -+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && -+ bd->props.power == FB_BLANK_UNBLANK) ? -+ bd->props.brightness : 0; -+ -+ level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS); -+ -+ /* Avoid to modify the brightness when EC is tuning it */ -+ if (old_level != level) { -+ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level) -+ ec_write(REG_DISPLAY_BRIGHTNESS, level); -+ old_level = level; -+ } -+ -+ return 0; -+} -+ -+static int yeeloong_get_brightness(struct backlight_device *bd) -+{ -+ return ec_read(REG_DISPLAY_BRIGHTNESS); -+} -+ -+static struct backlight_ops backlight_ops = { -+ .get_brightness = yeeloong_get_brightness, -+ .update_status = yeeloong_set_brightness, -+}; -+ -+static struct backlight_device *yeeloong_backlight_dev; -+ -+static int yeeloong_backlight_init(void) -+{ -+ int ret; -+ struct backlight_properties props; -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.max_brightness = MAX_BRIGHTNESS; -+ props.type = BACKLIGHT_PLATFORM; -+ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL, -+ NULL, &backlight_ops, &props); -+ -+ if (IS_ERR(yeeloong_backlight_dev)) { -+ ret = PTR_ERR(yeeloong_backlight_dev); -+ yeeloong_backlight_dev = NULL; -+ return ret; -+ } -+ -+ yeeloong_backlight_dev->props.brightness = -+ yeeloong_get_brightness(yeeloong_backlight_dev); -+ backlight_update_status(yeeloong_backlight_dev); -+ -+ return 0; -+} -+ -+static void yeeloong_backlight_exit(void) -+{ -+ if (yeeloong_backlight_dev) { -+ backlight_device_unregister(yeeloong_backlight_dev); -+ yeeloong_backlight_dev = NULL; -+ } -+} -+ -+/* AC & Battery subdriver */ -+ -+static struct power_supply yeeloong_ac, yeeloong_bat; -+ -+#define RET (val->intval) -+ -+#define BAT_CAP_CRITICAL 5 -+#define BAT_CAP_HIGH 95 -+ -+#define get_bat(type) \ -+ ec_read(REG_BAT_##type) -+ -+#define get_bat_l(type) \ -+ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW)) -+ -+static int yeeloong_get_ac_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ if (psp == POWER_SUPPLY_PROP_ONLINE) -+ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN); -+ -+ return 0; -+} -+ -+static enum power_supply_property yeeloong_ac_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static struct power_supply yeeloong_ac = { -+ .name = "yeeloong-ac", -+ .type = POWER_SUPPLY_TYPE_MAINS, -+ .properties = yeeloong_ac_props, -+ .num_properties = ARRAY_SIZE(yeeloong_ac_props), -+ .get_property = yeeloong_get_ac_props, -+}; -+ -+static inline bool is_bat_in(void) -+{ -+ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN); -+} -+ -+static int get_bat_temp(void) -+{ -+ return get_bat_l(TEMPERATURE) * 10; -+} -+ -+static int get_bat_current(void) -+{ -+ return -(s16)get_bat_l(CURRENT); -+} -+ -+static int get_bat_voltage(void) -+{ -+ return get_bat_l(VOLTAGE); -+} -+ -+static char *get_manufacturer(void) -+{ -+ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO"; -+} -+ -+static int get_relative_cap(void) -+{ -+ /* -+ * When the relative capacity becomes 2, the hardware is observed to -+ * have been turned off forcely. so, we must tune it be suitable to -+ * make the software do related actions. -+ */ -+ int tmp = get_bat_l(RELATIVE_CAP); -+ -+ if (tmp <= (BAT_CAP_CRITICAL * 2)) -+ tmp -= 3; -+ -+ return tmp; -+} -+ -+static int yeeloong_get_bat_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ switch (psp) { -+ /* Fixed information */ -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ /* mV -> µV */ -+ RET = get_bat_l(DESIGN_VOL) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: -+ /* mAh->µAh */ -+ RET = get_bat_l(DESIGN_CAP) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL: -+ /* µAh */ -+ RET = get_bat_l(FULLCHG_CAP) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_MANUFACTURER: -+ val->strval = get_manufacturer(); -+ break; -+ /* Dynamic information */ -+ case POWER_SUPPLY_PROP_PRESENT: -+ RET = is_bat_in(); -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ /* mA -> µA */ -+ RET = is_bat_in() ? get_bat_current() * 1000 : 0; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ /* mV -> µV */ -+ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0; -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ /* Celcius */ -+ RET = is_bat_in() ? get_bat_temp() : 0; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ RET = is_bat_in() ? get_relative_cap() : 0; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: { -+ int status; -+ -+ if (!is_bat_in()) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ break; -+ } -+ -+ status = get_bat(STATUS); -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; -+ -+ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ break; -+ } -+ -+ if (status & BIT_BAT_STATUS_FULL) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; -+ else { -+ int curr_cap = get_relative_cap(); -+ -+ if (status & BIT_BAT_STATUS_LOW) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; -+ if (curr_cap <= BAT_CAP_CRITICAL) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; -+ } else if (curr_cap >= BAT_CAP_HIGH) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; -+ } -+ } break; -+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: -+ /* seconds */ -+ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0; -+ break; -+ case POWER_SUPPLY_PROP_STATUS: { -+ int charge = get_bat(CHARGE); -+ -+ RET = POWER_SUPPLY_STATUS_UNKNOWN; -+ if (charge & FLAG_BAT_CHARGE_DISCHARGE) -+ RET = POWER_SUPPLY_STATUS_DISCHARGING; -+ else if (charge & FLAG_BAT_CHARGE_CHARGE) -+ RET = POWER_SUPPLY_STATUS_CHARGING; -+ } break; -+ case POWER_SUPPLY_PROP_HEALTH: { -+ int status; -+ -+ if (!is_bat_in()) { -+ RET = POWER_SUPPLY_HEALTH_UNKNOWN; -+ break; -+ } -+ -+ status = get_bat(STATUS); -+ RET = POWER_SUPPLY_HEALTH_GOOD; -+ -+ if (status & (BIT_BAT_STATUS_DESTROY | -+ BIT_BAT_STATUS_LOW)) -+ RET = POWER_SUPPLY_HEALTH_DEAD; -+ if (get_bat(CHARGE_STATUS) & -+ BIT_BAT_CHARGE_STATUS_OVERTEMP) -+ RET = POWER_SUPPLY_HEALTH_OVERHEAT; -+ } break; -+ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */ -+ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+#undef RET -+ -+static enum power_supply_property yeeloong_bat_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_FULL, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_CAPACITY_LEVEL, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_MANUFACTURER, -+}; -+ -+static struct power_supply yeeloong_bat = { -+ .name = "yeeloong-bat", -+ .type = POWER_SUPPLY_TYPE_BATTERY, -+ .properties = yeeloong_bat_props, -+ .num_properties = ARRAY_SIZE(yeeloong_bat_props), -+ .get_property = yeeloong_get_bat_props, -+}; -+ -+static int ac_bat_initialized; -+ -+static int yeeloong_bat_init(void) -+{ -+ int ret; -+ -+ ret = power_supply_register(NULL, &yeeloong_ac); -+ if (ret) -+ return ret; -+ ret = power_supply_register(NULL, &yeeloong_bat); -+ if (ret) { -+ power_supply_unregister(&yeeloong_ac); -+ return ret; -+ } -+ ac_bat_initialized = 1; -+ -+ return 0; -+} -+ -+static void yeeloong_bat_exit(void) -+{ -+ ac_bat_initialized = 0; -+ -+ power_supply_unregister(&yeeloong_ac); -+ power_supply_unregister(&yeeloong_bat); -+} -+/* hwmon subdriver */ -+ -+#define MIN_FAN_SPEED 0 -+#define MAX_FAN_SPEED 3 -+ -+#define get_fan(type) \ -+ ec_read(REG_FAN_##type) -+ -+#define set_fan(type, val) \ -+ ec_write(REG_FAN_##type, val) -+ -+static inline int get_fan_speed_level(void) -+{ -+ return get_fan(SPEED_LEVEL); -+} -+static inline void set_fan_speed_level(int speed) -+{ -+ set_fan(SPEED_LEVEL, speed); -+} -+ -+static inline int get_fan_mode(void) -+{ -+ return get_fan(AUTO_MAN_SWITCH); -+} -+static inline void set_fan_mode(int mode) -+{ -+ set_fan(AUTO_MAN_SWITCH, mode); -+} -+ -+/* -+ * 3 different modes: Full speed(0); manual mode(1); auto mode(2) -+ */ -+static int get_fan_pwm_enable(void) -+{ -+ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 : -+ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1; -+} -+ -+static void set_fan_pwm_enable(int mode) -+{ -+ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL); -+ if (mode == 0) -+ set_fan_speed_level(MAX_FAN_SPEED); -+} -+ -+static int get_fan_pwm(void) -+{ -+ return get_fan_speed_level(); -+} -+ -+static void set_fan_pwm(int value) -+{ -+ if (get_fan_mode() != BIT_FAN_MANUAL) -+ return; -+ -+ value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED); -+ -+ /* We must ensure the fan is on */ -+ if (value > 0) -+ set_fan(CONTROL, ON); -+ -+ set_fan_speed_level(value); -+} -+ -+static inline int get_fan_speed(void) -+{ -+ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW); -+} -+ -+static int get_fan_rpm(void) -+{ -+ return FAN_SPEED_DIVIDER / get_fan_speed(); -+} -+ -+static int get_cpu_temp(void) -+{ -+ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000; -+} -+ -+static int get_cpu_temp_max(void) -+{ -+ return 60 * 1000; -+} -+ -+static int get_bat_temp_alarm(void) -+{ -+ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP); -+} -+ -+static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long value; -+ -+ if (!count) -+ return 0; -+ -+ ret = kstrtoul(buf, 10, &value); -+ if (ret) -+ return ret; -+ -+ set(value); -+ -+ return count; -+} -+ -+static ssize_t show_sys_hwmon(int (*get) (void), char *buf) -+{ -+ return sprintf(buf, "%d\n", get()); -+} -+ -+#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ -+ static ssize_t show_##_name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ char *buf) \ -+ { \ -+ return show_sys_hwmon(_set, buf); \ -+ } \ -+ static ssize_t store_##_name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ return store_sys_hwmon(_get, buf, count); \ -+ } \ -+ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); -+ -+CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL); -+CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm); -+CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable, -+ set_fan_pwm_enable); -+CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL); -+CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL); -+CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL); -+CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL); -+CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL); -+CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL); -+ -+static ssize_t -+show_name(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ return sprintf(buf, "yeeloong\n"); -+} -+ -+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); -+ -+static struct attribute *hwmon_attributes[] = { -+ &sensor_dev_attr_pwm1.dev_attr.attr, -+ &sensor_dev_attr_pwm1_enable.dev_attr.attr, -+ &sensor_dev_attr_fan1_input.dev_attr.attr, -+ &sensor_dev_attr_temp1_input.dev_attr.attr, -+ &sensor_dev_attr_temp1_max.dev_attr.attr, -+ &sensor_dev_attr_temp2_input.dev_attr.attr, -+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, -+ &sensor_dev_attr_curr1_input.dev_attr.attr, -+ &sensor_dev_attr_in1_input.dev_attr.attr, -+ &sensor_dev_attr_name.dev_attr.attr, -+ NULL -+}; -+ -+static struct attribute_group hwmon_attribute_group = { -+ .attrs = hwmon_attributes -+}; -+ -+static struct device *yeeloong_hwmon_dev; -+ -+static int yeeloong_hwmon_init(void) -+{ -+ int ret; -+ -+ yeeloong_hwmon_dev = hwmon_device_register(NULL); -+ if (IS_ERR(yeeloong_hwmon_dev)) { -+ yeeloong_hwmon_dev = NULL; -+ return PTR_ERR(yeeloong_hwmon_dev); -+ } -+ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj, -+ &hwmon_attribute_group); -+ if (ret) { -+ hwmon_device_unregister(yeeloong_hwmon_dev); -+ yeeloong_hwmon_dev = NULL; -+ return ret; -+ } -+ /* ensure fan is set to auto mode */ -+ set_fan_pwm_enable(2); -+ -+ return 0; -+} -+ -+static void yeeloong_hwmon_exit(void) -+{ -+ if (yeeloong_hwmon_dev) { -+ sysfs_remove_group(&yeeloong_hwmon_dev->kobj, -+ &hwmon_attribute_group); -+ hwmon_device_unregister(yeeloong_hwmon_dev); -+ yeeloong_hwmon_dev = NULL; -+ } -+} -+ -+/* video output subdriver */ -+ -+#define LCD 0 -+#define CRT 1 -+#define VOD_NUM 2 /* The total number of video output device*/ -+ -+static struct output_device *vod[VOD_NUM]; -+ -+static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT}; -+ -+static int get_vo_dev(struct output_device *od) -+{ -+ int i, dev; -+ -+ dev = -1; -+ for (i = 0; i < VOD_NUM; i++) -+ if (od == vod[i]) -+ dev = i; -+ -+ return dev; -+} -+ -+static int vo_get_status(int dev) -+{ -+ return ec_read(vor[dev]); -+} -+ -+static int yeeloong_vo_get_status(struct output_device *od) -+{ -+ int vd; -+ -+ vd = get_vo_dev(od); -+ if (vd != -1) -+ return vo_get_status(vd); -+ -+ return -ENODEV; -+} -+ -+static void vo_set_state(int dev, int state) -+{ -+ int addr; -+ unsigned long value; -+ -+ switch (dev) { -+ case LCD: -+ addr = 0x31; -+ break; -+ case CRT: -+ addr = 0x21; -+ break; -+ default: -+ /* return directly if the wrong video output device */ -+ return; -+ } -+ -+ outb(addr, 0x3c4); -+ value = inb(0x3c5); -+ -+ switch (dev) { -+ case LCD: -+ value |= (state ? 0x03 : 0x02); -+ break; -+ case CRT: -+ if (state) -+ clear_bit(7, &value); -+ else -+ set_bit(7, &value); -+ break; -+ default: -+ break; -+ } -+ -+ outb(addr, 0x3c4); -+ outb(value, 0x3c5); -+ -+ if (dev == LCD) -+ ec_write(REG_BACKLIGHT_CTRL, state); -+} -+ -+static int yeeloong_vo_set_state(struct output_device *od) -+{ -+ int vd; -+ -+ vd = get_vo_dev(od); -+ if (vd == -1) -+ return -ENODEV; -+ -+ if (vd == CRT && !vo_get_status(vd)) -+ return 0; -+ -+ vo_set_state(vd, !!od->request_state); -+ -+ return 0; -+} -+ -+static struct output_properties vop = { -+ .set_state = yeeloong_vo_set_state, -+ .get_status = yeeloong_vo_get_status, -+}; -+ -+static int yeeloong_vo_init(void) -+{ -+ int ret, i; -+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; -+ -+ /* Register video output device: lcd, crt */ -+ for (i = 0; i < VOD_NUM; i++) { -+ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop); -+ if (IS_ERR(vod[i])) { -+ if (i != 0) -+ video_output_unregister(vod[i-1]); -+ ret = PTR_ERR(vod[i]); -+ vod[i] = NULL; -+ return ret; -+ } -+ } -+ /* Ensure LCD is on by default */ -+ vo_set_state(LCD, ON); -+ -+ /* -+ * Turn off CRT by default, and will be enabled when the CRT -+ * connectting event reported by SCI -+ */ -+ vo_set_state(CRT, OFF); -+ -+ return 0; -+} -+ -+static void yeeloong_vo_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < VOD_NUM; i++) { -+ if (vod[i]) { -+ video_output_unregister(vod[i]); -+ vod[i] = NULL; -+ } -+ } -+} -+ -+/* lcd subdriver */ -+ -+struct lcd_device *lcd[VOD_NUM]; -+ -+static int get_lcd_dev(struct lcd_device *ld) -+{ -+ int i, dev; -+ -+ dev = -1; -+ for (i = 0; i < VOD_NUM; i++) -+ if (ld == lcd[i]) -+ dev = i; -+ -+ return dev; -+} -+ -+static int yeeloong_lcd_set_power(struct lcd_device *ld, int power) -+{ -+ int dev = get_lcd_dev(ld); -+ -+ if (power == FB_BLANK_UNBLANK) -+ vo_set_state(dev, ON); -+ if (power == FB_BLANK_POWERDOWN) -+ vo_set_state(dev, OFF); -+ -+ return 0; -+} -+ -+static int yeeloong_lcd_get_power(struct lcd_device *ld) -+{ -+ return vo_get_status(get_lcd_dev(ld)); -+} -+ -+static struct lcd_ops lcd_ops = { -+ .set_power = yeeloong_lcd_set_power, -+ .get_power = yeeloong_lcd_get_power, -+}; -+ -+static int yeeloong_lcd_init(void) -+{ -+ int ret, i; -+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; -+ -+ /* Register video output device: lcd, crt */ -+ for (i = 0; i < VOD_NUM; i++) { -+ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops); -+ if (IS_ERR(lcd[i])) { -+ if (i != 0) -+ lcd_device_unregister(lcd[i-1]); -+ ret = PTR_ERR(lcd[i]); -+ lcd[i] = NULL; -+ return ret; -+ } -+ } -+#if 0 -+ /* This has been done by the vide output driver */ -+ -+ /* Ensure LCD is on by default */ -+ vo_set_state(LCD, ON); -+ -+ /* -+ * Turn off CRT by default, and will be enabled when the CRT -+ * connectting event reported by SCI -+ */ -+ vo_set_state(CRT, OFF); -+#endif -+ return 0; -+} -+ -+static void yeeloong_lcd_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < VOD_NUM; i++) { -+ if (lcd[i]) { -+ lcd_device_unregister(lcd[i]); -+ lcd[i] = NULL; -+ } -+ } -+} -+ -+/* hotkey subdriver */ -+ -+static struct input_dev *yeeloong_hotkey_dev; -+ -+static atomic_t reboot_flag, sleep_flag; -+#define in_sleep() (&sleep_flag) -+#define in_reboot() (&reboot_flag) -+ -+static const struct key_entry yeeloong_keymap[] = { -+ {KE_SW, EVENT_LID, { SW_LID } }, -+ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */ -+ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */ -+ {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */ -+ {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */ -+ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */ -+ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */ -+ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */ -+ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */ -+ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */ -+ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */ -+ {KE_END, 0} -+}; -+ -+static int is_fake_event(u16 keycode) -+{ -+ switch (keycode) { -+ case KEY_SLEEP: -+ case SW_LID: -+ return atomic_read(in_sleep()) | atomic_read(in_reboot()); -+ break; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static struct key_entry *get_event_key_entry(int event, int status) -+{ -+ struct key_entry *ke; -+ static int old_brightness_status = -1; -+ static int old_volume_status = -1; -+ -+ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event); -+ if (!ke) -+ return NULL; -+ -+ switch (event) { -+ case EVENT_DISPLAY_BRIGHTNESS: -+ /* current status > old one, means up */ -+ if ((status < old_brightness_status) || (0 == status)) -+ ke++; -+ old_brightness_status = status; -+ break; -+ case EVENT_AUDIO_VOLUME: -+ if ((status < old_volume_status) || (0 == status)) -+ ke++; -+ old_volume_status = status; -+ break; -+ default: -+ break; -+ } -+ -+ return ke; -+} -+ -+static int report_lid_switch(int status) -+{ -+ static int old_status; -+ -+ /* -+ * LID is a switch button, so, two continuous same status should be -+ * ignored -+ */ -+ if (old_status != status) { -+ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status); -+ input_sync(yeeloong_hotkey_dev); -+ } -+ old_status = status; -+ -+ return status; -+} -+ -+static int crt_detect_handler(int status) -+{ -+ /* -+ * When CRT is inserted, enable its output and disable the LCD output, -+ * otherwise, do reversely. -+ */ -+ vo_set_state(CRT, status); -+ vo_set_state(LCD, !status); -+ -+ return status; -+} -+ -+static int displaytoggle_handler(int status) -+{ -+ /* EC(>=PQ1D26) does this job for us, we can not do it again, -+ * otherwise, the brightness will not resume to the normal level! */ -+ if (ec_version_before("EC_VER=PQ1D26")) -+ vo_set_state(LCD, status); -+ -+ return status; -+} -+ -+static int mypow(int x, int y) -+{ -+ int i, j = x; -+ -+ for (i = 1; i < y; i++) -+ j *= j; -+ -+ return j; -+} -+ -+static int switchvideomode_handler(int status) -+{ -+ /* Default status: CRT|LCD = 0|1 = 1 */ -+ static int bin_state = 1; -+ int i; -+ -+ /* -+ * Only enable switch video output button -+ * when CRT is connected -+ */ -+ if (!vo_get_status(CRT)) -+ return 0; -+ /* -+ * 2. no CRT connected: LCD on, CRT off -+ * 3. BOTH on -+ * 0. BOTH off -+ * 1. LCD off, CRT on -+ */ -+ -+ bin_state++; -+ if (bin_state > mypow(2, VOD_NUM) - 1) -+ bin_state = 0; -+ -+ for (i = 0; i < VOD_NUM; i++) -+ vo_set_state(i, bin_state & (1 << i)); -+ -+ return bin_state; -+} -+ -+static int camera_handler(int status) -+{ -+ int value; -+ -+ value = ec_read(REG_CAMERA_CONTROL); -+ ec_write(REG_CAMERA_CONTROL, value | (1 << 1)); -+ -+ return status; -+} -+ -+static int usb2_handler(int status) -+{ -+ pr_emerg("USB2 Over Current occurred\n"); -+ -+ return status; -+} -+ -+static int usb0_handler(int status) -+{ -+ pr_emerg("USB0 Over Current occurred\n"); -+ -+ return status; -+} -+ -+static int ac_bat_handler(int status) -+{ -+ if (ac_bat_initialized) { -+ power_supply_changed(&yeeloong_ac); -+ power_supply_changed(&yeeloong_bat); -+ } -+ -+ return status; -+} -+ -+struct sci_event { -+ int reg; -+ sci_handler handler; -+}; -+ -+static const struct sci_event se[] = { -+ [EVENT_AC_BAT] = {0, ac_bat_handler}, -+ [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL}, -+ [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL}, -+ [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler}, -+ [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler}, -+ [EVENT_BLACK_SCREEN] = {REG_DISPLAY_LCD, displaytoggle_handler}, -+ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL}, -+ [EVENT_LID] = {REG_LID_DETECT, NULL}, -+ [EVENT_DISPLAY_TOGGLE] = {0, switchvideomode_handler}, -+ [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler}, -+ [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler}, -+ [EVENT_WLAN] = {REG_WLAN, NULL}, -+}; -+ -+static void do_event_action(int event) -+{ -+ int status = -1; -+ struct key_entry *ke; -+ struct sci_event *sep; -+ -+ sep = (struct sci_event *)&se[event]; -+ -+ if (sep->reg != 0) -+ status = ec_read(sep->reg); -+ -+ if (status == -1) { -+ /* ec_read hasn't been called, status is invalid */ -+ return; -+ } -+ -+ if (sep->handler != NULL) -+ status = sep->handler(status); -+ -+ pr_debug("%s: event: %d status: %d\n", __func__, event, status); -+ -+ /* Report current key to user-space */ -+ ke = get_event_key_entry(event, status); -+ -+ /* -+ * Ignore the LID and SLEEP event when we are already in sleep or -+ * reboot state, this will avoid the recursive pm operations. but note: -+ * the report_lid_switch() called in arch/mips/loongson/lemote-2f/pm.c -+ * is necessary, because it is used to wake the system from sleep -+ * state. In the future, perhaps SW_LID should works like SLEEP, no -+ * need to function as a SWITCH, just report the state when the LID is -+ * closed is enough, this event can tell the software to "SLEEP", no -+ * need to tell the softwares when we are resuming from "SLEEP". -+ */ -+ if (ke && !is_fake_event(ke->keycode)) { -+ if (ke->keycode == SW_LID) -+ report_lid_switch(status); -+ else -+ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1, -+ true); -+ } -+} -+ -+/* -+ * SCI(system control interrupt) main interrupt routine -+ * -+ * We will do the query and get event number together so the interrupt routine -+ * should be longer than 120us now at least 3ms elpase for it. -+ */ -+static irqreturn_t sci_irq_handler(int irq, void *dev_id) -+{ -+ int ret, event; -+ -+ if (SCI_IRQ_NUM != irq) -+ return IRQ_NONE; -+ -+ /* Query the event number */ -+ ret = ec_query_event_num(); -+ if (ret < 0) -+ return IRQ_NONE; -+ -+ event = ec_get_event_num(); -+ if (event < EVENT_START || event > EVENT_END) -+ return IRQ_NONE; -+ -+ /* Execute corresponding actions */ -+ do_event_action(event); -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Config and init some msr and gpio register properly. -+ */ -+static int sci_irq_init(void) -+{ -+ u32 hi, lo; -+ u32 gpio_base; -+ unsigned long flags; -+ int ret; -+ -+ /* Get gpio base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); -+ gpio_base = lo & 0xff00; -+ -+ /* Filter the former kb3310 interrupt for security */ -+ ret = ec_query_event_num(); -+ if (ret) -+ return ret; -+ -+ /* For filtering next number interrupt */ -+ udelay(10000); -+ -+ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN -+ * gpio : -+ * input, pull-up, no-invert, event-count and value 0, -+ * no-filter, no edge mode -+ * gpio27 map to Virtual gpio0 -+ * msr : -+ * no primary and lpc -+ * Unrestricted Z input to IG10 from Virtual gpio 0. -+ */ -+ local_irq_save(flags); -+ _rdmsr(0x80000024, &hi, &lo); -+ lo &= ~(1 << 10); -+ _wrmsr(0x80000024, hi, lo); -+ _rdmsr(0x80000025, &hi, &lo); -+ lo &= ~(1 << 10); -+ _wrmsr(0x80000025, hi, lo); -+ _rdmsr(0x80000023, &hi, &lo); -+ lo |= (0x0a << 0); -+ _wrmsr(0x80000023, hi, lo); -+ local_irq_restore(flags); -+ -+ /* Set gpio27 as sci interrupt -+ * -+ * input, pull-up, no-fliter, no-negedge, invert -+ * the sci event is just about 120us -+ */ -+ asm(".set noreorder\n"); -+ /* input enable */ -+ outl(0x00000800, (gpio_base | 0xA0)); -+ /* revert the input */ -+ outl(0x00000800, (gpio_base | 0xA4)); -+ /* event-int enable */ -+ outl(0x00000800, (gpio_base | 0xB8)); -+ asm(".set reorder\n"); -+ -+ return 0; -+} -+ -+static int notify_reboot(struct notifier_block *nb, unsigned long event, void *buf) -+{ -+ switch (event) { -+ case SYS_RESTART: -+ case SYS_HALT: -+ case SYS_POWER_OFF: -+ atomic_set(in_reboot(), 1); -+ break; -+ default: -+ return NOTIFY_DONE; -+ } -+ -+ return NOTIFY_OK; -+} -+ -+static int notify_pm(struct notifier_block *nb, unsigned long event, void *buf) -+{ -+ switch (event) { -+ case PM_HIBERNATION_PREPARE: -+ case PM_SUSPEND_PREPARE: -+ atomic_inc(in_sleep()); -+ break; -+ case PM_POST_HIBERNATION: -+ case PM_POST_SUSPEND: -+ case PM_RESTORE_PREPARE: /* do we need this ?? */ -+ atomic_dec(in_sleep()); -+ break; -+ default: -+ return NOTIFY_DONE; -+ } -+ -+ pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event, -+ atomic_read(in_sleep())); -+ -+ return NOTIFY_OK; -+} -+ -+static struct notifier_block reboot_notifier = { -+ .notifier_call = notify_reboot, -+}; -+ -+static struct notifier_block pm_notifier = { -+ .notifier_call = notify_pm, -+}; -+ -+static int yeeloong_hotkey_init(void) -+{ -+ int ret = 0; -+ -+ ret = register_reboot_notifier(&reboot_notifier); -+ if (ret) { -+ pr_err("Can't register reboot notifier\n"); -+ goto end; -+ } -+ -+ ret = register_pm_notifier(&pm_notifier); -+ if (ret) { -+ pr_err("Can't register pm notifier\n"); -+ goto free_reboot_notifier; -+ } -+ -+ ret = sci_irq_init(); -+ if (ret) { -+ pr_err("Can't init SCI interrupt\n"); -+ goto free_pm_notifier; -+ } -+ -+ ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler, -+ IRQF_ONESHOT, "sci", NULL); -+ if (ret) { -+ pr_err("Can't thread SCI interrupt handler\n"); -+ goto free_pm_notifier; -+ } -+ -+ yeeloong_hotkey_dev = input_allocate_device(); -+ -+ if (!yeeloong_hotkey_dev) { -+ ret = -ENOMEM; -+ goto free_irq; -+ } -+ -+ yeeloong_hotkey_dev->name = "HotKeys"; -+ yeeloong_hotkey_dev->phys = "button/input0"; -+ yeeloong_hotkey_dev->id.bustype = BUS_HOST; -+ yeeloong_hotkey_dev->dev.parent = NULL; -+ -+ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL); -+ if (ret) { -+ pr_err("Failed to setup input device keymap\n"); -+ goto free_dev; -+ } -+ -+ ret = input_register_device(yeeloong_hotkey_dev); -+ if (ret) -+ goto free_keymap; -+ -+ /* Update the current status of LID */ -+ report_lid_switch(ON); -+ -+#ifdef CONFIG_LOONGSON_SUSPEND -+ /* Install the real yeeloong_report_lid_status for pm.c */ -+ yeeloong_report_lid_status = report_lid_switch; -+#endif -+ return 0; -+ -+free_keymap: -+ sparse_keymap_free(yeeloong_hotkey_dev); -+free_dev: -+ input_free_device(yeeloong_hotkey_dev); -+free_irq: -+ free_irq(SCI_IRQ_NUM, NULL); -+free_pm_notifier: -+ unregister_pm_notifier(&pm_notifier); -+free_reboot_notifier: -+ unregister_reboot_notifier(&reboot_notifier); -+end: -+ return ret; -+} -+ -+static void yeeloong_hotkey_exit(void) -+{ -+ /* Free irq */ -+ free_irq(SCI_IRQ_NUM, NULL); -+ -+#ifdef CONFIG_LOONGSON_SUSPEND -+ /* Uninstall yeeloong_report_lid_status for pm.c */ -+ if (yeeloong_report_lid_status == report_lid_switch) -+ yeeloong_report_lid_status = NULL; -+#endif -+ -+ if (yeeloong_hotkey_dev) { -+ sparse_keymap_free(yeeloong_hotkey_dev); -+ input_unregister_device(yeeloong_hotkey_dev); -+ yeeloong_hotkey_dev = NULL; -+ } -+} -+ -+#ifdef CONFIG_PM -+static void usb_ports_set(int status) -+{ -+ status = !!status; -+ -+ ec_write(REG_USB0_FLAG, status); -+ ec_write(REG_USB1_FLAG, status); -+ ec_write(REG_USB2_FLAG, status); -+} -+ -+static int yeeloong_suspend(struct device *dev) -+ -+{ -+ if (ec_version_before("EC_VER=PQ1D27")) -+ vo_set_state(LCD, OFF); -+ vo_set_state(CRT, OFF); -+ usb_ports_set(OFF); -+ -+ return 0; -+} -+ -+static int yeeloong_resume(struct device *dev) -+{ -+ int ret; -+ -+ if (ec_version_before("EC_VER=PQ1D27")) -+ vo_set_state(LCD, ON); -+ vo_set_state(CRT, ON); -+ usb_ports_set(ON); -+ -+ ret = sci_irq_init(); -+ if (ret) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend, -+ yeeloong_resume); -+#endif -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "yeeloong_laptop", -+ }, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver platform_driver = { -+ .driver = { -+ .name = "yeeloong_laptop", -+ .owner = THIS_MODULE, -+#ifdef CONFIG_PM -+ .pm = &yeeloong_pm_ops, -+#endif -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int __init yeeloong_init(void) -+{ -+ int ret; -+ -+ pr_info("YeeLoong Laptop platform specific driver loaded.\n"); -+ -+ /* Register platform stuff */ -+ ret = platform_driver_register(&platform_driver); -+ if (ret) { -+ pr_err("Failed to register YeeLoong platform driver.\n"); -+ return ret; -+ } -+ -+#define yeeloong_init_drv(drv, alias) do { \ -+ pr_info("Registered YeeLoong " alias " driver.\n"); \ -+ ret = yeeloong_ ## drv ## _init(); \ -+ if (ret) { \ -+ pr_err("Failed to register YeeLoong " alias " driver.\n"); \ -+ yeeloong_ ## drv ## _exit(); \ -+ return ret; \ -+ } \ -+} while (0) -+ -+ yeeloong_init_drv(backlight, "backlight"); -+ yeeloong_init_drv(bat, "battery and AC"); -+ yeeloong_init_drv(hwmon, "hardware monitor"); -+ yeeloong_init_drv(vo, "video output"); -+ yeeloong_init_drv(lcd, "lcd output"); -+ yeeloong_init_drv(hotkey, "hotkey input"); -+ -+ return 0; -+} -+ -+static void __exit yeeloong_exit(void) -+{ -+ yeeloong_hotkey_exit(); -+ yeeloong_lcd_exit(); -+ yeeloong_vo_exit(); -+ yeeloong_hwmon_exit(); -+ yeeloong_bat_exit(); -+ yeeloong_backlight_exit(); -+ platform_driver_unregister(&platform_driver); -+ -+ pr_info("YeeLoong platform specific driver unloaded.\n"); -+} -+ -+module_init(yeeloong_init); -+module_exit(yeeloong_exit); -+ -+MODULE_AUTHOR("Wu Zhangjin ; Liu Junliang "); -+MODULE_DESCRIPTION("YeeLoong laptop driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index b5b5c3d..f908003 100644 ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -727,6 +727,7 @@ comment "Platform RTC drivers" - config RTC_DRV_CMOS - tristate "PC-style 'CMOS'" - depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 -+ depends on !DEXXON_GDIUM - default y if X86 - help - Say "yes" here to get direct support for the real time clock -diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c -index f940056..a9bb1db 100644 ---- a/drivers/usb/host/pci-quirks.c -+++ b/drivers/usb/host/pci-quirks.c -@@ -450,6 +450,26 @@ void usb_amd_dev_put(void) - } - EXPORT_SYMBOL_GPL(usb_amd_dev_put); - -+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) -+static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) -+{ -+ u16 cmd; -+ return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); -+} -+ -+#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) -+#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) -+ -+static int mmio_resource_enabled(struct pci_dev *pdev, int idx) -+{ -+ return pci_resource_start(pdev, idx) && mmio_enabled(pdev); -+} -+#endif -+ -+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) - /* - * Make sure the controller is completely inactive, unable to - * generate interrupts or do DMA. -@@ -531,15 +551,6 @@ reset_needed: - } - EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); - --static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) --{ -- u16 cmd; -- return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); --} -- --#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) --#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) -- - static void quirk_usb_handoff_uhci(struct pci_dev *pdev) - { - unsigned long base = 0; -@@ -557,12 +568,11 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev) - if (base) - uhci_check_and_reset_hc(pdev, base); - } -+#else -+#define quirk_usb_handoff_uhci(x) do { } while (0) -+#endif /* CONFIG_USB_UHCI_HCD* */ - --static int mmio_resource_enabled(struct pci_dev *pdev, int idx) --{ -- return pci_resource_start(pdev, idx) && mmio_enabled(pdev); --} -- -+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) - static void quirk_usb_handoff_ohci(struct pci_dev *pdev) - { - void __iomem *base; -@@ -641,7 +651,11 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) - /* Now the controller is safely in SUSPEND and nothing can wake it up */ - iounmap(base); - } -+#else -+#define quirk_usb_handoff_ohci(x) do { } while(0) -+#endif /* CONFIG_USB_OHCI_HCD* */ - -+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) - static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { - { - /* Pegatron Lucid (ExoPC) */ -@@ -816,6 +830,9 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev) - - iounmap(base); - } -+#else -+#define quirk_usb_disable_ehci(x) do { } while (0) -+#endif /* CONFIG_USB_EHCI_HCD* */ - - /* - * handshake - spin reading a register until handshake completes -@@ -956,6 +973,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) - } - EXPORT_SYMBOL_GPL(usb_disable_xhci_ports); - -+#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) - /** - * PCI Quirks for xHCI. - * -@@ -1064,6 +1082,9 @@ hc_init: - - iounmap(base); - } -+#else -+#define quirk_usb_handoff_xhci(x) do { } while (0) -+#endif /* CONFIG_USB_UHCI_HCD* */ - - static void quirk_usb_early_handoff(struct pci_dev *pdev) - { -diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c -index f0c0c53..84dff90 100644 ---- a/drivers/usb/serial/option.c -+++ b/drivers/usb/serial/option.c -@@ -79,6 +79,9 @@ static void option_instat_callback(struct urb *urb); - #define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 - #define OPTION_PRODUCT_GTM380_MODEM 0x7201 - -+#define HUAWO_VENDOR_ID 0x21F5 -+#define HUAWO_PRODUCT_E1621 0x2008 -+ - #define HUAWEI_VENDOR_ID 0x12D1 - #define HUAWEI_PRODUCT_E173 0x140C - #define HUAWEI_PRODUCT_E1750 0x1406 -@@ -633,6 +636,7 @@ static const struct usb_device_id option_ids[] = { - { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, - { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, -+ { USB_DEVICE(HUAWO_VENDOR_ID, HUAWO_PRODUCT_E1621) }, /* QUANTA 6500 chips, Unicom extensive use of this card */ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, -diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig -index 8bf495f..f6a15b6 100644 ---- a/drivers/video/Kconfig -+++ b/drivers/video/Kconfig -@@ -36,6 +36,12 @@ config VGASTATE - tristate - default n - -+config VIDEO_OUTPUT_CONTROL -+ tristate "Lowlevel video output switch controls" -+ help -+ This framework adds support for low-level control of the video -+ output switch. -+ - config VIDEOMODE_HELPERS - bool - -diff --git a/drivers/video/Makefile b/drivers/video/Makefile -index 9ad3c17..3d869d9 100644 ---- a/drivers/video/Makefile -+++ b/drivers/video/Makefile -@@ -7,6 +7,8 @@ obj-y += backlight/ - - obj-y += fbdev/ - -+#video output switch sysfs driver -+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o - obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o - ifeq ($(CONFIG_OF),y) - obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o -diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig -index b3dd417..452035ad 100644 ---- a/drivers/video/fbdev/Kconfig -+++ b/drivers/video/fbdev/Kconfig -@@ -2450,6 +2450,19 @@ config FB_SIMPLE - Configuration re: surface address, size, and format must be provided - through device tree, or plain old platform data. - -+config FB_SM712 -+ tristate "Silicon Motion SM712 framebuffer support" -+ depends on FB && PCI -+ select FB_CFB_FILLRECT -+ select FB_CFB_COPYAREA -+ select FB_CFB_IMAGEBLIT -+ help -+ Frame buffer driver for the Silicon Motion SM712 chip. -+ -+ This driver is also available as a module. The module will be -+ called sm712fb. If you want to compile it as a module, say M -+ here and read . -+ - source "drivers/video/fbdev/omap/Kconfig" - source "drivers/video/fbdev/omap2/Kconfig" - source "drivers/video/fbdev/exynos/Kconfig" -diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile -index 1979aff..9b694f9 100644 ---- a/drivers/video/fbdev/Makefile -+++ b/drivers/video/fbdev/Makefile -@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o - obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o - obj-$(CONFIG_FB_PS3) += ps3fb.o - obj-$(CONFIG_FB_SM501) += sm501fb.o -+obj-$(CONFIG_FB_SM712) += sm712fb/ - obj-$(CONFIG_FB_UDL) += udlfb.o - obj-$(CONFIG_FB_SMSCUFX) += smscufx.o - obj-$(CONFIG_FB_XILINX) += xilinxfb.o -diff --git a/drivers/video/fbdev/sm712fb/Makefile b/drivers/video/fbdev/sm712fb/Makefile -new file mode 100644 -index 0000000..9bf3519 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_FB_SM712) += sm712fb.o -+ -+sm712fb-objs := sm712fb_drv.o sm712fb_accel.o -diff --git a/drivers/video/fbdev/sm712fb/TODO b/drivers/video/fbdev/sm712fb/TODO -new file mode 100644 -index 0000000..dcfd4e7 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/TODO -@@ -0,0 +1,7 @@ -+TODO: -+- Dual head support -+- refine the code, convert more registers magic numbers to macros -+- Does it really works on Big Endian machines? -+ -+Please send any patches to Greg Kroah-Hartman and -+Tom Li . -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.c b/drivers/video/fbdev/sm712fb/sm712fb_accel.c -new file mode 100644 -index 0000000..12fce1f ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.c -@@ -0,0 +1,246 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#include -+#include -+#include -+ -+#include "sm712fb_drv.h" -+#include "sm712fb_accel.h" -+ -+static inline u32 bytes_to_dword(const u8 *bytes, int length) -+{ -+ u32 dword = 0; -+ -+ switch (length) { -+ case 4: -+#ifdef __BIG_ENDIAN -+ dword += bytes[3]; -+#else -+ dword += bytes[3] << 24; -+#endif -+ case 3: -+#ifdef __BIG_ENDIAN -+ dword += bytes[2] << 8; -+#else -+ dword += bytes[2] << 16; -+#endif -+ case 2: -+#ifdef __BIG_ENDIAN -+ dword += bytes[1] << 16; -+#else -+ dword += bytes[1] << 8; -+#endif -+ case 1: -+#ifdef __BIG_ENDIAN -+ dword += bytes[0] << 24; -+#else -+ dword += bytes[0]; -+#endif -+ } -+ return dword; -+} -+ -+int sm712fb_init_accel(struct sm712fb_info *fb) -+{ -+ u8 reg; -+ -+ /* reset the 2D engine */ -+ sm712_write_seq(fb, 0x21, sm712_read_seq(fb, 0x21) & 0xf8); -+ reg = sm712_read_seq(fb, 0x15); -+ sm712_write_seq(fb, 0x15, reg | 0x30); -+ sm712_write_seq(fb, 0x15, reg); -+ -+ if (sm712fb_wait(fb) != 0) -+ return -1; -+ -+ sm712_write_dpr(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0)); -+ -+ /* same width for DPR_PITCH and DPR_SRC_WINDOW */ -+ sm712_write_dpr(fb, DPR_PITCH, -+ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); -+ sm712_write_dpr(fb, DPR_SRC_WINDOW, -+ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); -+ -+ sm712_write_dpr(fb, DPR_BYTE_BIT_MASK, 0xffffffff); -+ sm712_write_dpr(fb, DPR_COLOR_COMPARE_MASK, 0); -+ sm712_write_dpr(fb, DPR_COLOR_COMPARE, 0); -+ sm712_write_dpr(fb, DPR_SRC_BASE, 0); -+ sm712_write_dpr(fb, DPR_DST_BASE, 0); -+ sm712_read_dpr(fb, DPR_DST_BASE); -+ -+ return 0; -+} -+ -+int sm712fb_wait(struct sm712fb_info *fb) -+{ -+ int i; -+ u8 reg; -+ -+ for (i = 0; i < 10000; i++) { -+ reg = sm712_read_seq(fb, SCR_DE_STATUS); -+ if ((reg & SCR_DE_STATUS_MASK) == SCR_DE_ENGINE_IDLE) -+ return 0; -+ udelay(1); -+ } -+ return -EBUSY; -+} -+ -+void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -+{ -+ u32 width = rect->width, height = rect->height; -+ u32 dx = rect->dx, dy = rect->dy; -+ u32 color; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((rect->dx >= info->var.xres_virtual) || -+ (rect->dy >= info->var.yres_virtual)) -+ return; -+ -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) -+ color = ((u32 *) (info->pseudo_palette))[rect->color]; -+ else -+ color = rect->color; -+ -+ sm712_write_dpr(sfb, DPR_FG_COLOR, color); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | -+ (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -+ -+void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) -+{ -+ u32 sx = area->sx, sy = area->sy; -+ u32 dx = area->dx, dy = area->dy; -+ u32 height = area->height, width = area->width; -+ u32 direction; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((sx >= info->var.xres_virtual) || (sy >= info->var.yres_virtual)) -+ return; -+ -+ if (sy < dy || (sy == dy && sx <= dx)) { -+ sx += width - 1; -+ dx += width - 1; -+ sy += height - 1; -+ dy += height - 1; -+ direction = DE_CTRL_RTOL; -+ } else -+ direction = 0; -+ -+ sm712_write_dpr(sfb, DPR_SRC_COORDS, DPR_COORDS(sx, sy)); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_DE_CTRL, -+ DE_CTRL_START | DE_CTRL_ROP_ENABLE | direction | -+ (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -+ -+void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image) -+{ -+ u32 dx = image->dx, dy = image->dy; -+ u32 width = image->width, height = image->height; -+ u32 fg_color, bg_color; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ u32 imgidx = 0; -+ u32 line = image->width >> 3; -+ -+ int i, j; -+ u32 total_bytes, total_dwords, remain_bytes; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((image->dx >= info->var.xres_virtual) || -+ (image->dy >= info->var.yres_virtual)) -+ return; -+ -+ if (unlikely(image->depth != 1)) { -+ /* unsupported depth, fallback to draw Tux */ -+ cfb_imageblit(info, image); -+ return; -+ } -+ -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) { -+ fg_color = ((u32 *) (info->pseudo_palette))[image->fg_color]; -+ bg_color = ((u32 *) (info->pseudo_palette))[image->bg_color]; -+ } else { -+ fg_color = image->fg_color; -+ bg_color = image->bg_color; -+ } -+ -+ /* total bytes we need to write */ -+ total_bytes = (width + 7) / 8; -+ -+ /* split the bytes into dwords and remainder bytes */ -+ total_dwords = (total_bytes & ~3) / 4; -+ remain_bytes = total_bytes & 3; -+ -+ sm712_write_dpr(sfb, DPR_SRC_COORDS, 0); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_FG_COLOR, fg_color); -+ sm712_write_dpr(sfb, DPR_BG_COLOR, bg_color); -+ -+ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | -+ (DE_CTRL_COMMAND_HOST_WRITE << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_HOST_MONO << DE_CTRL_HOST_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ -+ for (i = 0; i < height; i++) { -+ /* cast bytes data into dwords and write to the dataport */ -+ for (j = 0; j < total_dwords; j++) { -+ sm712_write_dataport(sfb, -+ bytes_to_dword(&image-> -+ data[imgidx] + -+ j * 4, 4)); -+ } -+ -+ if (remain_bytes) { -+ sm712_write_dataport(sfb, -+ bytes_to_dword(&image-> -+ data[imgidx] + -+ (total_dwords * 4), -+ remain_bytes)); -+ } -+ imgidx += line; -+ } -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.h b/drivers/video/fbdev/sm712fb/sm712fb_accel.h -new file mode 100644 -index 0000000..6f79177 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.h -@@ -0,0 +1,33 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#ifndef _SM712FB_ACCEL_H -+#define _SM712FB_ACCEL_H -+ -+int sm712fb_init_accel(struct sm712fb_info *fb); -+int sm712fb_wait(struct sm712fb_info *fb); -+void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -+void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area); -+void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image); -+ -+#endif -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.c b/drivers/video/fbdev/sm712fb/sm712fb_drv.c -new file mode 100644 -index 0000000..7f7cd4f ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.c -@@ -0,0 +1,1022 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_PM -+#include -+#endif -+ -+#include "sm712fb_drv.h" -+#include "sm712fb_accel.h" -+#include "sm712fb_modedb.h" -+ -+static struct fb_var_screeninfo sm712fb_var = { -+ .xres = 1024, -+ .yres = 600, -+ .xres_virtual = 1024, -+ .yres_virtual = 600, -+ .bits_per_pixel = 16, -+ .red = {16, 8, 0}, -+ .green = {8, 8, 0}, -+ .blue = {0, 8, 0}, -+ .activate = FB_ACTIVATE_NOW, -+ .height = -1, -+ .width = -1, -+ .vmode = FB_VMODE_NONINTERLACED, -+ .nonstd = 0, -+ .accel_flags = FB_ACCELF_TEXT, -+}; -+ -+static struct fb_fix_screeninfo sm712fb_fix = { -+ .id = "smXXXfb", -+ .type = FB_TYPE_PACKED_PIXELS, -+ .visual = FB_VISUAL_TRUECOLOR, -+ .line_length = 800 * 3, -+ .accel = FB_ACCEL_SMI_LYNX, -+ .type_aux = 0, -+ .xpanstep = 0, -+ .ypanstep = 0, -+ .ywrapstep = 0, -+}; -+ -+struct vesa_mode { -+ char index[6]; -+ u16 lfb_width; -+ u16 lfb_height; -+ u16 lfb_depth; -+}; -+ -+static bool accel = 1; -+ -+static struct vesa_mode vesa_mode_table[] = { -+ {"0x301", 640, 480, 8}, -+ {"0x303", 800, 600, 8}, -+ {"0x305", 1024, 768, 8}, -+ {"0x307", 1280, 1024, 8}, -+ -+ {"0x311", 640, 480, 16}, -+ {"0x314", 800, 600, 16}, -+ {"0x317", 1024, 768, 16}, -+ {"0x31A", 1280, 1024, 16}, -+ -+ {"0x312", 640, 480, 24}, -+ {"0x315", 800, 600, 24}, -+ {"0x318", 1024, 768, 24}, -+ {"0x31B", 1280, 1024, 24}, -+}; -+ -+struct screen_info sm712_scr_info; -+ -+static int sm712fb_setup(char *options) -+{ -+ char *this_opt; -+ -+ if (!options || !*options) -+ return 0; -+ -+ while ((this_opt = strsep(&options, ",")) != NULL) { -+ if (!*this_opt) -+ continue; -+ -+ if (!strcmp(this_opt, "accel:0")) -+ accel = false; -+ else if (!strcmp(this_opt, "accel:1")) -+ accel = true; -+ } -+ return 0; -+} -+ -+/* process command line options, get vga parameter */ -+static int __init sm712_vga_setup(char *options) -+{ -+ int i; -+ -+ if (!options || !*options) -+ return -EINVAL; -+ -+ sm712_scr_info.lfb_width = 0; -+ sm712_scr_info.lfb_height = 0; -+ sm712_scr_info.lfb_depth = 0; -+ -+ pr_debug("sm712_vga_setup = %s\n", options); -+ -+ for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { -+ if (strstr(options, vesa_mode_table[i].index)) { -+ sm712_scr_info.lfb_width = vesa_mode_table[i].lfb_width; -+ sm712_scr_info.lfb_height = -+ vesa_mode_table[i].lfb_height; -+ sm712_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; -+ return 0; -+ } -+ } -+ -+ return -1; -+} -+ -+__setup("vga=", sm712_vga_setup); -+ -+static void sm712_setpalette(int regno, unsigned red, unsigned green, -+ unsigned blue, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb = info->par; -+ -+ /* set bit 5:4 = 01 (write LCD RAM only) */ -+ sm712_write_seq(sfb, 0x66, (sm712_read_seq(sfb, 0x66) & 0xC3) | 0x10); -+ -+ sm712_writeb(sfb->mmio, DAC_REG, regno); -+ sm712_writeb(sfb->mmio, DAC_VAL, red >> 10); -+ sm712_writeb(sfb->mmio, DAC_VAL, green >> 10); -+ sm712_writeb(sfb->mmio, DAC_VAL, blue >> 10); -+} -+ -+/* chan_to_field -+ * -+ * convert a colour value into a field position -+ * -+ * from pxafb.c -+ */ -+ -+static inline unsigned int chan_to_field(unsigned int chan, -+ struct fb_bitfield *bf) -+{ -+ chan &= 0xffff; -+ chan >>= 16 - bf->length; -+ return chan << bf->offset; -+} -+ -+static int sm712_blank(int blank_mode, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb = info->par; -+ -+ /* clear DPMS setting */ -+ switch (blank_mode) { -+ case FB_BLANK_UNBLANK: -+ /* Screen On: HSync: On, VSync : On */ -+ sm712_write_seq(sfb, 0x01, -+ (sm712_read_seq(sfb, 0x01) & (~0x20))); -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) & 0x77)); -+ sm712_write_seq(sfb, 0x22, -+ (sm712_read_seq(sfb, 0x22) & (~0x30))); -+ sm712_write_seq(sfb, 0x23, -+ (sm712_read_seq(sfb, 0x23) & (~0xc0))); -+ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); -+ sm712_write_seq(sfb, 0x31, (sm712_read_seq(sfb, 0x31) | 0x03)); -+ break; -+ case FB_BLANK_NORMAL: -+ /* Screen Off: HSync: On, VSync : On Soft blank */ -+ sm712_write_seq(sfb, 0x01, -+ (sm712_read_seq(sfb, 0x01) & (~0x20))); -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x22, -+ (sm712_read_seq(sfb, 0x22) & (~0x30))); -+ sm712_write_seq(sfb, 0x23, -+ (sm712_read_seq(sfb, 0x23) & (~0xc0))); -+ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ break; -+ case FB_BLANK_VSYNC_SUSPEND: -+ /* Screen On: HSync: On, VSync : Off */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x0c); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x20)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0x20)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ case FB_BLANK_HSYNC_SUSPEND: -+ /* Screen On: HSync: Off, VSync : On */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x0c); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x10)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ case FB_BLANK_POWERDOWN: -+ /* Screen On: HSync: Off, VSync : Off */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x5a); -+ sm712_write_seq(sfb, 0x6b, 0x20); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x30)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int sm712_setcolreg(unsigned regno, unsigned red, unsigned green, -+ unsigned blue, unsigned trans, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb; -+ u32 val; -+ -+ sfb = info->par; -+ -+ if (regno > 255) -+ return 1; -+ -+ switch (sfb->fb.fix.visual) { -+ case FB_VISUAL_DIRECTCOLOR: -+ case FB_VISUAL_TRUECOLOR: -+ /* -+ * 16/32 bit true-colour, use pseudo-palette for 16 base color -+ */ -+ if (regno < 16) { -+ if (sfb->fb.var.bits_per_pixel == 16) { -+ u32 *pal = sfb->fb.pseudo_palette; -+ -+ val = chan_to_field(red, &sfb->fb.var.red); -+ val |= chan_to_field(green, &sfb->fb.var.green); -+ val |= chan_to_field(blue, &sfb->fb.var.blue); -+#ifdef __BIG_ENDIAN -+ pal[regno] = -+ ((red & 0xf800) >> 8) | -+ ((green & 0xe000) >> 13) | -+ ((green & 0x1c00) << 3) | -+ ((blue & 0xf800) >> 3); -+#else -+ pal[regno] = val; -+#endif -+ } else { -+ u32 *pal = sfb->fb.pseudo_palette; -+ -+ val = chan_to_field(red, &sfb->fb.var.red); -+ val |= chan_to_field(green, &sfb->fb.var.green); -+ val |= chan_to_field(blue, &sfb->fb.var.blue); -+#ifdef __BIG_ENDIAN -+ val = -+ (val & 0xff00ff00 >> 8) | -+ (val & 0x00ff00ff << 8); -+#endif -+ pal[regno] = val; -+ } -+ } -+ break; -+ -+ case FB_VISUAL_PSEUDOCOLOR: -+ /* color depth 8 bit */ -+ sm712_setpalette(regno, red, green, blue, info); -+ break; -+ -+ default: -+ return 1; /* unknown type */ -+ } -+ -+ return 0; -+ -+} -+ -+#ifdef __BIG_ENDIAN -+static ssize_t sm712fb_read(struct fb_info *info, char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ unsigned long p = *ppos; -+ -+ u32 *buffer, *dst; -+ u32 __iomem *src; -+ int c, i, cnt = 0, err = 0; -+ unsigned long total_size; -+ -+ if (!info || !info->screen_base) -+ return -ENODEV; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return -EPERM; -+ -+ total_size = info->screen_size; -+ -+ if (total_size == 0) -+ total_size = info->fix.smem_len; -+ -+ if (p >= total_size) -+ return 0; -+ -+ if (count >= total_size) -+ count = total_size; -+ -+ if (count + p > total_size) -+ count = total_size - p; -+ -+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ src = (u32 __iomem *) (info->screen_base + p); -+ -+ if (info->fbops->fb_sync) -+ info->fbops->fb_sync(info); -+ -+ while (count) { -+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; -+ dst = buffer; -+ for (i = c >> 2; i--;) { -+ *dst = fb_readl(src++); -+ *dst = -+ (*dst & 0xff00ff00 >> 8) | (*dst & 0x00ff00ff << 8); -+ dst++; -+ } -+ if (c & 3) { -+ u8 *dst8 = (u8 *) dst; -+ u8 __iomem *src8 = (u8 __iomem *) src; -+ -+ for (i = c & 3; i--;) { -+ if (i & 1) { -+ *dst8++ = fb_readb(++src8); -+ } else { -+ *dst8++ = fb_readb(--src8); -+ src8 += 2; -+ } -+ } -+ src = (u32 __iomem *) src8; -+ } -+ -+ if (copy_to_user(buf, buffer, c)) { -+ err = -EFAULT; -+ break; -+ } -+ *ppos += c; -+ buf += c; -+ cnt += c; -+ count -= c; -+ } -+ -+ kfree(buffer); -+ -+ return (err) ? err : cnt; -+} -+ -+static ssize_t -+sm712fb_write(struct fb_info *info, const char __user *buf, size_t count, -+ loff_t *ppos) -+{ -+ unsigned long p = *ppos; -+ -+ u32 *buffer, *src; -+ u32 __iomem *dst; -+ int c, i, cnt = 0, err = 0; -+ unsigned long total_size; -+ -+ if (!info || !info->screen_base) -+ return -ENODEV; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return -EPERM; -+ -+ total_size = info->screen_size; -+ -+ if (total_size == 0) -+ total_size = info->fix.smem_len; -+ -+ if (p > total_size) -+ return -EFBIG; -+ -+ if (count > total_size) { -+ err = -EFBIG; -+ count = total_size; -+ } -+ -+ if (count + p > total_size) { -+ if (!err) -+ err = -ENOSPC; -+ -+ count = total_size - p; -+ } -+ -+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ dst = (u32 __iomem *) (info->screen_base + p); -+ -+ if (info->fbops->fb_sync) -+ info->fbops->fb_sync(info); -+ -+ while (count) { -+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; -+ src = buffer; -+ -+ if (copy_from_user(src, buf, c)) { -+ err = -EFAULT; -+ break; -+ } -+ -+ for (i = c >> 2; i--;) { -+ fb_writel((*src & 0xff00ff00 >> 8) | -+ (*src & 0x00ff00ff << 8), dst++); -+ src++; -+ } -+ if (c & 3) { -+ u8 *src8 = (u8 *) src; -+ u8 __iomem *dst8 = (u8 __iomem *) dst; -+ -+ for (i = c & 3; i--;) { -+ if (i & 1) { -+ fb_writeb(*src8++, ++dst8); -+ } else { -+ fb_writeb(*src8++, --dst8); -+ dst8 += 2; -+ } -+ } -+ dst = (u32 __iomem *) dst8; -+ } -+ -+ *ppos += c; -+ buf += c; -+ cnt += c; -+ count -= c; -+ } -+ -+ kfree(buffer); -+ -+ return (cnt) ? cnt : err; -+} -+#endif /* ! __BIG_ENDIAN */ -+ -+static void sm712_set_timing(struct sm712fb_info *sfb) -+{ -+ int i = 0, j = 0; -+ u32 m_nScreenStride; -+ -+ dev_dbg(&sfb->pdev->dev, -+ "sfb->width=%d sfb->height=%d " -+ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n", -+ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz); -+ -+ for (j = 0; j < numVGAModes; j++) { -+ if (VGAMode[j].mmSizeX != sfb->width || -+ VGAMode[j].mmSizeY != sfb->height || -+ VGAMode[j].bpp != sfb->fb.var.bits_per_pixel || -+ VGAMode[j].hz != sfb->hz) { -+ continue; -+ } -+ -+ dev_dbg(&sfb->pdev->dev, -+ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d " -+ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n", -+ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, -+ VGAMode[j].bpp, VGAMode[j].hz); -+ -+ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j); -+ -+ sm712_writeb(sfb->mmio, 0x3c6, 0x0); -+ -+ sm712_write_seq(sfb, 0, 0x1); -+ -+ sm712_writeb(sfb->mmio, 0x3c2, VGAMode[j].Init_MISC); -+ -+ /* init SEQ register SR00 - SR04 */ -+ for (i = 0; i < SR00_SR04_SIZE; i++) -+ sm712_write_seq(sfb, i, VGAMode[j].Init_SR00_SR04[i]); -+ -+ /* init SEQ register SR10 - SR24 */ -+ for (i = 0; i < SR10_SR24_SIZE; i++) -+ sm712_write_seq(sfb, i + 0x10, -+ VGAMode[j].Init_SR10_SR24[i]); -+ -+ /* init SEQ register SR30 - SR75 */ -+ for (i = 0; i < SR30_SR75_SIZE; i++) -+ if ((i + 0x30) != 0x62 && -+ (i + 0x30) != 0x6a && (i + 0x30) != 0x6b) -+ sm712_write_seq(sfb, i + 0x30, -+ VGAMode[j].Init_SR30_SR75[i]); -+ -+ /* init SEQ register SR80 - SR93 */ -+ for (i = 0; i < SR80_SR93_SIZE; i++) -+ sm712_write_seq(sfb, i + 0x80, -+ VGAMode[j].Init_SR80_SR93[i]); -+ -+ /* init SEQ register SRA0 - SRAF */ -+ for (i = 0; i < SRA0_SRAF_SIZE; i++) -+ sm712_write_seq(sfb, i + 0xa0, -+ VGAMode[j].Init_SRA0_SRAF[i]); -+ -+ /* init Graphic register GR00 - GR08 */ -+ for (i = 0; i < GR00_GR08_SIZE; i++) -+ sm712_write_grph(sfb, i, VGAMode[j].Init_GR00_GR08[i]); -+ -+ /* init Attribute register AR00 - AR14 */ -+ for (i = 0; i < AR00_AR14_SIZE; i++) -+ sm712_write_attr(sfb, i, VGAMode[j].Init_AR00_AR14[i]); -+ -+ /* init CRTC register CR00 - CR18 */ -+ for (i = 0; i < CR00_CR18_SIZE; i++) -+ sm712_write_crtc(sfb, i, VGAMode[j].Init_CR00_CR18[i]); -+ -+ /* init CRTC register CR30 - CR4D */ -+ for (i = 0; i < CR30_CR4D_SIZE; i++) -+ sm712_write_crtc(sfb, i + 0x30, -+ VGAMode[j].Init_CR30_CR4D[i]); -+ -+ /* init CRTC register CR90 - CRA7 */ -+ for (i = 0; i < CR90_CRA7_SIZE; i++) -+ sm712_write_crtc(sfb, i + 0x90, -+ VGAMode[j].Init_CR90_CRA7[i]); -+ } -+ sm712_writeb(sfb->mmio, 0x3c2, 0x67); -+ -+ /* set VPR registers */ -+ sm712_writel(sfb->vpr, 0x0C, 0x0); -+ sm712_writel(sfb->vpr, 0x40, 0x0); -+ -+ /* set data width */ -+ m_nScreenStride = (sfb->width * sfb->fb.var.bits_per_pixel) / 64; -+ switch (sfb->fb.var.bits_per_pixel) { -+ case 8: -+ sm712_writel(sfb->vpr, 0x0, 0x0); -+ break; -+ case 16: -+ sm712_writel(sfb->vpr, 0x0, 0x00020000); -+ break; -+ case 24: -+ sm712_writel(sfb->vpr, 0x0, 0x00040000); -+ break; -+ case 32: -+ sm712_writel(sfb->vpr, 0x0, 0x00030000); -+ break; -+ } -+ sm712_writel(sfb->vpr, 0x10, -+ (u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride)); -+} -+ -+static void sm712fb_setmode(struct sm712fb_info *sfb) -+{ -+ switch (sfb->fb.var.bits_per_pixel) { -+ case 32: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 4; -+ sfb->fb.var.red.length = 8; -+ sfb->fb.var.green.length = 8; -+ sfb->fb.var.blue.length = 8; -+ sfb->fb.var.red.offset = 16; -+ sfb->fb.var.green.offset = 8; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 24: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 3; -+ sfb->fb.var.red.length = 8; -+ sfb->fb.var.green.length = 8; -+ sfb->fb.var.blue.length = 8; -+ sfb->fb.var.red.offset = 16; -+ sfb->fb.var.green.offset = 8; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 8: -+ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres; -+ sfb->fb.var.red.length = 3; -+ sfb->fb.var.green.length = 3; -+ sfb->fb.var.blue.length = 2; -+ sfb->fb.var.red.offset = 5; -+ sfb->fb.var.green.offset = 2; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 16: -+ default: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 2; -+ sfb->fb.var.red.length = 5; -+ sfb->fb.var.green.length = 6; -+ sfb->fb.var.blue.length = 5; -+ sfb->fb.var.red.offset = 11; -+ sfb->fb.var.green.offset = 5; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ } -+ -+ sfb->width = sfb->fb.var.xres; -+ sfb->height = sfb->fb.var.yres; -+ sfb->hz = 60; -+ sm712_set_timing(sfb); -+} -+ -+static int sm712_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ /* sanity checks */ -+ if (var->xres_virtual < var->xres) -+ var->xres_virtual = var->xres; -+ -+ if (var->yres_virtual < var->yres) -+ var->yres_virtual = var->yres; -+ -+ /* set valid default bpp */ -+ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && -+ (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) -+ var->bits_per_pixel = 16; -+ -+ return 0; -+} -+ -+static int sm712_set_par(struct fb_info *info) -+{ -+ sm712fb_setmode(info->par); -+ -+ return 0; -+} -+ -+static struct fb_ops sm712fb_ops = { -+ .owner = THIS_MODULE, -+ .fb_check_var = sm712_check_var, -+ .fb_set_par = sm712_set_par, -+ .fb_setcolreg = sm712_setcolreg, -+ .fb_blank = sm712_blank, -+ .fb_fillrect = cfb_fillrect, -+ .fb_imageblit = cfb_imageblit, -+ .fb_copyarea = cfb_copyarea, -+#ifdef __BIG_ENDIAN -+ .fb_read = sm712fb_read, -+ .fb_write = sm712fb_write, -+#endif -+}; -+ -+/* -+ * alloc struct sm712fb_info and assign default values -+ */ -+static struct sm712fb_info *sm712_fb_info_new(struct pci_dev *pdev) -+{ -+ struct sm712fb_info *sfb; -+ -+ sfb = kzalloc(sizeof(*sfb), GFP_KERNEL); -+ -+ if (!sfb) -+ return NULL; -+ -+ sfb->pdev = pdev; -+ -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT; -+ sfb->fb.fbops = &sm712fb_ops; -+ sfb->fb.fix = sm712fb_fix; -+ sfb->fb.var = sm712fb_var; -+ sfb->fb.pseudo_palette = sfb->colreg; -+ sfb->fb.par = sfb; -+ sfb->accel = accel; -+ -+ return sfb; -+} -+ -+/* -+ * free struct sm712fb_info -+ */ -+static void sm712_fb_info_free(struct sm712fb_info *sfb) -+{ -+ kfree(sfb); -+} -+ -+/* -+ * Map in the screen memory -+ */ -+ -+static int sm712_map_smem(struct sm712fb_info *sfb, -+ struct pci_dev *pdev, u_long smem_len) -+{ -+ -+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); -+ -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 32) -+ sfb->fb.fix.smem_start += 0x800000; -+#endif -+ -+ sfb->fb.fix.smem_len = smem_len; -+ -+ sfb->fb.screen_base = sfb->lfb; -+ -+ if (!sfb->fb.screen_base) { -+ dev_err(&pdev->dev, -+ "%s: unable to map screen memory\n", sfb->fb.fix.id); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Unmap in the screen memory -+ * -+ */ -+static void sm712_unmap_smem(struct sm712fb_info *sfb) -+{ -+ if (sfb && sfb->fb.screen_base) { -+ iounmap(sfb->fb.screen_base); -+ sfb->fb.screen_base = NULL; -+ sfb->lfb = NULL; -+ } -+} -+ -+static inline void sm712_init_hw(struct sm712fb_info *sfb) -+{ -+ /* enable linear memory mode and packed pixel format */ -+ outb_p(0x18, 0x3c4); -+ outb_p(0x11, 0x3c5); -+ -+ /* set MCLK = 14.31818 * (0x16 / 0x2) */ -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x62, 0x3e); -+ -+ /* enable PCI burst */ -+ sm712_write_seq(sfb, 0x17, 0x20); -+ -+#ifdef __BIG_ENDIAN -+ /* enable word swap */ -+ if (sfb->fb.var.bits_per_pixel == 32) -+ sm712_write_seq(sfb, 0x17, 0x30); -+#endif -+ -+ if (!sfb->accel) { -+ dev_info(&sfb->pdev->dev, "2d acceleration was disabled by user.\n"); -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; -+ return; -+ } -+ -+ if (sm712fb_init_accel(sfb) < 0) { -+ dev_info(&sfb->pdev->dev, "failed to enable 2d accleration.\n"); -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; -+ return; -+ } else { -+ sm712fb_ops.fb_fillrect = sm712fb_fillrect; -+ sm712fb_ops.fb_copyarea = sm712fb_copyarea; -+ sm712fb_ops.fb_imageblit = sm712fb_imageblit; -+ sfb->fb.flags |= FBINFO_HWACCEL_COPYAREA | -+ FBINFO_HWACCEL_FILLRECT | -+ FBINFO_HWACCEL_IMAGEBLIT | -+ FBINFO_READS_FAST; -+ dev_info(&sfb->pdev->dev, "sm712fb: enable 2d acceleration.\n"); -+ } -+} -+ -+static int sm712fb_pci_probe(struct pci_dev *pdev, -+ const struct pci_device_id *ent) -+{ -+ struct sm712fb_info *sfb; -+ int err; -+ unsigned long mmio_base; -+ -+#ifndef MODULE -+ char *option = NULL; -+ -+ if (!fb_get_options("sm712fb", &option)) -+ sm712fb_setup(option); -+#endif -+ -+ dev_info(&pdev->dev, "Silicon Motion display driver."); -+ -+ err = pci_enable_device(pdev); /* enable SMTC chip */ -+ if (err) -+ return err; -+ -+ sprintf(sm712fb_fix.id, "sm712fb"); -+ -+ sfb = sm712_fb_info_new(pdev); -+ -+ if (!sfb) { -+ err = -ENOMEM; -+ goto free_fail; -+ } -+ -+ sfb->chip_id = ent->device; -+ -+ pci_set_drvdata(pdev, sfb); -+ -+ /* get mode parameter from sm712_scr_info */ -+ if (sm712_scr_info.lfb_width != 0) { -+ sfb->fb.var.xres = sm712_scr_info.lfb_width; -+ sfb->fb.var.yres = sm712_scr_info.lfb_height; -+ sfb->fb.var.bits_per_pixel = sm712_scr_info.lfb_depth; -+ } else { -+ /* default resolution 1024x600 16bit mode */ -+ sfb->fb.var.xres = SM712_DEFAULT_XRES; -+ sfb->fb.var.yres = SM712_DEFAULT_YRES; -+ sfb->fb.var.bits_per_pixel = SM712_DEFAULT_BPP; -+ } -+ -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 24) -+ sfb->fb.var.bits_per_pixel = (sm712_scr_info.lfb_depth = 32); -+#endif -+ -+ /* Map address and memory detection */ -+ mmio_base = pci_resource_start(pdev, 0); -+ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); -+ -+ if (sfb->chip_id != 0x712) { -+ dev_err(&pdev->dev, -+ "No valid Silicon Motion display chip was detected!"); -+ -+ goto fb_fail; -+ } -+ -+ sfb->fb.fix.mmio_start = mmio_base + SM712_REG_BASE; -+ sfb->fb.fix.mmio_len = SM712_REG_SIZE; -+#ifdef __BIG_ENDIAN -+ sfb->lfb = ioremap(mmio_base, 0x00c00000); -+#else -+ sfb->lfb = ioremap(mmio_base, 0x00800000); -+#endif -+ sfb->mmio = sfb->lfb + SM712_MMIO_BASE; -+ sfb->dpr = sfb->lfb + SM712_DPR_BASE; -+ sfb->vpr = sfb->lfb + SM712_VPR_BASE; -+ sfb->dataport = sfb->lfb + SM712_DATAPORT_BASE; -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 32) { -+ sfb->lfb += 0x800000; -+ dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb); -+ } -+#endif -+ if (!sfb->mmio) { -+ dev_err(&pdev->dev, -+ "%s: unable to map memory mapped IO!", sfb->fb.fix.id); -+ err = -ENOMEM; -+ goto fb_fail; -+ } -+ -+ sm712_init_hw(sfb); -+ -+ /* can support 32 bpp */ -+ if (15 == sfb->fb.var.bits_per_pixel) -+ sfb->fb.var.bits_per_pixel = 16; -+ -+ sfb->fb.var.xres_virtual = sfb->fb.var.xres; -+ sfb->fb.var.yres_virtual = sfb->fb.var.yres; -+ err = sm712_map_smem(sfb, pdev, SM712_VRAM_SIZE); -+ if (err) -+ goto fail; -+ -+ sm712fb_setmode(sfb); -+ -+ err = register_framebuffer(&sfb->fb); -+ if (err < 0) -+ goto fail; -+ -+ dev_info(&pdev->dev, -+ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.", -+ sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres, -+ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); -+ -+ return 0; -+ -+fail: -+ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail."); -+ -+ sm712_unmap_smem(sfb); -+fb_fail: -+ sm712_fb_info_free(sfb); -+free_fail: -+ pci_disable_device(pdev); -+ -+ return err; -+} -+ -+/* -+ * 0x712 (LynxEM+) -+ */ -+static const struct pci_device_id sm712fb_pci_table[] = { -+ {PCI_DEVICE(0x126f, 0x712),}, -+ {0,} -+}; -+ -+static void sm712fb_pci_remove(struct pci_dev *pdev) -+{ -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ sm712_unmap_smem(sfb); -+ unregister_framebuffer(&sfb->fb); -+ sm712_fb_info_free(sfb); -+} -+ -+#ifdef CONFIG_PM -+static int sm712fb_pci_suspend(struct device *device) -+{ -+ struct pci_dev *pdev = to_pci_dev(device); -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ -+ /* set the hw in sleep mode use external clock and self memory refresh -+ * so that we can turn off internal PLLs later on -+ */ -+ sm712_write_seq(sfb, 0x20, (sm712_read_seq(sfb, 0x20) | 0xc0)); -+ sm712_write_seq(sfb, 0x69, (sm712_read_seq(sfb, 0x69) & 0xf7)); -+ -+ console_lock(); -+ fb_set_suspend(&sfb->fb, 1); -+ console_unlock(); -+ -+ /* additionally turn off all function blocks including internal PLLs */ -+ sm712_write_seq(sfb, 0x21, 0xff); -+ -+ return 0; -+} -+ -+static int sm712fb_pci_resume(struct device *device) -+{ -+ struct pci_dev *pdev = to_pci_dev(device); -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ -+ /* reinit hardware */ -+ sm712_init_hw(sfb); -+ -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0xc0)); -+ sm712_write_seq(sfb, 0x33, ((sm712_read_seq(sfb, 0x33) | 0x08) & 0xfb)); -+ -+ sm712fb_setmode(sfb); -+ -+ console_lock(); -+ fb_set_suspend(&sfb->fb, 0); -+ console_unlock(); -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(sm712_pm_ops, sm712fb_pci_suspend, sm712fb_pci_resume); -+#define SM712_PM_OPS (&sm712_pm_ops) -+ -+#else /* !CONFIG_PM */ -+ -+#define SM712_PM_OPS NULL -+ -+#endif /* !CONFIG_PM */ -+ -+static struct pci_driver sm712fb_driver = { -+ .name = "sm712fb", -+ .id_table = sm712fb_pci_table, -+ .probe = sm712fb_pci_probe, -+ .remove = sm712fb_pci_remove, -+ .driver.pm = SM712_PM_OPS, -+}; -+ -+module_pci_driver(sm712fb_driver); -+ -+module_param(accel, bool, S_IRUGO); -+MODULE_PARM_DESC(accel, "Enable or disable 2D Acceleration"); -+ -+MODULE_AUTHOR("Siliconmotion "); -+MODULE_DESCRIPTION("Framebuffer driver for Silicon Motion SM712 Graphic Cards"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.h b/drivers/video/fbdev/sm712fb/sm712fb_drv.h -new file mode 100644 -index 0000000..bf81bff ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.h -@@ -0,0 +1,130 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#ifndef _SM712FB_DRV_H -+#define _SM712FB_DRV_H -+ -+/* -+* Private structure -+*/ -+struct sm712fb_info { -+ struct pci_dev *pdev; -+ struct fb_info fb; -+ u16 chip_id; -+ u8 chip_rev_id; -+ -+ void __iomem *lfb; /* linear frame buffer, the base address */ -+ -+ void __iomem *dpr; /* drawing processor control regs */ -+ void __iomem *vpr; /* video processor control regs */ -+ void __iomem *cpr; /* capture processor control regs */ -+ void __iomem *mmio; /* memory map IO port */ -+ void __iomem *dataport; /* 2d drawing engine data port */ -+ -+ u_int width; -+ u_int height; -+ u_int hz; -+ -+ u32 colreg[17]; -+ -+ bool accel; -+}; -+ -+/* constants for registers operations */ -+ -+#include "sm712fb_io.h" -+ -+#define FB_ACCEL_SMI_LYNX 88 -+ -+#define SM712_DEFAULT_XRES 1024 -+#define SM712_DEFAULT_YRES 600 -+#define SM712_DEFAULT_BPP 16 -+ -+#define SM712_VRAM_SIZE 0x00400000 -+ -+#define SM712_REG_BASE 0x00400000 -+#define SM712_REG_SIZE 0x00400000 -+ -+#define SM712_MMIO_BASE 0x00700000 -+ -+#define SM712_DPR_BASE 0x00408000 -+#define SM712_DPR_SIZE (0x6C + 1) -+ -+#define DPR_COORDS(x, y) (((x) << 16) | (y)) -+ -+#define DPR_SRC_COORDS 0x00 -+#define DPR_DST_COORDS 0x04 -+#define DPR_SPAN_COORDS 0x08 -+#define DPR_DE_CTRL 0x0c -+#define DPR_PITCH 0x10 -+#define DPR_FG_COLOR 0x14 -+#define DPR_BG_COLOR 0x18 -+#define DPR_STRETCH 0x1c -+#define DPR_COLOR_COMPARE 0x20 -+#define DPR_COLOR_COMPARE_MASK 0x24 -+#define DPR_BYTE_BIT_MASK 0x28 -+#define DPR_CROP_TOPLEFT_COORDS 0x2c -+#define DPR_CROP_BOTRIGHT_COORDS 0x30 -+#define DPR_SRC_WINDOW 0x3c -+#define DPR_SRC_BASE 0x40 -+#define DPR_DST_BASE 0x44 -+ -+#define DE_CTRL_START 0x80000000 -+#define DE_CTRL_RTOL 0x08000000 -+#define DE_CTRL_COMMAND_MASK 0x001f0000 -+#define DE_CTRL_COMMAND_SHIFT 16 -+#define DE_CTRL_COMMAND_BITBLT 0x00 -+#define DE_CTRL_COMMAND_SOLIDFILL 0x01 -+#define DE_CTRL_COMMAND_HOST_WRITE 0x08 -+#define DE_CTRL_ROP_ENABLE 0x00008000 -+#define DE_CTRL_ROP_MASK 0x000000ff -+#define DE_CTRL_ROP_SHIFT 0 -+#define DE_CTRL_ROP_SRC 0x0c -+ -+#define DE_CTRL_HOST_SHIFT 22 -+#define DE_CTRL_HOST_MONO 1 -+ -+#define SCR_DE_STATUS 0x16 -+#define SCR_DE_STATUS_MASK 0x18 -+#define SCR_DE_ENGINE_IDLE 0x10 -+ -+#define SM712_VPR_BASE 0x0040c000 -+#define SM712_VPR_SIZE (0x44 + 1) -+ -+#define SM712_DATAPORT_BASE 0x00400000 -+ -+#define SR00_SR04_SIZE (0x04 - 0x00 + 1) -+#define SR10_SR24_SIZE (0x24 - 0x10 + 1) -+#define SR30_SR75_SIZE (0x75 - 0x30 + 1) -+#define SR80_SR93_SIZE (0x93 - 0x80 + 1) -+#define SRA0_SRAF_SIZE (0xAF - 0xA0 + 1) -+#define GR00_GR08_SIZE (0x08 - 0x00 + 1) -+#define AR00_AR14_SIZE (0x14 - 0x00 + 1) -+#define CR00_CR18_SIZE (0x18 - 0x00 + 1) -+#define CR30_CR4D_SIZE (0x4D - 0x30 + 1) -+#define CR90_CRA7_SIZE (0xA7 - 0x90 + 1) -+ -+#define DAC_REG (0x3c8) -+#define DAC_VAL (0x3c9) -+ -+#endif -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_io.h b/drivers/video/fbdev/sm712fb/sm712fb_io.h -new file mode 100644 -index 0000000..93346a0 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_io.h -@@ -0,0 +1,90 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ */ -+ -+ -+#define sm712_writeb(base, reg, dat) writeb(dat, base + reg) -+#define sm712_writew(base, reg, dat) writew(dat, base + reg) -+#define sm712_writel(base, reg, dat) writel(dat, base + reg) -+ -+#define sm712_readb(base, reg) readb(base + reg) -+#define sm712_readw(base, reg) readw(base + reg) -+#define sm712_readl(base, reg) readl(base + reg) -+ -+ -+static inline void sm712_write_crtc(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3d4, reg); -+ sm712_writeb(fb->mmio, 0x3d5, val); -+} -+ -+static inline u8 sm712_read_crtc(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3d4, reg); -+ return sm712_readb(fb->mmio, 0x3d5); -+} -+ -+static inline void sm712_write_grph(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3ce, reg); -+ sm712_writeb(fb->mmio, 0x3cf, val); -+} -+ -+static inline u8 sm712_read_grph(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3ce, reg); -+ return sm712_readb(fb->mmio, 0x3cf); -+} -+ -+static inline void sm712_write_attr(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_readb(fb->mmio, 0x3da); -+ sm712_writeb(fb->mmio, 0x3c0, reg); -+ sm712_readb(fb->mmio, 0x3c1); -+ sm712_writeb(fb->mmio, 0x3c0, val); -+} -+ -+static inline void sm712_write_seq(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3c4, reg); -+ sm712_writeb(fb->mmio, 0x3c5, val); -+} -+ -+static inline u8 sm712_read_seq(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3c4, reg); -+ return sm712_readb(fb->mmio, 0x3c5); -+} -+ -+static inline u32 sm712_read_dpr(struct sm712fb_info *fb, u8 reg) -+{ -+ return sm712_readl(fb->dpr, reg); -+} -+ -+static inline void sm712_write_dpr(struct sm712fb_info *fb, u8 reg, u32 val) -+{ -+ sm712_writel(fb->dpr, reg, val); -+} -+ -+static inline void sm712_write_dataport(struct sm712fb_info *fb, u32 val) -+{ -+ sm712_writel(fb->dataport, 0, val); -+} -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_modedb.h b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h -new file mode 100644 -index 0000000..16ee7e3 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h -@@ -0,0 +1,682 @@ -+/* The next structure holds all information relevant for a specific video mode. -+ */ -+ -+struct ModeInit { -+ int mmSizeX; -+ int mmSizeY; -+ int bpp; -+ int hz; -+ unsigned char Init_MISC; -+ unsigned char Init_SR00_SR04[SR00_SR04_SIZE]; -+ unsigned char Init_SR10_SR24[SR10_SR24_SIZE]; -+ unsigned char Init_SR30_SR75[SR30_SR75_SIZE]; -+ unsigned char Init_SR80_SR93[SR80_SR93_SIZE]; -+ unsigned char Init_SRA0_SRAF[SRA0_SRAF_SIZE]; -+ unsigned char Init_GR00_GR08[GR00_GR08_SIZE]; -+ unsigned char Init_AR00_AR14[AR00_AR14_SIZE]; -+ unsigned char Init_CR00_CR18[CR00_CR18_SIZE]; -+ unsigned char Init_CR30_CR4D[CR30_CR4D_SIZE]; -+ unsigned char Init_CR90_CRA7[CR90_CRA7_SIZE]; -+}; -+ -+/********************************************************************** -+ SM712 Mode table. -+ **********************************************************************/ -+struct ModeInit VGAMode[] = { -+ { -+ /* mode#0: 640 x 480 16Bpp 60Hz */ -+ 640, 480, 16, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ { -+ /* mode#1: 640 x 480 24Bpp 60Hz */ -+ 640, 480, 24, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ { -+ /* mode#0: 640 x 480 32Bpp 60Hz */ -+ 640, 480, 32, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ -+ { /* mode#2: 800 x 600 16Bpp 60Hz */ -+ 800, 600, 16, 60, -+ /* Init_MISC */ -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, -+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, -+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ { /* mode#3: 800 x 600 24Bpp 60Hz */ -+ 800, 600, 24, 60, -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, -+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ { /* mode#7: 800 x 600 32Bpp 60Hz */ -+ 800, 600, 32, 60, -+ /* Init_MISC */ -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, -+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, -+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ /* We use 1024x768 table to light 1024x600 panel for lemote */ -+ { /* mode#4: 1024 x 600 16Bpp 60Hz */ -+ 1024, 600, 16, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, -+ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x00, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, -+ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, -+ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, -+ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#5: 1024 x 768 24Bpp 60Hz */ -+ 1024, 768, 24, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, -+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#4: 1024 x 768 32Bpp 60Hz */ -+ 1024, 768, 32, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, -+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#6: 320 x 240 16Bpp 60Hz */ -+ 320, 240, 16, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, -+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ -+ { /* mode#8: 320 x 240 32Bpp 60Hz */ -+ 320, 240, 32, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, -+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+}; -+ -+#define numVGAModes ARRAY_SIZE(VGAMode) -diff --git a/drivers/video/output.c b/drivers/video/output.c -new file mode 100644 -index 0000000..1446c49 ---- /dev/null -+++ b/drivers/video/output.c -@@ -0,0 +1,133 @@ -+/* -+ * output.c - Display Output Switch driver -+ * -+ * Copyright (C) 2006 Luming Yu -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+ -+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Luming Yu "); -+ -+static ssize_t state_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ ssize_t ret_size = 0; -+ struct output_device *od = to_output_device(dev); -+ if (od->props) -+ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); -+ return ret_size; -+} -+ -+static ssize_t state_store(struct device *dev, struct device_attribute *attr, -+ const char *buf,size_t count) -+{ -+ char *endp; -+ struct output_device *od = to_output_device(dev); -+ int request_state = simple_strtoul(buf,&endp,0); -+ size_t size = endp - buf; -+ -+ if (isspace(*endp)) -+ size++; -+ if (size != count) -+ return -EINVAL; -+ -+ if (od->props) { -+ od->request_state = request_state; -+ od->props->set_state(od); -+ } -+ return count; -+} -+static DEVICE_ATTR_RW(state); -+ -+static void video_output_release(struct device *dev) -+{ -+ struct output_device *od = to_output_device(dev); -+ kfree(od); -+} -+ -+static struct attribute *video_output_attrs[] = { -+ &dev_attr_state.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(video_output); -+ -+static struct class video_output_class = { -+ .name = "video_output", -+ .dev_release = video_output_release, -+ .dev_groups = video_output_groups, -+}; -+ -+struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op) -+{ -+ struct output_device *new_dev; -+ int ret_code = 0; -+ -+ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); -+ if (!new_dev) { -+ ret_code = -ENOMEM; -+ goto error_return; -+ } -+ new_dev->props = op; -+ new_dev->dev.class = &video_output_class; -+ new_dev->dev.parent = dev; -+ dev_set_name(&new_dev->dev, "%s", name); -+ dev_set_drvdata(&new_dev->dev, devdata); -+ ret_code = device_register(&new_dev->dev); -+ if (ret_code) { -+ kfree(new_dev); -+ goto error_return; -+ } -+ return new_dev; -+ -+error_return: -+ return ERR_PTR(ret_code); -+} -+EXPORT_SYMBOL(video_output_register); -+ -+void video_output_unregister(struct output_device *dev) -+{ -+ if (!dev) -+ return; -+ device_unregister(&dev->dev); -+} -+EXPORT_SYMBOL(video_output_unregister); -+ -+static void __exit video_output_class_exit(void) -+{ -+ class_unregister(&video_output_class); -+} -+ -+static int __init video_output_class_init(void) -+{ -+ return class_register(&video_output_class); -+} -+ -+postcore_initcall(video_output_class_init); -+module_exit(video_output_class_exit); -diff --git a/include/linux/sm501.h b/include/linux/sm501.h -index 02fde50..a8677f0 100644 ---- a/include/linux/sm501.h -+++ b/include/linux/sm501.h -@@ -27,6 +27,9 @@ extern unsigned long sm501_set_clock(struct device *dev, - extern unsigned long sm501_find_clock(struct device *dev, - int clksrc, unsigned long req_freq); - -+extern void sm501_configure_gpio(struct device *dev, -+ unsigned int gpio, unsigned char mode); -+ - /* sm501_misc_control - * - * Modify the SM501's MISC_CONTROL register -@@ -122,6 +125,7 @@ struct sm501_reg_init { - #define SM501_USE_AC97 (1<<7) - #define SM501_USE_I2S (1<<8) - #define SM501_USE_GPIO (1<<9) -+#define SM501_USE_PWM (1<<10) - - #define SM501_USE_ALL (0xffffffff) - -diff --git a/include/linux/video_output.h b/include/linux/video_output.h -new file mode 100644 -index 0000000..ed5cdeb ---- /dev/null -+++ b/include/linux/video_output.h -@@ -0,0 +1,57 @@ -+/* -+ * -+ * Copyright (C) 2006 Luming Yu -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ */ -+#ifndef _LINUX_VIDEO_OUTPUT_H -+#define _LINUX_VIDEO_OUTPUT_H -+#include -+#include -+struct output_device; -+struct output_properties { -+ int (*set_state)(struct output_device *); -+ int (*get_status)(struct output_device *); -+}; -+struct output_device { -+ int request_state; -+ struct output_properties *props; -+ struct device dev; -+}; -+#define to_output_device(obj) container_of(obj, struct output_device, dev) -+#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE) -+struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op); -+void video_output_unregister(struct output_device *dev); -+#else -+static struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op) -+{ -+ return ERR_PTR(-ENODEV); -+} -+static void video_output_unregister(struct output_device *dev) -+{ -+ return; -+} -+#endif -+#endif -diff --git a/init/calibrate.c b/init/calibrate.c -index ce635dc..10e775d 100644 ---- a/init/calibrate.c -+++ b/init/calibrate.c -@@ -21,6 +21,7 @@ static int __init lpj_setup(char *str) - - __setup("lpj=", lpj_setup); - -+#ifndef ARCH_HAS_PREPARED_LPJ - #ifdef ARCH_HAS_READ_CURRENT_TIMER - - /* This routine uses the read_current_timer() routine and gets the -@@ -171,6 +172,7 @@ static unsigned long calibrate_delay_direct(void) - return 0; - } - #endif -+#endif /* ARCH_HAS_PREPARED_LPJ */ - - /* - * This is the number of bits of precision for the loops_per_jiffy. Each -@@ -291,6 +293,7 @@ void calibrate_delay(void) - lpj = lpj_fine; - pr_info("Calibrating delay loop (skipped), " - "value calculated using timer frequency.. "); -+#ifndef ARCH_HAS_PREPARED_LPJ - } else if ((lpj = calibrate_delay_is_known())) { - ; - } else if ((lpj = calibrate_delay_direct()) != 0) { -@@ -301,6 +304,7 @@ void calibrate_delay(void) - if (!printed) - pr_info("Calibrating delay loop... "); - lpj = calibrate_delay_converge(); -+#endif /* ARCH_HAS_PREPARED_LPJ */ - } - per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj; - if (!printed) -diff --git a/net/rfkill/core.c b/net/rfkill/core.c -index fa7cd79..616abb5 100644 ---- a/net/rfkill/core.c -+++ b/net/rfkill/core.c -@@ -111,7 +111,7 @@ static LIST_HEAD(rfkill_list); /* list of registered rf switches */ - static DEFINE_MUTEX(rfkill_global_mutex); - static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ - --static unsigned int rfkill_default_state = 1; -+static unsigned int rfkill_default_state; /* default: 0 = radio off */ - module_param_named(default_state, rfkill_default_state, uint, 0444); - MODULE_PARM_DESC(default_state, - "Default initial state for all radio types, 0 = radio off"); -diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl -index 826470d..9e6dc30 100755 ---- a/scripts/recordmcount.pl -+++ b/scripts/recordmcount.pl -@@ -309,14 +309,33 @@ if ($arch eq "x86_64") { - $cc .= " -m64"; - $objcopy .= " -O elf64-sparc"; - } elsif ($arch eq "mips") { -- # To enable module support, we need to enable the -mlong-calls option -- # of gcc for module, after using this option, we can not get the real -- # offset of the calling to _mcount, but the offset of the lui -- # instruction or the addiu one. herein, we record the address of the -- # first one, and then we can replace this instruction by a branch -- # instruction to jump over the profiling function to filter the -- # indicated functions, or swith back to the lui instruction to trace -- # them, which means dynamic tracing. -+ # -+ # To disable tracing, just replace "jal _mcount" with nop; -+ # to enable tracing, replace back. so, the offset 14 is -+ # needed to be recorded. -+ # -+ # 10: 03e0082d move at,ra -+ # 14: 0c000000 jal 0 -+ # 14: R_MIPS_26 _mcount -+ # 14: R_MIPS_NONE *ABS* -+ # 14: R_MIPS_NONE *ABS* -+ # 18: 00020021 nop -+ # -+ # -+ # -+ # If no long call(-mlong-calls), the same to kernel. -+ # -+ # If the module space differs from the kernel space, long -+ # call is needed, as a result, the address of _mcount is -+ # needed to be recorded in a register and then jump from -+ # module space to kernel space via "jalr ". To -+ # disable tracing, "jalr " can be replaced by -+ # nop; to enable tracing, replace it back. Since the -+ # offset of "jalr " is not easy to be matched, -+ # the offset of the 1st _mcount below is recorded and to -+ # disable tracing, "lui v1, 0x0" is substituted with "b -+ # label", which jumps over "jalr "; to enable -+ # tracing, replace it back. - # - # c: 3c030000 lui v1,0x0 - # c: R_MIPS_HI16 _mcount -@@ -328,19 +347,12 @@ if ($arch eq "x86_64") { - # 10: R_MIPS_NONE *ABS* - # 14: 03e0082d move at,ra - # 18: 0060f809 jalr v1 -+ # label: - # -- # for the kernel: -- # -- # 10: 03e0082d move at,ra -- # 14: 0c000000 jal 0 -- # 14: R_MIPS_26 _mcount -- # 14: R_MIPS_NONE *ABS* -- # 14: R_MIPS_NONE *ABS* -- # 18: 00020021 nop - if ($is_module eq "0") { - $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$"; - } else { -- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$"; -+ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_(HI16|26)\\s+_mcount\$"; - } - $objdump .= " -Melf-trad".$endian."mips "; - -diff --git a/scripts/sstrip.sh b/scripts/sstrip.sh -new file mode 100755 -index 0000000..49b973a ---- /dev/null -+++ b/scripts/sstrip.sh -@@ -0,0 +1,59 @@ -+#!/bin/bash -+# sstrip.sh -- strip the section table of an elf file -+# -+# Copyright (C) 2010 Wu Zhangjin, wuzhangjin@gmail.com -+# Licensed under the GPLv2 -+# -+# Since the section table is useless for the embedded device, it can be -+# stripped out. -+# -+# Note: Some bootloader may check the section table but most of the time, it -+# may be not really used, If it really need the section table, it may need the -+# decompressed kernel image. -+ -+# Usage -+ -+function usage -+{ -+cat </dev/null` -+[ "xELF" != "x${FILE_TYPE}" ] && echo "$0: ${IMAGE} is not an ELF file" && exit -1 -+ -+[ "x${V}" == "x1" ] && orig_filesz=`wc -c ${IMAGE} | cut -d' ' -f1` -+ -+# Get the offset of the section table, here get the end of the program section -+filesz=$((`${OBJDUMP} -p ${IMAGE} | grep -m1 filesz | tr -s ' ' | cut -d' ' -f3`)) -+ -+# Truncate it via the dd tool -+dd if=/dev/null bs=1 of=${IMAGE} seek=${filesz} 2>/dev/null -+ -+# Clear the section table information in the ELF header -+# The last 6 bytes of the ELF header are the section table information -+echo -ne "\x00\x00\x00\x00\x00\x00" | dd of=${IMAGE} bs=1 seek=46 count=6 conv=notrunc 2>/dev/null -+ -+# Debug -+if [ "x${V}" == "x1" ]; then -+ echo "----------------------------------------------------------------" -+ echo "Strip the section table at ${filesz} of ${IMAGE}" -+ echo "----------------------------------------------------------------" -+ echo " sstrip: $0" -+ echo " objdump: ${OBJDUMP}" -+ echo "original size: ${orig_filesz}" -+ echo "current size: ${filesz}" -+ echo "reduced size: $((${orig_filesz} - ${filesz}))" -+fi diff --git a/kernels/linux-libre-grsec-knock/4.0.2-ae91f13af5-loongson-community.patch b/kernels/linux-libre-grsec-knock/4.0.2-ae91f13af5-loongson-community.patch new file mode 100644 index 000000000..affcd29d8 --- /dev/null +++ b/kernels/linux-libre-grsec-knock/4.0.2-ae91f13af5-loongson-community.patch @@ -0,0 +1,12144 @@ +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index c7a1690..0f854f0 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -333,7 +333,7 @@ config LASAT + + config MACH_LOONGSON + bool "Loongson family of machines" +- select SYS_SUPPORTS_ZBOOT ++ select SYS_SUPPORTS_ZBOOT_UART16550 + help + This enables the support of Loongson family of machines. + +@@ -1640,6 +1640,15 @@ config CPU_LOONGSON2 + bool + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_64BIT_KERNEL ++ select CPU_SUPPORTS_HIGHMEM if ! EMBEDDED ++ select ARCH_WANT_OPTIONAL_GPIOLIB ++ ++config CPU_LOONGSON1 ++ bool ++ select CPU_MIPS32 ++ select CPU_MIPSR2 ++ select CPU_HAS_PREFETCH ++ select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select CPU_SUPPORTS_HUGEPAGES + +@@ -2313,7 +2322,7 @@ config CPU_SUPPORTS_MSA + + config ARCH_FLATMEM_ENABLE + def_bool y +- depends on !NUMA && !CPU_LOONGSON2 ++ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION) + + config ARCH_DISCONTIGMEM_ENABLE + bool +diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile +index 61af6b6..8598044 100644 +--- a/arch/mips/boot/compressed/Makefile ++++ b/arch/mips/boot/compressed/Makefile +@@ -30,9 +30,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ + targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o + + # decompressor objects (linked with vmlinuz) +-vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o ++vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o + + ifdef CONFIG_DEBUG_ZBOOT ++vmlinuzobjs-y += $(obj)/dbg.o + vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o + vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o + endif +@@ -79,9 +80,18 @@ quiet_cmd_zld = LD $@ + cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ + quiet_cmd_strip = STRIP $@ + cmd_strip = $(STRIP) -s $@ ++ifdef CONFIG_EMBEDDED ++quiet_cmd_sstrip = SSTRIP $@ ++ cmd_sstrip = $(srctree)/scripts/sstrip.sh $@ ++endif + vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr + $(call cmd,zld) + $(call cmd,strip) ++ $(call cmd,sstrip) ++ ++vmlinuz.unsstrip: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr ++ $(call cmd,zld) ++ $(call cmd,strip) + + # + # Some DECstations need all possible sections of an ECOFF executable +@@ -94,14 +104,14 @@ endif + hostprogs-y += ../elf2ecoff + + ifdef CONFIG_32BIT +- VMLINUZ = vmlinuz ++ VMLINUZ = vmlinuz.unsstrip + else + VMLINUZ = vmlinuz.32 + endif + + quiet_cmd_32 = OBJCOPY $@ + cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ +-vmlinuz.32: vmlinuz ++vmlinuz.32: vmlinuz.unsstrip + $(call cmd,32) + + quiet_cmd_ecoff = ECOFF $@ +@@ -110,11 +120,11 @@ vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ) + $(call cmd,ecoff) + + OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary +-vmlinuz.bin: vmlinuz ++vmlinuz.bin: vmlinuz.unsstrip + $(call cmd,objcopy) + + OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec +-vmlinuz.srec: vmlinuz ++vmlinuz.srec: vmlinuz.unsstrip + $(call cmd,objcopy) + +-clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} ++clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec,unsstrip} +diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c +index 31903cf..14da73c 100644 +--- a/arch/mips/boot/compressed/decompress.c ++++ b/arch/mips/boot/compressed/decompress.c +@@ -28,8 +28,13 @@ unsigned long free_mem_end_ptr; + extern unsigned char __image_begin, __image_end; + + /* debug interfaces */ ++#ifdef CONFIG_DEBUG_ZBOOT + extern void puts(const char *s); + extern void puthex(unsigned long long val); ++#else ++#define puts(s) ++#define puthex(val) ++#endif + + void error(char *x) + { +diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script +index 5a33409..de04ac9 100644 +--- a/arch/mips/boot/compressed/ld.script ++++ b/arch/mips/boot/compressed/ld.script +@@ -49,5 +49,6 @@ SECTIONS + *(.reginfo) + *(.comment) + *(.note) ++ *(.gnu.attributes) + } + } +diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h +index a0ee0cb..4e18add 100644 +--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h ++++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h +@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo); + /* GPIO : I/O SPACE; REG : 32BITS */ + #define GPIOL_OUT_VAL 0x00 + #define GPIOL_OUT_EN 0x04 ++#define GPIOL_OUT_AUX1_SEL 0x10 ++/* SMB : I/O SPACE, REG : 8BITS WIDTH */ ++#define SMB_SDA 0x00 ++#define SMB_STS 0x01 ++#define SMB_STS_SLVSTP (1 << 7) ++#define SMB_STS_SDAST (1 << 6) ++#define SMB_STS_BER (1 << 5) ++#define SMB_STS_NEGACK (1 << 4) ++#define SMB_STS_STASTR (1 << 3) ++#define SMB_STS_NMATCH (1 << 2) ++#define SMB_STS_MASTER (1 << 1) ++#define SMB_STS_XMIT (1 << 0) ++#define SMB_CTRL_STS 0x02 ++#define SMB_CSTS_TGSTL (1 << 5) ++#define SMB_CSTS_TSDA (1 << 4) ++#define SMB_CSTS_GCMTCH (1 << 3) ++#define SMB_CSTS_MATCH (1 << 2) ++#define SMB_CSTS_BB (1 << 1) ++#define SMB_CSTS_BUSY (1 << 0) ++#define SMB_CTRL1 0x03 ++#define SMB_CTRL1_STASTRE (1 << 7) ++#define SMB_CTRL1_NMINTE (1 << 6) ++#define SMB_CTRL1_GCMEN (1 << 5) ++#define SMB_CTRL1_ACK (1 << 4) ++#define SMB_CTRL1_RSVD (1 << 3) ++#define SMB_CTRL1_INTEN (1 << 2) ++#define SMB_CTRL1_STOP (1 << 1) ++#define SMB_CTRL1_START (1 << 0) ++#define SMB_ADDR 0x04 ++#define SMB_ADDR_SAEN (1 << 7) ++#define SMB_CONTROLLER_ADDR (0xef << 0) ++#define SMB_CTRL2 0x05 ++#define SMB_FREQ (0x20 << 1) ++#define SMB_ENABLE (0x01 << 0) ++#define SMB_CTRL3 0x06 + + #endif /* _CS5536_H */ +diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h +index 021d017..50aafca 100644 +--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h ++++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h +@@ -28,8 +28,19 @@ static inline void __maybe_unused enable_mfgpt0_counter(void) + #define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ) + + #define MFGPT_BASE mfgpt_base ++#define MFGPT0_CMP1 (MFGPT_BASE + 0) + #define MFGPT0_CMP2 (MFGPT_BASE + 2) + #define MFGPT0_CNT (MFGPT_BASE + 4) + #define MFGPT0_SETUP (MFGPT_BASE + 6) + ++#define MFGPT1_CMP1 (MFGPT_BASE + 0x08) ++#define MFGPT1_CMP2 (MFGPT_BASE + 0x0A) ++#define MFGPT1_CNT (MFGPT_BASE + 0x0C) ++#define MFGPT1_SETUP (MFGPT_BASE + 0x0E) ++ ++#define MFGPT2_CMP1 (MFGPT_BASE + 0x10) ++#define MFGPT2_CMP2 (MFGPT_BASE + 0x12) ++#define MFGPT2_CNT (MFGPT_BASE + 0x14) ++#define MFGPT2_SETUP (MFGPT_BASE + 0x16) ++ + #endif /*!_CS5536_MFGPT_H */ +diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h +index 5459ac0..14e82d9 100644 +--- a/arch/mips/include/asm/mach-loongson/loongson.h ++++ b/arch/mips/include/asm/mach-loongson/loongson.h +@@ -46,6 +46,12 @@ static inline void prom_init_uart_base(void) + #endif + } + ++/* ++ * Copy kernel command line from arcs_cmdline ++ */ ++#include ++extern char loongson_cmdline[COMMAND_LINE_SIZE]; ++ + /* irq operation functions */ + extern void bonito_irqdispatch(void); + extern void __init bonito_irq_init(void); +diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h +index cb2b602..78fcd38 100644 +--- a/arch/mips/include/asm/mach-loongson/machine.h ++++ b/arch/mips/include/asm/mach-loongson/machine.h +@@ -24,6 +24,12 @@ + + #endif + ++#ifdef CONFIG_DEXXON_GDIUM ++ ++#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10 ++ ++#endif ++ + #ifdef CONFIG_LOONGSON_MACH3X + + #define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC +diff --git a/arch/mips/include/asm/mach-loongson1/clock.h b/arch/mips/include/asm/mach-loongson1/clock.h +new file mode 100644 +index 0000000..dd1afdb +--- /dev/null ++++ b/arch/mips/include/asm/mach-loongson1/clock.h +@@ -0,0 +1,53 @@ ++#ifndef __ASM_MACH_LOONGSON1_CLOCK_H ++#define __ASM_MACH_LOONGSON1_CLOCK_H ++ ++#include ++#include ++#include ++#include ++ ++extern void (*cpu_wait) (void); ++ ++struct clk; ++ ++struct clk_ops { ++ void (*init) (struct clk *clk); ++ void (*enable) (struct clk *clk); ++ void (*disable) (struct clk *clk); ++ void (*recalc) (struct clk *clk); ++ int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id); ++ long (*round_rate) (struct clk *clk, unsigned long rate); ++}; ++ ++struct clk { ++ struct list_head node; ++ const char *name; ++ int id; ++ struct module *owner; ++ ++ struct clk *parent; ++ struct clk_ops *ops; ++ ++ struct kref kref; ++ ++ unsigned long rate; ++ unsigned long flags; ++}; ++ ++#define CLK_ALWAYS_ENABLED (1 << 0) ++#define CLK_RATE_PROPAGATES (1 << 1) ++ ++/* Should be defined by processor-specific code */ ++void arch_init_clk_ops(struct clk_ops **, int type); ++ ++int clk_init(void); ++ ++int __clk_enable(struct clk *); ++void __clk_disable(struct clk *); ++ ++void clk_recalc_rate(struct clk *); ++ ++int clk_register(struct clk *); ++void clk_unregister(struct clk *); ++ ++#endif /* __ASM_MIPS_CLOCK_H */ +diff --git a/arch/mips/include/asm/mach-loongson1/regs-intc.h b/arch/mips/include/asm/mach-loongson1/regs-intc.h +new file mode 100644 +index 0000000..6d5db23 +--- /dev/null ++++ b/arch/mips/include/asm/mach-loongson1/regs-intc.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (c) 2011 Zhang, Keguang ++ * ++ * Loongson1 Interrupt register definitions. ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_LOONGSON1_REGS_INTC_H ++#define __ASM_MACH_LOONGSON1_REGS_INTC_H ++ ++#define LS1X_INTC_REG(n, x) \ ++ (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4)) ++ ++#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) ++#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) ++#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) ++#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) ++#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) ++#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) ++ ++#endif /* __ASM_MACH_LOONGSON1_REGS_INTC_H */ +diff --git a/arch/mips/include/asm/sparsemem.h b/arch/mips/include/asm/sparsemem.h +index b1071c1..8b8e551 100644 +--- a/arch/mips/include/asm/sparsemem.h ++++ b/arch/mips/include/asm/sparsemem.h +@@ -11,7 +11,11 @@ + #else + # define SECTION_SIZE_BITS 28 + #endif +-#define MAX_PHYSMEM_BITS 48 ++#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit c461731836 broke Loongson2. */ ++# define MAX_PHYSMEM_BITS 48 ++#else ++# define MAX_PHYSMEM_BITS 35 ++#endif + + #endif /* CONFIG_SPARSEMEM */ + #endif /* _MIPS_SPARSEMEM_H */ +diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h +index b05bb70..44c9a69 100644 +--- a/arch/mips/include/asm/timex.h ++++ b/arch/mips/include/asm/timex.h +@@ -11,6 +11,10 @@ + + #ifdef __KERNEL__ + ++#ifdef CONFIG_CSRC_R4K ++#define ARCH_HAS_PREPARED_LPJ ++#endif ++ + #include + + #include +diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h +index fc0cf5a..99e6430 100644 +--- a/arch/mips/include/uapi/asm/inst.h ++++ b/arch/mips/include/uapi/asm/inst.h +@@ -65,6 +65,8 @@ enum spec_op { + enum spec2_op { + madd_op, maddu_op, mul_op, spec2_3_unused_op, + msub_op, msubu_op, /* more unused ops */ ++ loongson_madd_op = 0x18, loongson_msub_op, ++ loongson_nmadd_op, loongson_nmsub_op, + clz_op = 0x20, clo_op, + dclz_op = 0x24, dclo_op, + sdbpp_op = 0x3f +@@ -151,7 +153,7 @@ enum cop0_com_func { + */ + enum cop1_fmt { + s_fmt, d_fmt, e_fmt, q_fmt, +- w_fmt, l_fmt ++ w_fmt, l_fmt, ps_fmt + }; + + /* +@@ -180,7 +182,8 @@ enum cop1_sdw_func { + enum cop1x_func { + lwxc1_op = 0x00, ldxc1_op = 0x01, + swxc1_op = 0x08, sdxc1_op = 0x09, +- pfetch_op = 0x0f, madd_s_op = 0x20, ++ pfetch_op = 0x0f, ++ prefx_op = 0x17, madd_s_op = 0x20, + madd_d_op = 0x21, madd_e_op = 0x22, + msub_s_op = 0x28, msub_d_op = 0x29, + msub_e_op = 0x2a, nmadd_s_op = 0x30, +diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S +index d07b210..69996f2 100644 +--- a/arch/mips/kernel/scall64-o32.S ++++ b/arch/mips/kernel/scall64-o32.S +@@ -26,6 +26,18 @@ + + .align 5 + NESTED(handle_sys, PT_SIZE, sp) ++#ifdef CONFIG_MIPS_USER_RDTSC ++ MFC0 k0, CP0_EPC ++ lw k1, 0(k0) ++ sltiu k1, k1, 0x1c ++ bne k1, zero, 1f # Normal syscall code: 0x0c < 0x1c ++ nop ++ mfc0 v0, CP0_COUNT # Get TSC ++ PTR_ADDIU k0, 4 # ret from syscall ++ MTC0 k0, CP0_EPC ++ eret ++1: ++#endif /* CONFIG_MIPS_USER_RDTSC */ + .set noat + SAVE_SOME + TRACE_IRQS_ON_RELOAD +diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c +index 8d01709..9cd25da 100644 +--- a/arch/mips/kernel/time.c ++++ b/arch/mips/kernel/time.c +@@ -119,6 +119,11 @@ static __init int cpu_has_mfc0_count_bug(void) + + void __init time_init(void) + { ++#ifdef CONFIG_HR_SCHED_CLOCK ++ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) ++ write_c0_count(0); ++#endif ++ + plat_time_init(); + + /* +diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile +index 1e9e900..36fcccc 100644 +--- a/arch/mips/lib/Makefile ++++ b/arch/mips/lib/Makefile +@@ -2,10 +2,14 @@ + # Makefile for MIPS-specific library files.. + # + +-lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ ++lib-y += bitops.o csum_partial.o memcpy.o memset.o \ + mips-atomic.o strlen_user.o strncpy_user.o \ + strnlen_user.o uncached.o + ++ifndef CONFIG_CSRC_R4K ++lib-y += delay.o ++endif ++ + obj-y += iomap.o + obj-$(CONFIG_PCI) += iomap-pci.o + lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y)) +diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig +index 156de85..0a433e6 100644 +--- a/arch/mips/loongson/Kconfig ++++ b/arch/mips/loongson/Kconfig +@@ -32,12 +32,12 @@ config LEMOTE_FULOONG2E + + config LEMOTE_MACH2F + bool "Lemote Loongson 2F family machines" +- select ARCH_SPARSEMEM_ENABLE ++ select ARCH_SPARSEMEM_ENABLE if HIBERNATION + select BOARD_SCACHE + select BOOT_ELF32 + select CEVT_R4K if ! MIPS_EXTERNAL_TIMER + select CPU_HAS_WB +- select CS5536 ++ select CS5536 if PCI + select CSRC_R4K if ! MIPS_EXTERNAL_TIMER + select DMA_NONCOHERENT + select GENERIC_ISA_DMA_SUPPORT_BROKEN +@@ -45,14 +45,13 @@ config LEMOTE_MACH2F + select HW_HAS_PCI + select I8259 + select IRQ_CPU +- select ISA + select SYS_HAS_CPU_LOONGSON2F + select SYS_HAS_EARLY_PRINTK + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL +- select SYS_SUPPORTS_HIGHMEM ++ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED + select SYS_SUPPORTS_LITTLE_ENDIAN +- select LOONGSON_MC146818 ++ select LOONGSON_MC146818 if RTC_DRV_CMOS + help + Lemote Loongson 2F family machines utilize the 2F revision of + Loongson processor and the AMD CS5536 south bridge. +@@ -60,6 +59,31 @@ config LEMOTE_MACH2F + These family machines include fuloong2f mini PC, yeeloong2f notebook, + LingLoong allinone PC and so forth. + ++config DEXXON_GDIUM ++ bool "Dexxon Gdium Netbook" ++ select ARCH_SPARSEMEM_ENABLE ++ select BOARD_SCACHE ++ select BOOT_ELF32 ++ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER ++ select CPU_HAS_WB ++ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER ++ select DMA_NONCOHERENT ++ select GENERIC_ISA_DMA_SUPPORT_BROKEN ++ select HW_HAS_PCI ++ select I8259 ++ select IRQ_CPU ++ select ISA ++ select SYS_HAS_CPU_LOONGSON2F ++ select SYS_HAS_EARLY_PRINTK ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_64BIT_KERNEL ++ select SYS_SUPPORTS_HIGHMEM ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select ARCH_REQUIRE_GPIOLIB ++ select HAVE_PWM if MFD_SM501 ++ help ++ Dexxon gdium netbook based on Loongson 2F and SM502. ++ + config LOONGSON_MACH3X + bool "Generic Loongson 3 family machines" + select ARCH_SPARSEMEM_ENABLE +@@ -152,6 +176,24 @@ config LOONGSON_MC146818 + bool + default n + ++config GDIUM_PWM_CLOCK ++ tristate "Gdium PWM Timer" ++ default n ++ depends on HAVE_PWM && EXPERIMENTAL && BROKEN ++ select MIPS_EXTERNAL_TIMER ++ help ++ This options enables the experimental sm501-pwm based clock. With it, ++ you may be possible to use the loongson2f cpufreq driver. ++ ++config GDIUM_VERSION ++ int "Configure Gdium Version" ++ depends on DEXXON_GDIUM ++ default "3" ++ help ++ I have no information about how to determine which version your board ++ is, If the default config doesn't work for it, please change it to ++ smaller ones. ++ + config LEFI_FIRMWARE_INTERFACE + bool + +diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile +index 7429994..63214c8 100644 +--- a/arch/mips/loongson/Makefile ++++ b/arch/mips/loongson/Makefile +@@ -17,6 +17,12 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ + obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ + + # ++# Dexxon gdium netbook, based on loongson 2F and SM502 ++# ++ ++obj-$(CONFIG_DEXXON_GDIUM) += gdium/ ++ ++# + # All Loongson-3 family machines + # + +diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform +index 0ac20eb..cd957dd 100644 +--- a/arch/mips/loongson/Platform ++++ b/arch/mips/loongson/Platform +@@ -30,4 +30,5 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/ + cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely + load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 + load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 ++load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000 + load-$(CONFIG_LOONGSON_MACH3X) += 0xffffffff80200000 +diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c +index 72fed00..96d5919 100644 +--- a/arch/mips/loongson/common/cmdline.c ++++ b/arch/mips/loongson/common/cmdline.c +@@ -17,10 +17,15 @@ + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ ++#include + #include + + #include + ++/* the kernel command line copied from arcs_cmdline */ ++char loongson_cmdline[COMMAND_LINE_SIZE]; ++EXPORT_SYMBOL(loongson_cmdline); ++ + void __init prom_init_cmdline(void) + { + int prom_argc; +@@ -45,4 +50,31 @@ void __init prom_init_cmdline(void) + } + + prom_init_machtype(); ++ ++ /* append machine specific command line */ ++ switch (mips_machtype) { ++ case MACH_LEMOTE_LL2F: ++ if ((strstr(arcs_cmdline, "video=")) == NULL) ++ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60"); ++ break; ++ case MACH_LEMOTE_FL2F: ++ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL) ++ strcat(arcs_cmdline, " ide_core.ignore_cable=0"); ++ break; ++ case MACH_LEMOTE_ML2F7: ++ /* Mengloong-2F has a 800x480 screen */ ++ if ((strstr(arcs_cmdline, "vga=")) == NULL) ++ strcat(arcs_cmdline, " vga=0x313"); ++ break; ++ case MACH_DEXXON_GDIUM2F10: ++ /* gdium has a 1024x600 screen */ ++ if ((strstr(arcs_cmdline, "video=")) == NULL) ++ strcat(arcs_cmdline, " video=sm501fb:1024x600@60"); ++ break; ++ default: ++ break; ++ } ++ ++ /* copy arcs_cmdline into loongson_cmdline */ ++ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE); + } +diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c +index 045ea3d..1d1db80 100644 +--- a/arch/mips/loongson/common/env.c ++++ b/arch/mips/loongson/common/env.c +@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap; + struct loongson_system_configuration loongson_sysconf; + + u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; ++EXPORT_SYMBOL_GPL(loongson_chipcfg); + u64 loongson_freqctrl[MAX_PACKAGES]; + + unsigned long long smp_group[4]; +diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile +new file mode 100644 +index 0000000..f3f4f51 +--- /dev/null ++++ b/arch/mips/loongson/gdium/Makefile +@@ -0,0 +1,6 @@ ++# Makefile for gdium ++ ++obj-y += irq.o reset.o platform.o ++ ++obj-$(CONFIG_MFD_SM501) += sm501-pwm.o ++obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o +diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c +new file mode 100644 +index 0000000..fdbf42a +--- /dev/null ++++ b/arch/mips/loongson/gdium/gdium-clock.c +@@ -0,0 +1,234 @@ ++/* ++ * Doesn't work really well. When used, the clocksource is producing ++ * bad timings and the clockevent can't be used (don't have one shot feature ++ * thus can't switch on the fly and the pwm is initialised too late to be able ++ * to use it at boot time). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define CLOCK_PWM 1 ++#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */ ++#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ) ++#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */ ++#define CLOCK_PWM_DUTY 50 ++#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4) ++ ++static const char drv_name[] = "gdium-clock"; ++ ++static struct pwm_device *clock_pwm; ++ ++static DEFINE_SPINLOCK(clock_pwm_lock); ++static uint64_t clock_tick; ++ ++static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *cd = dev_id; ++ unsigned long flag; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ clock_tick++; ++ /* wait intn2 to finish */ ++ do { ++ LOONGSON_INTENCLR = (1 << 13); ++ } while (LOONGSON_INTISR & (1 << 13)); ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ ++ if (cd && cd->event_handler) ++ cd->event_handler(cd); ++ ++ return IRQ_HANDLED; ++} ++ ++static cycle_t gdium_pwm_clock_read(struct clocksource *cs) ++{ ++ unsigned long flag; ++ uint32_t jifs; ++ uint64_t ticks; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ jifs = jiffies; ++ ticks = clock_tick; ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ /* return (cycle_t)ticks; */ ++ return (cycle_t)(CLOCK_LATCH * jifs); ++} ++ ++static struct clocksource gdium_pwm_clock_clocksource = { ++ .name = "gdium_csrc", ++ .read = gdium_pwm_clock_read, ++ .mask = CLOCKSOURCE_MASK(64), ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, ++ .shift = 20, ++}; ++ ++/* Debug fs */ ++static int gdium_pwm_clock_show(struct seq_file *s, void *p) ++{ ++ unsigned long flag; ++ uint64_t ticks; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ ticks = clock_tick; ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ seq_printf(s, "%lld\n", ticks); ++ return 0; ++} ++ ++static int gdium_pwm_clock_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, gdium_pwm_clock_show, inode->i_private); ++} ++ ++static const struct file_operations gdium_pwm_clock_fops = { ++ .open = gdium_pwm_clock_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++static struct dentry *debugfs_file; ++ ++static void gdium_pwm_clock_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ /* Nothing to do ... */ ++} ++ ++static struct clock_event_device gdium_pwm_clock_cevt = { ++ .name = "gdium_cevt", ++ .features = CLOCK_EVT_FEAT_PERIODIC, ++ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ ++ .rating = 299, ++ .irq = CLOCK_PWM_IRQ, ++ .set_mode = gdium_pwm_clock_set_mode, ++}; ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "gdium-pwmclk", ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver gdium_pwm_clock_driver = { ++ .driver = { ++ .name = drv_name, ++ .owner = THIS_MODULE, ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int gdium_pwm_clock_drvinit(void) ++{ ++ int ret; ++ struct clocksource *cs = &gdium_pwm_clock_clocksource; ++ struct clock_event_device *cd = &gdium_pwm_clock_cevt; ++ unsigned int cpu = smp_processor_id(); ++ ++ clock_tick = 0; ++ ++ clock_pwm = pwm_request(CLOCK_PWM, drv_name); ++ if (clock_pwm == NULL) { ++ pr_err("unable to request PWM for Gdium clock\n"); ++ return -EBUSY; ++ } ++ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD); ++ if (ret) { ++ pr_err("unable to configure PWM for Gdium clock\n"); ++ goto err_pwm_request; ++ } ++ ret = pwm_enable(clock_pwm); ++ if (ret) { ++ pr_err("unable to enable PWM for Gdium clock\n"); ++ goto err_pwm_request; ++ } ++ ++ cd->cpumask = cpumask_of(cpu); ++ ++ cd->shift = 22; ++ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift); ++ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd); ++ cd->min_delta_ns = clockevent_delta2ns(0xF, cd); ++ clockevents_register_device(&gdium_pwm_clock_cevt); ++ ++ /* SM501 PWM1 connected to intn2 <->ip4 */ ++ LOONGSON_INTPOL = (1 << 13); ++ LOONGSON_INTEDGE &= ~(1 << 13); ++ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt); ++ if (ret) { ++ pr_err("Can't claim irq\n"); ++ goto err_pwm_disable; ++ } ++ ++ cs->rating = 200; ++ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift); ++ ret = clocksource_register(&gdium_pwm_clock_clocksource); ++ if (ret) { ++ pr_err("Can't register clocksource\n"); ++ goto err_irq; ++ } ++ pr_info("Clocksource registered with shift %d and mult %d\n", ++ cs->shift, cs->mult); ++ ++ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO, ++ NULL, NULL, &gdium_pwm_clock_fops); ++ ++ return 0; ++ ++err_irq: ++ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); ++err_pwm_disable: ++ pwm_disable(clock_pwm); ++err_pwm_request: ++ pwm_free(clock_pwm); ++ return ret; ++} ++ ++static void gdium_pwm_clock_drvexit(void) ++{ ++ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); ++ pwm_disable(clock_pwm); ++ pwm_free(clock_pwm); ++} ++ ++ ++static int __devinit gdium_pwm_clock_init(void) ++{ ++ int ret = gdium_pwm_clock_drvinit(); ++ ++ if (ret) { ++ pr_err("Fail to register gdium clock driver\n"); ++ return ret; ++ } ++ ++ return platform_driver_register(&gdium_pwm_clock_driver); ++} ++ ++static void __exit gdium_pwm_clock_cleanup(void) ++{ ++ gdium_pwm_clock_drvexit(); ++ platform_driver_unregister(&gdium_pwm_clock_driver); ++} ++ ++module_init(gdium_pwm_clock_init); ++module_exit(gdium_pwm_clock_cleanup); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("Gdium PWM clock driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:gdium-pwmclk"); +diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c +new file mode 100644 +index 0000000..2415d20 +--- /dev/null ++++ b/arch/mips/loongson/gdium/irq.c +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2007 Lemote Inc. ++ * Author: Fuxin Zhang, zhangfx@lemote.com ++ * ++ * Copyright (c) 2010 yajin ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */ ++#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */ ++#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */ ++ ++void mach_irq_dispatch(unsigned int pending) ++{ ++ if (pending & CAUSEF_IP7) ++ do_IRQ(LOONGSON_TIMER_IRQ); ++ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ ++ do_perfcnt_IRQ(); ++ bonito_irqdispatch(); ++ } else if (pending & CAUSEF_IP3) /* CPU UART */ ++ do_IRQ(LOONGSON_UART_IRQ); ++#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE) ++ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 4); ++#endif ++ else ++ spurious_interrupt(); ++} ++ ++static irqreturn_t ip6_action(int cpl, void *dev_id) ++{ ++ return IRQ_HANDLED; ++} ++ ++struct irqaction ip6_irqaction = { ++ .handler = ip6_action, ++ .name = "cascade", ++ .flags = IRQF_SHARED, ++}; ++ ++void __init mach_init_irq(void) ++{ ++ /* setup north bridge irq (bonito) */ ++ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction); ++} +diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c +new file mode 100644 +index 0000000..ffafba4 +--- /dev/null ++++ b/arch/mips/loongson/gdium/platform.c +@@ -0,0 +1,135 @@ ++/* ++ * Copyright (c) 2009 Philippe Vachon ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define GDIUM_GPIO_BASE 224 ++ ++static struct i2c_board_info __initdata sm502dev_i2c_devices[] = { ++ { ++ I2C_BOARD_INFO("lm75", 0x48), ++ }, ++ { ++ I2C_BOARD_INFO("m41t83", 0x68), ++ }, ++ { ++ I2C_BOARD_INFO("gdium-laptop", 0x40), ++ }, ++}; ++ ++static int sm502dev_backlight_init(struct device *dev) ++{ ++ /* Add gpio request stuff here */ ++ return 0; ++} ++ ++static void sm502dev_backlight_exit(struct device *dev) ++{ ++ /* Add gpio free stuff here */ ++} ++ ++static struct platform_pwm_backlight_data backlight_data = { ++ .pwm_id = 0, ++ .max_brightness = 15, ++ .dft_brightness = 8, ++ .pwm_period_ns = 50000, /* 20 kHz */ ++ .init = sm502dev_backlight_init, ++ .exit = sm502dev_backlight_exit, ++}; ++ ++static struct platform_device backlight = { ++ .name = "pwm-backlight", ++ .dev = { ++ .platform_data = &backlight_data, ++ }, ++ .id = -1, ++}; ++ ++/* ++ * Warning this stunt is very dangerous ++ * as the sm501 gpio have dynamic numbers... ++ */ ++/* bus 0 is the one for the ST7, DS75 etc... */ ++static struct i2c_gpio_platform_data i2c_gpio0_data = { ++#if CONFIG_GDIUM_VERSION > 2 ++ .sda_pin = GDIUM_GPIO_BASE + 13, ++ .scl_pin = GDIUM_GPIO_BASE + 6, ++#else ++ .sda_pin = 192+15, ++ .scl_pin = 192+14, ++#endif ++ .udelay = 5, ++ .timeout = HZ / 10, ++ .sda_is_open_drain = 0, ++ .scl_is_open_drain = 0, ++}; ++ ++static struct platform_device i2c_gpio0_device = { ++ .name = "i2c-gpio", ++ .id = 0, ++ .dev = { .platform_data = &i2c_gpio0_data, }, ++}; ++ ++/* bus 1 is for the CRT/VGA external screen */ ++static struct i2c_gpio_platform_data i2c_gpio1_data = { ++ .sda_pin = GDIUM_GPIO_BASE + 10, ++ .scl_pin = GDIUM_GPIO_BASE + 9, ++ .udelay = 5, ++ .timeout = HZ / 10, ++ .sda_is_open_drain = 0, ++ .scl_is_open_drain = 0, ++}; ++ ++static struct platform_device i2c_gpio1_device = { ++ .name = "i2c-gpio", ++ .id = 1, ++ .dev = { .platform_data = &i2c_gpio1_data, }, ++}; ++ ++static struct platform_device gdium_clock = { ++ .name = "gdium-pwmclk", ++ .id = -1, ++}; ++ ++static struct platform_device *devices[] __initdata = { ++ &i2c_gpio0_device, ++ &i2c_gpio1_device, ++ &backlight, ++ &gdium_clock, ++}; ++ ++static int __init gdium_platform_devices_setup(void) ++{ ++ int ret; ++ ++ pr_info("Registering gdium platform devices\n"); ++ ++ ret = i2c_register_board_info(0, sm502dev_i2c_devices, ++ ARRAY_SIZE(sm502dev_i2c_devices)); ++ ++ if (ret != 0) { ++ pr_info("Error while registering platform devices: %d\n", ret); ++ return ret; ++ } ++ ++ platform_add_devices(devices, ARRAY_SIZE(devices)); ++ ++ return 0; ++} ++ ++/* ++ * some devices are on the pwm stuff which is behind the mfd which is ++ * behind the pci bus so arch_initcall can't work because too early ++ */ ++late_initcall(gdium_platform_devices_setup); +diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c +new file mode 100644 +index 0000000..8289f95 +--- /dev/null ++++ b/arch/mips/loongson/gdium/reset.c +@@ -0,0 +1,22 @@ ++/* Board-specific reboot/shutdown routines ++ * ++ * Copyright (C) 2010 yajin ++ * ++ * 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. ++ */ ++#include ++ ++void mach_prepare_shutdown(void) ++{ ++ LOONGSON_GPIOIE &= ~(1<<1); ++ LOONGSON_GPIODATA |= (1<<1); ++} ++ ++void mach_prepare_reboot(void) ++{ ++ LOONGSON_GPIOIE &= ~(1<<2); ++ LOONGSON_GPIODATA &= ~(1<<2); ++} +diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c +new file mode 100644 +index 0000000..5af3b23 +--- /dev/null ++++ b/arch/mips/loongson/gdium/sm501-pwm.c +@@ -0,0 +1,465 @@ ++/* ++ * SM501 PWM clock ++ * Copyright (C) 2009-2010 Arnaud Patard ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const char drv_name[] = "sm501-pwm"; ++ ++#define INPUT_CLOCK 96 /* MHz */ ++#define PWM_COUNT 3 ++ ++#define SM501PWM_HIGH_COUNTER (1<<20) ++#define SM501PWM_LOW_COUNTER (1<<8) ++#define SM501PWM_CLOCK_DIVIDE (1>>4) ++#define SM501PWM_IP (1<<3) ++#define SM501PWM_I (1<<2) ++#define SM501PWM_E (1<<0) ++ ++struct pwm_device { ++ struct list_head node; ++ struct device *dev; ++ void __iomem *regs; ++ int duty_ns; ++ int period_ns; ++ char enabled; ++ void (*handler)(struct pwm_device *pwm); ++ ++ const char *label; ++ unsigned int use_count; ++ unsigned int pwm_id; ++}; ++ ++struct sm501pwm_info { ++ void __iomem *regs; ++ int irq; ++ struct resource *res; ++ struct device *dev; ++ struct dentry *debugfs; ++ ++ struct pwm_device pwm[3]; ++}; ++ ++int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) ++{ ++ unsigned int high, low, divider; ++ int divider1, divider2; ++ unsigned long long delay; ++ ++ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns) ++ return -EINVAL; ++ ++ /* Get delay ++ * We're loosing some precision but multiplying then dividing ++ * will overflow ++ */ ++ if (period_ns > 1000) { ++ delay = period_ns / 1000; ++ delay *= INPUT_CLOCK; ++ } else { ++ delay = period_ns * 96; ++ delay /= 1000; ++ } ++ ++ /* Get the number of clock low and high */ ++ high = delay * duty_ns / period_ns; ++ low = delay - high; ++ ++ /* Get divider to make 'low' and 'high' fit into 12 bits */ ++ /* No need to say that the divider must be >= 0 */ ++ divider1 = fls(low)-12; ++ divider2 = fls(high)-12; ++ ++ if (divider1 < 0) ++ divider1 = 0; ++ if (divider2 < 0) ++ divider2 = 0; ++ ++ divider = max(divider1, divider2); ++ ++ low >>= divider; ++ high >>= divider; ++ ++ pwm->duty_ns = duty_ns; ++ pwm->period_ns = period_ns; ++ ++ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_config); ++ ++int pwm_enable(struct pwm_device *pwm) ++{ ++ u32 reg; ++ ++ if (!pwm) ++ return -EINVAL; ++ ++ switch (pwm->pwm_id) { ++ case 0: ++ sm501_configure_gpio(pwm->dev->parent, 29, 1); ++ break; ++ case 1: ++ sm501_configure_gpio(pwm->dev->parent, 30, 1); ++ break; ++ case 2: ++ sm501_configure_gpio(pwm->dev->parent, 31, 1); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ reg = readl(pwm->regs); ++ reg |= (SM501PWM_IP | SM501PWM_E); ++ writel(reg, pwm->regs); ++ pwm->enabled = 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(pwm_enable); ++ ++void pwm_disable(struct pwm_device *pwm) ++{ ++ u32 reg; ++ ++ if (!pwm) ++ return; ++ ++ reg = readl(pwm->regs); ++ reg &= ~(SM501PWM_IP | SM501PWM_E); ++ writel(reg, pwm->regs); ++ ++ switch (pwm->pwm_id) { ++ case 0: ++ sm501_configure_gpio(pwm->dev->parent, 29, 0); ++ break; ++ case 1: ++ sm501_configure_gpio(pwm->dev->parent, 30, 0); ++ break; ++ case 2: ++ sm501_configure_gpio(pwm->dev->parent, 31, 0); ++ break; ++ default: ++ break; ++ } ++ pwm->enabled = 0; ++} ++EXPORT_SYMBOL(pwm_disable); ++ ++static DEFINE_MUTEX(pwm_lock); ++static LIST_HEAD(pwm_list); ++ ++struct pwm_device *pwm_request(int pwm_id, const char *label) ++{ ++ struct pwm_device *pwm; ++ int found = 0; ++ ++ mutex_lock(&pwm_lock); ++ ++ list_for_each_entry(pwm, &pwm_list, node) { ++ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) { ++ pwm->use_count++; ++ pwm->label = label; ++ found = 1; ++ break; ++ } ++ } ++ ++ mutex_unlock(&pwm_lock); ++ ++ return (found) ? pwm : NULL; ++} ++EXPORT_SYMBOL(pwm_request); ++ ++void pwm_free(struct pwm_device *pwm) ++{ ++ mutex_lock(&pwm_lock); ++ ++ if (pwm->use_count) { ++ pwm->use_count--; ++ pwm->label = NULL; ++ } else ++ dev_warn(pwm->dev, "PWM device already freed\n"); ++ ++ mutex_unlock(&pwm_lock); ++} ++EXPORT_SYMBOL(pwm_free); ++ ++int pwm_int_enable(struct pwm_device *pwm) ++{ ++ unsigned long conf; ++ ++ if (!pwm || !pwm->regs || !pwm->handler) ++ return -EINVAL; ++ ++ conf = readl(pwm->regs); ++ conf |= SM501PWM_I; ++ writel(conf, pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_int_enable); ++ ++int pwm_int_disable(struct pwm_device *pwm) ++{ ++ unsigned long conf; ++ ++ if (!pwm || !pwm->regs || !pwm->handler) ++ return -EINVAL; ++ ++ conf = readl(pwm->regs); ++ conf &= ~SM501PWM_I; ++ writel(conf, pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_int_disable); ++ ++int pwm_set_handler(struct pwm_device *pwm, ++ void (*handler)(struct pwm_device *pwm)) ++{ ++ if (!pwm || !handler) ++ return -EINVAL; ++ pwm->handler = handler; ++ return 0; ++} ++EXPORT_SYMBOL(pwm_set_handler); ++ ++static irqreturn_t sm501pwm_irq(int irq, void *dev_id) ++{ ++ unsigned long value; ++ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id; ++ struct pwm_device *pwm; ++ int i; ++ ++ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0); ++ ++ /* Check is the interrupt is for us */ ++ if (value & (1<<22)) { ++ for (i = 0 ; i < PWM_COUNT ; i++) { ++ /* ++ * Find which pwm triggered the interrupt ++ * and ack ++ */ ++ value = readl(info->regs + i*4); ++ if (value & SM501PWM_IP) ++ writel(value | SM501PWM_IP, info->regs + i*4); ++ ++ pwm = &info->pwm[i]; ++ if (pwm->handler) ++ pwm->handler(pwm); ++ } ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static void add_pwm(int id, struct sm501pwm_info *info) ++{ ++ struct pwm_device *pwm = &info->pwm[id]; ++ ++ pwm->use_count = 0; ++ pwm->pwm_id = id; ++ pwm->dev = info->dev; ++ pwm->regs = info->regs + id * 4; ++ ++ mutex_lock(&pwm_lock); ++ list_add_tail(&pwm->node, &pwm_list); ++ mutex_unlock(&pwm_lock); ++} ++ ++static void del_pwm(int id, struct sm501pwm_info *info) ++{ ++ struct pwm_device *pwm = &info->pwm[id]; ++ ++ pwm->use_count = 0; ++ pwm->pwm_id = -1; ++ mutex_lock(&pwm_lock); ++ list_del(&pwm->node); ++ mutex_unlock(&pwm_lock); ++} ++ ++/* Debug fs */ ++static int sm501pwm_show(struct seq_file *s, void *p) ++{ ++ struct pwm_device *pwm; ++ ++ mutex_lock(&pwm_lock); ++ list_for_each_entry(pwm, &pwm_list, node) { ++ if (pwm->use_count) { ++ seq_printf(s, "pwm-%d (%12s) %d %d %s\n", ++ pwm->pwm_id, pwm->label, ++ pwm->duty_ns, pwm->period_ns, ++ pwm->enabled ? "on" : "off"); ++ seq_printf(s, " %08x\n", readl(pwm->regs)); ++ } ++ } ++ mutex_unlock(&pwm_lock); ++ ++ return 0; ++} ++ ++static int sm501pwm_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, sm501pwm_show, inode->i_private); ++} ++ ++static const struct file_operations sm501pwm_fops = { ++ .open = sm501pwm_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init sm501pwm_probe(struct platform_device *pdev) ++{ ++ struct sm501pwm_info *info; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ int ret = 0; ++ int res_len; ++ int i; ++ ++ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL); ++ if (!info) { ++ dev_err(dev, "Allocation failure\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ info->dev = dev; ++ platform_set_drvdata(pdev, info); ++ ++ /* Get irq number */ ++ info->irq = platform_get_irq(pdev, 0); ++ if (!info->irq) { ++ dev_err(dev, "no irq found\n"); ++ ret = -ENODEV; ++ goto err_alloc; ++ } ++ ++ /* Get regs address */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(dev, "No memory resource found\n"); ++ ret = -ENODEV; ++ goto err_alloc; ++ } ++ info->res = res; ++ res_len = (res->end - res->start)+1; ++ ++ if (!request_mem_region(res->start, res_len, drv_name)) { ++ dev_err(dev, "Can't request iomem resource\n"); ++ ret = -EBUSY; ++ goto err_alloc; ++ } ++ ++ info->regs = ioremap(res->start, res_len); ++ if (!info->regs) { ++ dev_err(dev, "ioremap failed\n"); ++ ret = -ENOMEM; ++ goto err_mem; ++ } ++ ++ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info); ++ if (ret != 0) { ++ dev_err(dev, "can't get irq\n"); ++ goto err_map; ++ } ++ ++ ++ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1); ++ ++ for (i = 0; i < 3; i++) ++ add_pwm(i, info); ++ ++ dev_info(dev, "SM501 PWM Found at %lx irq %d\n", ++ (unsigned long)info->res->start, info->irq); ++ ++ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO, ++ NULL, info, &sm501pwm_fops); ++ ++ ++ return 0; ++ ++err_map: ++ iounmap(info->regs); ++ ++err_mem: ++ release_mem_region(res->start, res_len); ++ ++err_alloc: ++ kfree(info); ++ platform_set_drvdata(pdev, NULL); ++err: ++ return ret; ++} ++ ++static int sm501pwm_remove(struct platform_device *pdev) ++{ ++ struct sm501pwm_info *info = platform_get_drvdata(pdev); ++ int i; ++ ++ if (info->debugfs) ++ debugfs_remove(info->debugfs); ++ ++ for (i = 0; i < 3; i++) { ++ pwm_disable(&info->pwm[i]); ++ del_pwm(i, info); ++ } ++ ++ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0); ++ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22); ++ ++ free_irq(info->irq, info); ++ iounmap(info->regs); ++ release_mem_region(info->res->start, ++ (info->res->end - info->res->start)+1); ++ kfree(info); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static struct platform_driver sm501pwm_driver = { ++ .probe = sm501pwm_probe, ++ .remove = sm501pwm_remove, ++ .driver = { ++ .name = drv_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __devinit sm501pwm_init(void) ++{ ++ return platform_driver_register(&sm501pwm_driver); ++} ++ ++static void __exit sm501pwm_cleanup(void) ++{ ++ platform_driver_unregister(&sm501pwm_driver); ++} ++ ++module_init(sm501pwm_init); ++module_exit(sm501pwm_cleanup); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("SM501 PWM driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:sm501-pwm"); +diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile +index 4f9eaa3..f945bd7a 100644 +--- a/arch/mips/loongson/lemote-2f/Makefile ++++ b/arch/mips/loongson/lemote-2f/Makefile +@@ -2,7 +2,7 @@ + # Makefile for lemote loongson2f family machines + # + +-obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o ++obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o platform.o + + # + # Suspend Support +diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c +new file mode 100644 +index 0000000..5316360 +--- /dev/null ++++ b/arch/mips/loongson/lemote-2f/platform.c +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++ ++static struct platform_device yeeloong_pdev = { ++ .name = "yeeloong_laptop", ++ .id = -1, ++}; ++ ++static struct platform_device lynloong_pdev = { ++ .name = "lynloong_pc", ++ .id = -1, ++}; ++ ++static int __init lemote2f_platform_init(void) ++{ ++ struct platform_device *pdev = NULL; ++ ++ switch (mips_machtype) { ++ case MACH_LEMOTE_YL2F89: ++ pdev = &yeeloong_pdev; ++ break; ++ case MACH_LEMOTE_LL2F: ++ pdev = &lynloong_pdev; ++ break; ++ default: ++ break; ++ ++ } ++ ++ if (pdev != NULL) ++ return platform_device_register(pdev); ++ ++ return -ENODEV; ++} ++ ++arch_initcall(lemote2f_platform_init); +diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c +index b30bf65..c0177cb 100644 +--- a/arch/mips/math-emu/cp1emu.c ++++ b/arch/mips/math-emu/cp1emu.c +@@ -7,6 +7,9 @@ + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. + * ++ * Loongson instruction support ++ * Copyright (C) 2011 Mark H Weaver ++ * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. +@@ -60,6 +63,11 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, + static int fpux_emu(struct pt_regs *, + struct mips_fpu_struct *, mips_instruction, void *__user *); + ++#ifdef CONFIG_MACH_LOONGSON ++static int loongson_spec2_emu(struct pt_regs *, ++ struct mips_fpu_struct *, mips_instruction, void *__user *); ++#endif ++ + /* Control registers */ + + #define FPCREG_RID 0 /* $0 = revision id */ +@@ -842,6 +850,14 @@ do { \ + #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) + #define DPTOREG(dp, x) DITOREG((dp).bits, x) + ++/* Support for Loongson paired single floating-point format */ ++#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \ ++ (si1) = (u32)di; (si2) = (u32)(di >> 32); }) ++#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x) ++ ++#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x) ++#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x) ++ + /* + * Emulate the single floating point instruction pointed at by EPC. + * Two instructions if the instruction is in a branch delay slot. +@@ -1235,6 +1251,16 @@ emul: + xcp->regs[MIPSInst_RD(ir)] = + xcp->regs[MIPSInst_RS(ir)]; + break; ++ ++#ifdef CONFIG_MACH_LOONGSON ++ case spec2_op:{ ++ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr); ++ if (sig) ++ return sig; ++ break; ++ } ++#endif ++ + default: + sigill: + return SIGILL; +@@ -1312,6 +1338,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); + DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); + DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); + ++#ifdef CONFIG_MACH_LOONGSON ++static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ++ mips_instruction ir, void *__user *fault_addr) ++{ ++ int rfmt; /* resulting format */ ++ unsigned rcsr = 0; /* resulting csr */ ++ union { ++ union ieee754dp d; ++ struct { ++ union ieee754sp s; ++ union ieee754sp s2; ++ }; ++ } rv; /* resulting value */ ++ ++ /* XXX maybe add a counter for loongson spec2 fp instructions? */ ++ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */ ++ ++ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { ++ case s_fmt:{ ++ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); ++ union ieee754sp fd, fs, ft; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_sp_madd; ++ goto scoptop; ++ case loongson_msub_op: ++ handler = fpemu_sp_msub; ++ goto scoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_sp_nmadd; ++ goto scoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_sp_nmsub; ++ goto scoptop; ++ ++ scoptop: ++ SPFROMREG(fd, MIPSInst_FD(ir)); ++ SPFROMREG(fs, MIPSInst_FS(ir)); ++ SPFROMREG(ft, MIPSInst_FT(ir)); ++ rv.s = (*handler) (fd, fs, ft); ++ ++ copcsr: ++ if (ieee754_cxtest(IEEE754_INEXACT)) ++ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; ++ if (ieee754_cxtest(IEEE754_UNDERFLOW)) ++ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; ++ if (ieee754_cxtest(IEEE754_OVERFLOW)) ++ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; ++ if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) ++ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; ++ ++ break; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ case d_fmt:{ ++ union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); ++ union ieee754dp fd, fs, ft; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_dp_madd; ++ goto dcoptop; ++ case loongson_msub_op: ++ handler = fpemu_dp_msub; ++ goto dcoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_dp_nmadd; ++ goto dcoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_dp_nmsub; ++ goto dcoptop; ++ ++ dcoptop: ++ DPFROMREG(fd, MIPSInst_FD(ir)); ++ DPFROMREG(fs, MIPSInst_FS(ir)); ++ DPFROMREG(ft, MIPSInst_FT(ir)); ++ rv.d = (*handler) (fd, fs, ft); ++ goto copcsr; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ case ps_fmt:{ ++ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fd1, fs1, ft1; ++ union ieee754sp fd2, fs2, ft2; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_sp_madd; ++ goto pscoptop; ++ case loongson_msub_op: ++ handler = fpemu_sp_msub; ++ goto pscoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_sp_nmadd; ++ goto pscoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_sp_nmsub; ++ goto pscoptop; ++ ++ pscoptop: ++ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir)); ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); ++ rv.s = (*handler) (fd1, fs1, ft1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler) (fd2, fs2, ft2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ default: ++ return SIGILL; ++ } ++ ++ /* ++ * Update the fpu CSR register for this operation. ++ * If an exception is required, generate a tidy SIGFPE exception, ++ * without updating the result register. ++ * Note: cause exception bits do not accumulate, they are rewritten ++ * for each op; only the flag/sticky bits accumulate. ++ */ ++ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; ++ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { ++ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ ++ return SIGFPE; ++ } ++ ++ /* ++ * Now we can safely write the result back to the register file. ++ */ ++ switch (rfmt) { ++ case d_fmt: ++ DPTOREG(rv.d, MIPSInst_FD(ir)); ++ break; ++ case s_fmt: ++ SPTOREG(rv.s, MIPSInst_FD(ir)); ++ break; ++ case ps_fmt: ++ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); ++ break; ++ default: ++ return SIGILL; ++ } ++ ++ return 0; ++} ++#endif ++ + static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + mips_instruction ir, void *__user *fault_addr) + { +@@ -1413,7 +1605,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + break; + + default: +- return SIGILL; ++ goto SIGILL_unless_prefx_op; + } + break; + } +@@ -1483,7 +1675,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + goto copcsr; + + default: +- return SIGILL; ++ goto SIGILL_unless_prefx_op; + } + break; + } +@@ -1496,6 +1688,11 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + break; + + default: ++ SIGILL_unless_prefx_op: ++ if (MIPSInst_FUNC(ir) == prefx_op) { ++ /* ignore prefx operation */ ++ break; ++ } + return SIGILL; + } + +@@ -1517,7 +1714,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + unsigned cond; + union { + union ieee754dp d; +- union ieee754sp s; ++ struct { ++ union ieee754sp s; ++#ifdef CONFIG_MACH_LOONGSON ++ union ieee754sp s2; /* for Loongson paired singles */ ++#endif ++ }; + int w; + s64 l; + } rv; /* resulting value */ +@@ -1614,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + case fmov_op: + /* an easy one */ + SPFROMREG(rv.s, MIPSInst_FS(ir)); +- goto copcsr; ++ break; + + /* binary op on handler */ + scopbop: +@@ -1811,7 +2013,7 @@ copcsr: + case fmov_op: + /* an easy one */ + DPFROMREG(rv.d, MIPSInst_FS(ir)); +- goto copcsr; ++ break; + + /* binary op on handler */ + dcopbop: +@@ -1928,6 +2130,83 @@ dcopuop: + break; + } + ++#ifdef CONFIG_MACH_LOONGSON ++ case ps_fmt:{ /* 6 */ ++ /* Support for Loongson paired single fp instructions */ ++ union { ++ union ieee754sp(*b) (union ieee754sp, union ieee754sp); ++ union ieee754sp(*u) (union ieee754sp); ++ } handler; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ /* binary ops */ ++ case fadd_op: ++ handler.b = ieee754sp_add; ++ goto pscopbop; ++ case fsub_op: ++ handler.b = ieee754sp_sub; ++ goto pscopbop; ++ case fmul_op: ++ handler.b = ieee754sp_mul; ++ goto pscopbop; ++ ++ /* unary ops */ ++ case fabs_op: ++ handler.u = ieee754sp_abs; ++ goto pscopuop; ++ case fneg_op: ++ handler.u = ieee754sp_neg; ++ goto pscopuop; ++ case fmov_op: ++ /* an easy one */ ++ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir)); ++ break; ++ ++ pscopbop: /* paired binary op handler */ ++ { ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fs1, ft1; ++ union ieee754sp fs2, ft2; ++ ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); ++ rv.s = (*handler.b) (fs1, ft1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler.b) (fs2, ft2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ } ++ pscopuop: /* paired unary op handler */ ++ { ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fs1; ++ union ieee754sp fs2; ++ ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ rv.s = (*handler.u) (fs1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler.u) (fs2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ } ++ break; ++ ++ default: ++ if (MIPSInst_FUNC(ir) >= fcmp_op) { ++ /* Loongson fp hardware handles all ++ cases of fp compare insns, so we ++ shouldn't have to */ ++ printk ("Loongson paired-single fp compare" ++ " unimplemented in cp1emu.c\n"); ++ } ++ return SIGILL; ++ } ++ break; ++ } ++#endif ++ + case l_fmt: + + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) +@@ -1999,6 +2278,11 @@ dcopuop: + + DITOREG(rv.l, MIPSInst_FD(ir)); + break; ++#ifdef CONFIG_MACH_LOONGSON ++ case ps_fmt: ++ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); ++ break; ++#endif + default: + return SIGILL; + } +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index 300591c..ed272e2 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o + obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o + obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o + obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o ++obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o + obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3.o + obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o + obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o +diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c +new file mode 100644 +index 0000000..b296220 +--- /dev/null ++++ b/arch/mips/pci/fixup-gdium.c +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (C) 2010 yajin ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++/* ++ * http://www.pcidatabase.com ++ * GDIUM has different PCI mapping ++ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI ++ * slog 14 (0x126f/0x0501) -> sm501 ++ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers ++ * plus Single EHCI controller ++ * slot 16 (0x10ec/0x8139) -> Realtek 8139c ++ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller ++ */ ++ ++#undef INT_IRQA ++#undef INT_IRQB ++#undef INT_IRQC ++#undef INT_IRQD ++#define INT_IRQA 36 ++#define INT_IRQB 37 ++#define INT_IRQC 38 ++#define INT_IRQD 39 ++ ++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ int irq = 0; ++ ++ switch (slot) { ++ case 13: ++ irq = INT_IRQC + ((pin - 1) & 3); ++ break; ++ case 14: ++ irq = INT_IRQA; ++ break; ++ case 15: ++#if CONFIG_GDIUM_VERSION > 2 ++ irq = INT_IRQB; ++#else ++ irq = INT_IRQA + ((pin - 1) & 3); ++#endif ++ break; ++ case 16: ++ irq = INT_IRQD; ++ break; ++#if CONFIG_GDIUM_VERSION > 2 ++ case 17: ++ irq = INT_IRQC; ++ break; ++#endif ++ default: ++ pr_info(" strange pci slot number %d on gdium.\n", slot); ++ break; ++ } ++ return irq; ++} ++ ++/* Do platform specific device initialization at pci_enable_device() time */ ++int pcibios_plat_dev_init(struct pci_dev *dev) ++{ ++ return 0; ++} ++ ++/* Fixups for the USB host controllers */ ++static void __init gdium_usb_host_fixup(struct pci_dev *dev) ++{ ++ unsigned int val; ++ pci_read_config_dword(dev, 0xe0, &val); ++#if CONFIG_GDIUM_VERSION > 2 ++ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3); ++#else ++ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5); ++ pci_write_config_dword(dev, 0xe4, 1<<5); ++#endif ++} ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, ++ gdium_usb_host_fixup); ++#if CONFIG_GDIUM_VERSION > 2 ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550, ++ gdium_usb_host_fixup); ++#endif +diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S +index e7567c8..498e42d 100644 +--- a/arch/mips/power/hibernate.S ++++ b/arch/mips/power/hibernate.S +@@ -30,8 +30,10 @@ LEAF(swsusp_arch_suspend) + END(swsusp_arch_suspend) + + LEAF(swsusp_arch_resume) ++#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit 771004298d broke Loongson2. */ + /* Avoid TLB mismatch during and after kernel resume */ + jal local_flush_tlb_all ++#endif + PTR_L t0, restore_pblist + 0: + PTR_L t1, PBE_ADDRESS(t0) /* source */ +diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c +index fc897ba..ac60f6b 100644 +--- a/drivers/cpufreq/loongson2_cpufreq.c ++++ b/drivers/cpufreq/loongson2_cpufreq.c +@@ -161,20 +161,32 @@ static int __init cpufreq_init(void) + /* Register platform stuff */ + ret = platform_driver_register(&platform_driver); + if (ret) +- return ret; ++ goto err_return; + + pr_info("cpufreq: Loongson-2F CPU frequency driver.\n"); + +- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, +- CPUFREQ_TRANSITION_NOTIFIER); ++ ret = cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ if (ret) ++ goto err_platform_driver_unregister; + + ret = cpufreq_register_driver(&loongson2_cpufreq_driver); ++ if (ret) ++ goto err_cpufreq_unregister_notifier; + +- if (!ret && !nowait) { ++ if (!nowait) { + saved_cpu_wait = cpu_wait; + cpu_wait = loongson2_cpu_wait; + } + ++ return 0; ++ ++ err_cpufreq_unregister_notifier: ++ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ err_platform_driver_unregister: ++ platform_driver_unregister(&platform_driver); ++ err_return: + return ret; + } + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 152b006..767d8de 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -871,6 +871,13 @@ config HID_ZYDACRON + ---help--- + Support for Zydacron remote control. + ++config HID_GDIUM ++ bool "Gdium Fn keys support" if EMBEDDED ++ depends on USB_HID && DEXXON_GDIUM ++ default !EMBEDDED ++ ---help--- ++ Support for Functions keys available on Gdiums. ++ + config HID_SENSOR_HUB + tristate "HID Sensors framework support" + depends on HID && HAS_IOMEM +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 6f19958..2740ff0 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -99,6 +99,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o + wacom-objs := wacom_wac.o wacom_sys.o + obj-$(CONFIG_HID_WACOM) += wacom.o + obj-$(CONFIG_HID_WALTOP) += hid-waltop.o ++obj-$(CONFIG_HID_GDIUM) += hid-gdium.o + obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o + obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o + +diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c +new file mode 100644 +index 0000000..67cc095 +--- /dev/null ++++ b/drivers/hid/hid-gdium.c +@@ -0,0 +1,210 @@ ++/* ++ * hid-gdium -- Gdium laptop function keys ++ * ++ * Arnaud Patard ++ * ++ * Based on hid-apple.c ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++#define GDIUM_FN_ON 1 ++ ++static int fnmode = GDIUM_FN_ON; ++module_param(fnmode, int, 0644); ++MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)"); ++ ++struct gdium_data { ++ unsigned int fn_on; ++}; ++ ++ ++struct gdium_key_translation { ++ u16 from; ++ u16 to; ++}; ++ ++static struct gdium_key_translation gdium_fn_keys[] = { ++ { KEY_F1, KEY_CAMERA }, ++ { KEY_F2, KEY_CONNECT }, ++ { KEY_F3, KEY_MUTE }, ++ { KEY_F4, KEY_VOLUMEUP}, ++ { KEY_F5, KEY_VOLUMEDOWN }, ++ { KEY_F6, KEY_SWITCHVIDEOMODE }, ++ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */ ++ { KEY_F8, KEY_BRIGHTNESSUP }, ++ { KEY_F9, KEY_BRIGHTNESSDOWN }, ++ { KEY_F10, KEY_SLEEP }, ++ { KEY_F11, KEY_PROG1 }, ++ { KEY_F12, KEY_PROG2 }, ++ { KEY_UP, KEY_PAGEUP }, ++ { KEY_DOWN, KEY_PAGEDOWN }, ++ { KEY_INSERT, KEY_NUMLOCK }, ++ { KEY_DELETE, KEY_SCROLLLOCK }, ++ { KEY_T, KEY_STOPCD }, ++ { KEY_F, KEY_PREVIOUSSONG }, ++ { KEY_H, KEY_NEXTSONG }, ++ { KEY_G, KEY_PLAYPAUSE }, ++ { } ++}; ++ ++static struct gdium_key_translation *gdium_find_translation( ++ struct gdium_key_translation *table, u16 from) ++{ ++ struct gdium_key_translation *trans; ++ ++ /* Look for the translation */ ++ for (trans = table; trans->from; trans++) ++ if (trans->from == from) ++ return trans; ++ return NULL; ++} ++ ++static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input, ++ struct hid_usage *usage, __s32 value) ++{ ++ struct gdium_data *data = hid_get_drvdata(hid); ++ struct gdium_key_translation *trans; ++ int do_translate; ++ ++ if (usage->type != EV_KEY) ++ return 0; ++ ++ if ((usage->code == KEY_FN)) { ++ data->fn_on = !!value; ++ input_event(input, usage->type, usage->code, value); ++ return 1; ++ } ++ ++ if (fnmode) { ++ trans = gdium_find_translation(gdium_fn_keys, usage->code); ++ if (trans) { ++ do_translate = data->fn_on; ++ if (do_translate) { ++ input_event(input, usage->type, trans->to, value); ++ return 1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int gdium_input_event(struct hid_device *hdev, struct hid_field *field, ++ struct hid_usage *usage, __s32 value) ++{ ++ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type) ++ return 0; ++ ++ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value)) ++ return 1; ++ ++ return 0; ++} ++ ++ ++static void gdium_input_setup(struct input_dev *input) ++{ ++ struct gdium_key_translation *trans; ++ ++ set_bit(KEY_NUMLOCK, input->keybit); ++ ++ /* Enable all needed keys */ ++ for (trans = gdium_fn_keys; trans->from; trans++) ++ set_bit(trans->to, input->keybit); ++} ++ ++static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) ++ && ((usage->hid & HID_USAGE) == 0x82)) { ++ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); ++ gdium_input_setup(hi->input); ++ return 1; ++ } ++ return 0; ++} ++ ++static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ struct gdium_data *data; ++ int ret; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) { ++ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n"); ++ return -ENOMEM; ++ } ++ ++ hid_set_drvdata(hdev, data); ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ dev_err(&hdev->dev, "parse failed\n"); ++ goto err_free; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ++ if (ret) { ++ dev_err(&hdev->dev, "hw start failed\n"); ++ goto err_free; ++ } ++ ++ return 0; ++err_free: ++ kfree(data); ++ return ret; ++} ++static void gdium_input_remove(struct hid_device *hdev) ++{ ++ hid_hw_stop(hdev); ++ kfree(hid_get_drvdata(hdev)); ++} ++ ++static const struct hid_device_id gdium_input_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) }, ++ {} ++}; ++MODULE_DEVICE_TABLE(hid, gdium_input_devices); ++ ++static struct hid_driver gdium_input_driver = { ++ .name = "gdium-fnkeys", ++ .id_table = gdium_input_devices, ++ .probe = gdium_input_probe, ++ .remove = gdium_input_remove, ++ .event = gdium_input_event, ++ .input_mapping = gdium_input_mapping, ++}; ++ ++static int gdium_input_init(void) ++{ ++ int ret; ++ ++ ret = hid_register_driver(&gdium_input_driver); ++ if (ret) ++ pr_err("can't register gdium keyboard driver\n"); ++ ++ return ret; ++} ++static void gdium_input_exit(void) ++{ ++ hid_unregister_driver(&gdium_input_driver); ++} ++ ++module_init(gdium_input_init); ++module_exit(gdium_input_exit); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 7fe5590..3087a7f 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -1025,6 +1025,9 @@ + #define USB_VENDOR_ID_ZYTRONIC 0x14c8 + #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 + ++#define USB_VENDOR_ID_GDIUM 0x04B4 ++#define USB_DEVICE_ID_GDIUM 0xe001 ++ + #define USB_VENDOR_ID_PRIMAX 0x0461 + #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 + +diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c +index 376f2dc..b576801 100644 +--- a/drivers/ide/ide-iops.c ++++ b/drivers/ide/ide-iops.c +@@ -27,6 +27,10 @@ + #include + #include + ++#ifdef CONFIG_LEMOTE_MACH2F ++#include ++#endif ++ + void SELECT_MASK(ide_drive_t *drive, int mask) + { + const struct ide_port_ops *port_ops = drive->hwif->port_ops; +@@ -300,6 +304,11 @@ void ide_check_nien_quirk_list(ide_drive_t *drive) + { + const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; + ++#ifdef CONFIG_LEMOTE_MACH2F ++ if (mips_machtype != MACH_LEMOTE_YL2F89) ++ return; ++#endif ++ + for (list = nien_quirk_list; *list != NULL; list++) + if (strstr(m, *list) != NULL) { + drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; +diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c +index 91077ef..2cfd9ff 100644 +--- a/drivers/mfd/sm501.c ++++ b/drivers/mfd/sm501.c +@@ -58,7 +58,7 @@ struct sm501_gpio { + struct sm501_gpio { + /* no gpio support, empty definition for sm501_devdata. */ + }; +-#endif ++#endif /* CONFIG_MFD_SM501_GPIO */ + + struct sm501_devdata { + spinlock_t reg_lock; +@@ -1124,6 +1124,22 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) + { + return sm->gpio.registered; + } ++ ++void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned ++ char mode) ++{ ++ unsigned long set, reg, offset = gpio; ++ ++ if (offset >= 32) { ++ reg = SM501_GPIO63_32_CONTROL; ++ offset = gpio - 32; ++ } else ++ reg = SM501_GPIO31_0_CONTROL; ++ ++ set = mode ? 1 << offset : 0; ++ ++ sm501_modify_reg(dev, reg, set, 0); ++} + #else + static inline int sm501_register_gpio(struct sm501_devdata *sm) + { +@@ -1143,7 +1159,13 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) + { + return 0; + } +-#endif ++ ++void sm501_configure_gpio(struct device *dev, unsigned int gpio, ++ unsigned char mode) ++{ ++} ++#endif /* CONFIG_MFD_SM501_GPIO */ ++EXPORT_SYMBOL_GPL(sm501_configure_gpio); + + static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, + struct sm501_platdata_gpio_i2c *iic) +@@ -1198,6 +1220,20 @@ static int sm501_register_gpio_i2c(struct sm501_devdata *sm, + return 0; + } + ++/* register sm501 PWM device */ ++static int sm501_register_pwm(struct sm501_devdata *sm) ++{ ++ struct platform_device *pdev; ++ ++ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0); ++ if (!pdev) ++ return -ENOMEM; ++ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC); ++ sm501_create_irq(sm, &pdev->resource[1]); ++ ++ return sm501_register_device(sm, pdev); ++} ++ + /* sm501_dbg_regs + * + * Debug attribute to attach to parent device to show core registers +@@ -1356,6 +1392,8 @@ static int sm501_init_dev(struct sm501_devdata *sm) + sm501_register_uart(sm, idata->devices); + if (idata->devices & SM501_USE_GPIO) + sm501_register_gpio(sm); ++ if (idata->devices & SM501_USE_PWM) ++ sm501_register_pwm(sm); + } + + if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { +@@ -1542,10 +1580,15 @@ static struct sm501_initdata sm501_pci_initdata = { + .devices = SM501_USE_ALL, + + /* Errata AB-3 says that 72MHz is the fastest available +- * for 33MHZ PCI with proper bus-mastering operation */ +- ++ * for 33MHZ PCI with proper bus-mastering operation ++ * For gdium, it works under 84&112M clock freq.*/ ++#ifdef CONFIG_DEXXON_GDIUM ++ .mclk = 84 * MHZ, ++ .m1xclk = 112 * MHZ, ++#else + .mclk = 72 * MHZ, + .m1xclk = 144 * MHZ, ++#endif + }; + + static struct sm501_platdata_fbsub sm501_pdata_fbsub = { +diff --git a/drivers/net/titan_ge.c b/drivers/net/titan_ge.c +new file mode 100644 +index 0000000..dc137bf8 +--- /dev/null ++++ b/drivers/net/titan_ge.c +@@ -0,0 +1,2069 @@ ++/* ++ * drivers/net/titan_ge.c - Driver for Titan ethernet ports ++ * ++ * Copyright (C) 2003 PMC-Sierra Inc. ++ * Author : Manish Lachwani (lachwani@pmc-sierra.com) ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * The MAC unit of the Titan consists of the following: ++ * ++ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO ++ * -> FIFO is where the incoming and outgoing data is placed ++ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes ++ * the data into the FIFO for Rx ++ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. ++ * -> AFX is the address filtering block ++ * -> GMII block to communicate with the PHY ++ * ++ * Rx will look like the following: ++ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory ++ * ++ * Tx will look like the following: ++ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII ++ * ++ * The Titan driver has support for the following performance features: ++ * -> Rx side checksumming ++ * -> Jumbo Frames ++ * -> Interrupt Coalscing ++ * -> Rx NAPI ++ * -> SKB Recycling ++ * -> Transmit/Receive descriptors in SRAM ++ * -> Fast routing for IP forwarding ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* For MII specifc registers, titan_mdio.h should be included */ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "titan_ge.h" ++#include "titan_mdio.h" ++ ++/* Static Function Declarations */ ++static int titan_ge_eth_open(struct net_device *); ++static void titan_ge_eth_stop(struct net_device *); ++static struct net_device_stats *titan_ge_get_stats(struct net_device *); ++static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int, ++ unsigned long, unsigned long, ++ unsigned long); ++static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int, ++ unsigned long, unsigned long); ++ ++static int titan_ge_open(struct net_device *); ++static int titan_ge_start_xmit(struct sk_buff *, struct net_device *); ++static int titan_ge_stop(struct net_device *); ++ ++static unsigned long titan_ge_tx_coal(unsigned long, int); ++ ++static void titan_ge_port_reset(unsigned int); ++static int titan_ge_free_tx_queue(titan_ge_port_info *); ++static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *); ++static int titan_ge_port_start(struct net_device *, titan_ge_port_info *); ++ ++static int titan_ge_return_tx_desc(titan_ge_port_info *, int); ++ ++/* ++ * Some configuration for the FIFO and the XDMA channel needs ++ * to be done only once for all the ports. This flag controls ++ * that ++ */ ++static unsigned long config_done; ++ ++/* ++ * One time out of memory flag ++ */ ++static unsigned int oom_flag; ++ ++static int titan_ge_poll(struct net_device *netdev, int *budget); ++ ++static int titan_ge_receive_queue(struct net_device *, unsigned int); ++ ++static struct platform_device *titan_ge_device[3]; ++ ++/* MAC Address */ ++extern unsigned char titan_ge_mac_addr_base[6]; ++ ++unsigned long titan_ge_base; ++static unsigned long titan_ge_sram; ++ ++static char titan_string[] = "titan"; ++ ++/* ++ * The Titan GE has two alignment requirements: ++ * -> skb->data to be cacheline aligned (32 byte) ++ * -> IP header alignment to 16 bytes ++ * ++ * The latter is not implemented. So, that results in an extra copy on ++ * the Rx. This is a big performance hog. For the former case, the ++ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size ++ * requested is calculated: ++ * ++ * Ethernet Frame Size : 1518 ++ * Ethernet Header : 14 ++ * Future Titan change for IP header alignment : 2 ++ * ++ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header ++ * alignment, we use skb_reserve(). ++ */ ++ ++#define ALIGNED_RX_SKB_ADDR(addr) \ ++ ((((unsigned long)(addr) + (64UL - 1UL)) \ ++ & ~(64UL - 1UL)) - (unsigned long)(addr)) ++ ++#define titan_ge_alloc_skb(__length, __gfp_flags) \ ++({ struct sk_buff *__skb; \ ++ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \ ++ if(__skb) { \ ++ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \ ++ if(__offset) \ ++ skb_reserve(__skb, __offset); \ ++ } \ ++ __skb; \ ++}) ++ ++/* ++ * Configure the GMII block of the Titan based on what the PHY tells us ++ */ ++static void titan_ge_gmii_config(int port_num) ++{ ++ unsigned int reg_data = 0, phy_reg; ++ int err; ++ ++ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); ++ ++ if (err == TITAN_GE_MDIO_ERROR) { ++ printk(KERN_ERR ++ "Could not read PHY control register 0x11 \n"); ++ printk(KERN_ERR ++ "Setting speed to 1000 Mbps and Duplex to Full \n"); ++ ++ return; ++ } ++ ++ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0); ++ ++ if (phy_reg & 0x8000) { ++ if (phy_reg & 0x2000) { ++ /* Full Duplex and 1000 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x201); ++ } else { ++ /* Half Duplex and 1000 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x2201); ++ } ++ } ++ if (phy_reg & 0x4000) { ++ if (phy_reg & 0x2000) { ++ /* Full Duplex and 100 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x100); ++ } else { ++ /* Half Duplex and 100 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x2100); ++ } ++ } ++ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL + ++ (port_num << 12)); ++ reg_data |= 0x3; ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL + ++ (port_num << 12)), reg_data); ++} ++ ++/* ++ * Enable the TMAC if it is not ++ */ ++static void titan_ge_enable_tx(unsigned int port_num) ++{ ++ unsigned long reg_data; ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); ++ if (!(reg_data & 0x8000)) { ++ printk("TMAC disabled for port %d!! \n", port_num); ++ ++ reg_data |= 0x0001; /* Enable TMAC */ ++ reg_data |= 0x4000; /* CRC Check Enable */ ++ reg_data |= 0x2000; /* Padding enable */ ++ reg_data |= 0x0800; /* CRC Add enable */ ++ reg_data |= 0x0080; /* PAUSE frame */ ++ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ } ++} ++ ++/* ++ * Tx Timeout function ++ */ ++static void titan_ge_tx_timeout(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ printk(KERN_INFO "%s: TX timeout ", netdev->name); ++ printk(KERN_INFO "Resetting card \n"); ++ ++ /* Do the reset outside of interrupt context */ ++ schedule_work(&titan_ge_eth->tx_timeout_task); ++} ++ ++/* ++ * Update the AFX tables for UC and MC for slice 0 only ++ */ ++static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth) ++{ ++ int port = titan_ge_eth->port_num; ++ unsigned int i; ++ volatile unsigned long reg_data = 0; ++ u8 p_addr[6]; ++ ++ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6); ++ ++ /* Set the MAC address here for TMAC and RMAC */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1); ++ /* Configure the eight address filters */ ++ for (i = 0; i < 8; i++) { ++ /* Select each of the eight filters */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 + ++ (port << 12)), i); ++ ++ /* Configure the match */ ++ reg_data = 0x9; /* Forward Enable Bit */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 + ++ (port << 12)), reg_data); ++ ++ /* Finally, AFX Exact Match Address Registers */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ ++ /* VLAN id set to 0 */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + ++ (port << 12)), 0); ++ } ++} ++ ++/* ++ * Actual Routine to reset the adapter when the timeout occurred ++ */ ++static void titan_ge_tx_timeout_task(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ int port = titan_ge_eth->port_num; ++ ++ printk("Titan GE: Transmit timed out. Resetting ... \n"); ++ ++ /* Dump debug info */ ++ printk(KERN_ERR "TRTG cause : %x \n", ++ TITAN_GE_READ(0x100c + (port << 12))); ++ ++ /* Fix this for the other ports */ ++ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c)); ++ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040)); ++ printk(KERN_ERR "XDMA GDI ERROR : %x \n", ++ TITAN_GE_READ(0x5008 + (port << 8))); ++ printk(KERN_ERR "CHANNEL ERROR: %x \n", ++ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT ++ + (port << 8))); ++ ++ netif_device_detach(netdev); ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ titan_ge_port_start(netdev, titan_ge_eth); ++ netif_device_attach(netdev); ++} ++ ++/* ++ * Change the MTU of the Ethernet Device ++ */ ++static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned long flags; ++ ++ if ((new_mtu > 9500) || (new_mtu < 64)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ netdev->mtu = new_mtu; ++ ++ /* Now we have to reopen the interface so that SKBs with the new ++ * size will be allocated */ ++ ++ if (netif_running(netdev)) { ++ titan_ge_eth_stop(netdev); ++ ++ if (titan_ge_eth_open(netdev) != TITAN_OK) { ++ printk(KERN_ERR ++ "%s: Fatal error on opening device\n", ++ netdev->name); ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ return -1; ++ } ++ } ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ return 0; ++} ++ ++/* ++ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line ++ * only. Once an interrupt is triggered, figure out the port and then check ++ * the channel. ++ */ ++static irqreturn_t titan_ge_int_handler(int irq, void *dev_id) ++{ ++ struct net_device *netdev = (struct net_device *) dev_id; ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int reg_data; ++ unsigned int eth_int_cause_error = 0, is; ++ unsigned long eth_int_cause1; ++ int err = 0; ++#ifdef CONFIG_SMP ++ unsigned long eth_int_cause2; ++#endif ++ ++ /* Ack the CPU interrupt */ ++ switch (port_num) { ++ case 0: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is); ++#endif ++ break; ++ ++ case 1: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is); ++#endif ++ break; ++ ++ case 2: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is); ++#endif ++ } ++ ++ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); ++#ifdef CONFIG_SMP ++ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B); ++#endif ++ ++ /* Spurious interrupt */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) { ++#else ++ if (eth_int_cause1 == 0) { ++#endif ++ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT + ++ (port_num << 8)); ++ ++ if (eth_int_cause_error == 0) ++ return IRQ_NONE; ++ } ++ ++ /* Handle Tx first. No need to ack interrupts */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 & 0x20202) || ++ (eth_int_cause2 & 0x20202) ) ++#else ++ if (eth_int_cause1 & 0x20202) ++#endif ++ titan_ge_free_tx_queue(titan_ge_eth); ++ ++ /* Handle the Rx next */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 & 0x10101) || ++ (eth_int_cause2 & 0x10101)) { ++#else ++ if (eth_int_cause1 & 0x10101) { ++#endif ++ if (netif_rx_schedule_prep(netdev)) { ++ unsigned int ack; ++ ++ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ /* Disable Tx and Rx both */ ++ if (port_num == 0) ++ ack &= ~(0x3); ++ if (port_num == 1) ++ ack &= ~(0x300); ++ ++ if (port_num == 2) ++ ack &= ~(0x30000); ++ ++ /* Interrupts have been disabled */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack); ++ ++ __netif_rx_schedule(netdev); ++ } ++ } ++ ++ /* Handle error interrupts */ ++ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) { ++ printk(KERN_ERR ++ "XDMA Channel Error : %x on port %d\n", ++ eth_int_cause_error, port_num); ++ ++ printk(KERN_ERR ++ "XDMA GDI Hardware error : %x on port %d\n", ++ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num); ++ ++ printk(KERN_ERR ++ "XDMA currently has %d Rx descriptors \n", ++ TITAN_GE_READ(0x5048 + (port_num << 8))); ++ ++ printk(KERN_ERR ++ "XDMA currently has prefetcted %d Rx descriptors \n", ++ TITAN_GE_READ(0x505c + (port_num << 8))); ++ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + ++ (port_num << 8)), eth_int_cause_error); ++ } ++ ++ /* ++ * PHY interrupt to inform abt the changes. Reading the ++ * PHY Status register will clear the interrupt ++ */ ++ if ((!(eth_int_cause1 & 0x30303)) && ++ (eth_int_cause_error == 0)) { ++ err = ++ titan_ge_mdio_read(port_num, ++ TITAN_GE_MDIO_PHY_IS, ®_data); ++ ++ if (reg_data & 0x0400) { ++ /* Link status change */ ++ titan_ge_mdio_read(port_num, ++ TITAN_GE_MDIO_PHY_STATUS, ®_data); ++ if (!(reg_data & 0x0400)) { ++ /* Link is down */ ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ } else { ++ /* Link is up */ ++ netif_carrier_on(netdev); ++ netif_wake_queue(netdev); ++ ++ /* Enable the queue */ ++ titan_ge_enable_tx(port_num); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Multicast and Promiscuous mode set. The ++ * set_multi entry point is called whenever the ++ * multicast address list or the network interface ++ * flags are updated. ++ */ ++static void titan_ge_set_multi(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned long reg_data; ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + ++ (port_num << 12)); ++ ++ if (netdev->flags & IFF_PROMISC) { ++ reg_data |= 0x2; ++ } ++ else if (netdev->flags & IFF_ALLMULTI) { ++ reg_data |= 0x01; ++ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */ ++ } ++ else { ++ reg_data = 0x2; ++ } ++ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + ++ (port_num << 12)), reg_data); ++ if (reg_data & 0x01) { ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI + ++ (port_num << 12)), 0xffff); ++ } ++} ++ ++/* ++ * Open the network device ++ */ ++static int titan_ge_open(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num; ++ int retval; ++ ++ retval = request_irq(irq, titan_ge_int_handler, ++ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev); ++ ++ if (retval != 0) { ++ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n"); ++ return -1; ++ } ++ ++ netdev->irq = irq; ++ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num); ++ ++ spin_lock_irq(&(titan_ge_eth->lock)); ++ ++ if (titan_ge_eth_open(netdev) != TITAN_OK) { ++ spin_unlock_irq(&(titan_ge_eth->lock)); ++ printk("%s: Error opening interface \n", netdev->name); ++ free_irq(netdev->irq, netdev); ++ return -EBUSY; ++ } ++ ++ spin_unlock_irq(&(titan_ge_eth->lock)); ++ ++ return 0; ++} ++ ++/* ++ * Allocate the SKBs for the Rx ring. Also used ++ * for refilling the queue ++ */ ++static int titan_ge_rx_task(struct net_device *netdev, ++ titan_ge_port_info *titan_ge_port) ++{ ++ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev; ++ volatile titan_ge_rx_desc *rx_desc; ++ struct sk_buff *skb; ++ int rx_used_desc; ++ int count = 0; ++ ++ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) { ++ ++ /* First try to get the skb from the recycler */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC); ++#else ++ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC); ++#endif ++ if (unlikely(!skb)) { ++ /* OOM, set the flag */ ++ printk("OOM \n"); ++ oom_flag = 1; ++ break; ++ } ++ count++; ++ skb->dev = netdev; ++ ++ titan_ge_port->rx_ring_skbs++; ++ ++ rx_used_desc = titan_ge_port->rx_used_desc_q; ++ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]); ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ rx_desc->buffer_addr = dma_map_single(device, skb->data, ++ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE); ++#else ++ rx_desc->buffer_addr = dma_map_single(device, skb->data, ++ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE); ++#endif ++ ++ titan_ge_port->rx_skb[rx_used_desc] = skb; ++ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED; ++ ++ titan_ge_port->rx_used_desc_q = ++ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE; ++ } ++ ++ return count; ++} ++ ++/* ++ * Actual init of the Tital GE port. There is one register for ++ * the channel configuration ++ */ ++static void titan_port_init(struct net_device *netdev, ++ titan_ge_port_info * titan_ge_eth) ++{ ++ unsigned long reg_data; ++ ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ ++ /* First reset the TMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data |= 0x80000000; ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ udelay(30); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data &= ~(0xc0000000); ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ /* Now reset the RMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data |= 0x00080000; ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ udelay(30); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data &= ~(0x000c0000); ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++} ++ ++/* ++ * Start the port. All the hardware specific configuration ++ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX ++ * go here ++ */ ++static int titan_ge_port_start(struct net_device *netdev, ++ titan_ge_port_info * titan_port) ++{ ++ volatile unsigned long reg_data, reg_data1; ++ int port_num = titan_port->port_num; ++ int count = 0; ++ unsigned long reg_data_1; ++ ++ if (config_done == 0) { ++ reg_data = TITAN_GE_READ(0x0004); ++ reg_data |= 0x100; ++ TITAN_GE_WRITE(0x0004, reg_data); ++ ++ reg_data &= ~(0x100); ++ TITAN_GE_WRITE(0x0004, reg_data); ++ ++ /* Turn on GMII/MII mode and turn off TBI mode */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1); ++ reg_data |= 0x00000700; ++ reg_data &= ~(0x00800000); /* Fencing */ ++ ++ TITAN_GE_WRITE(0x000c, 0x00001100); ++ ++ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data); ++ ++ /* Set the CPU Resource Limit register */ ++ TITAN_GE_WRITE(0x00f8, 0x8); ++ ++ /* Be conservative when using the BIU buffers */ ++ TITAN_GE_WRITE(0x0068, 0x4); ++ } ++ ++ titan_port->tx_threshold = 0; ++ titan_port->rx_threshold = 0; ++ ++ /* We need to write the descriptors for Tx and Rx */ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)), ++ (unsigned long) titan_port->tx_dma); ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)), ++ (unsigned long) titan_port->rx_dma); ++ ++ if (config_done == 0) { ++ /* Step 1: XDMA config */ ++ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG); ++ reg_data &= ~(0x80000000); /* clear reset */ ++ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */ ++ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */ ++ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */ ++ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */ ++ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data); ++ } ++ ++ /* IR register for the XDMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)); ++ reg_data |= 0x80068000; /* No Rx_OOD */ ++ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data); ++ ++ /* Start the Tx and Rx XDMA controller */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)); ++ reg_data &= 0x4fffffff; /* Clear tx reset */ ++ reg_data &= 0xfff4ffff; /* Clear rx reset */ ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ reg_data |= 0xa0 | 0x30030000; ++#else ++ reg_data |= 0x40 | 0x20030000; ++#endif ++ ++#ifndef CONFIG_SMP ++ reg_data &= ~(0x10); ++ reg_data |= 0x0f; /* All of the packet */ ++#endif ++ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data); ++ ++ /* Rx desc count */ ++ count = titan_ge_rx_task(netdev, titan_port); ++ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count); ++ count = TITAN_GE_READ(0x5048 + (port_num << 8)); ++ ++ udelay(30); ++ ++ /* ++ * Step 2: Configure the SDQPF, i.e. FIFO ++ */ ++ if (config_done == 0) { ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); ++ reg_data = 0x1; ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ reg_data &= ~(0x1); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); ++ reg_data = 0x1; ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ reg_data &= ~(0x1); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ } ++ /* ++ * Enable RX FIFO 0, 4 and 8 ++ */ ++ if (port_num == 0) { ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10); ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4844); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x4844, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ reg_data |= (0xff << 10); ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4944); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x4944, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ } ++ ++ if (port_num == 1) { ++ reg_data = TITAN_GE_READ(0x4870); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (0xff + 1); ++ ++ TITAN_GE_WRITE(0x4870, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4874); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x4874, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4870, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x494c); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x494c, reg_data); ++ reg_data |= (0xff << 10) | (0xff + 1); ++ TITAN_GE_WRITE(0x494c, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4950); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x4950, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x494c, reg_data); ++ } ++ ++ /* ++ * Titan 1.2 revision does support port #2 ++ */ ++ if (port_num == 2) { ++ /* ++ * Put the descriptors in the SRAM ++ */ ++ reg_data = TITAN_GE_READ(0x48a0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x48a4); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x48a4, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x4958); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ TITAN_GE_WRITE(0x4958, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x495c); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x495c, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ } ++ ++ if (port_num == 2) { ++ reg_data = TITAN_GE_READ(0x48a0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x48a4); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x48a4, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x4958); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ TITAN_GE_WRITE(0x4958, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x495c); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x495c, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ } ++ ++ /* ++ * Step 3: TRTG block enable ++ */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12)); ++ ++ /* ++ * This is the 1.2 revision of the chip. It has fix for the ++ * IP header alignment. Now, the IP header begins at an ++ * aligned address and this wont need an extra copy in the ++ * driver. This performance drawback existed in the previous ++ * versions of the silicon ++ */ ++ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12)); ++ reg_data_1 |= 0x40000000; ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ reg_data_1 |= 0x04000000; ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ mdelay(5); ++ ++ reg_data_1 &= ~(0x04000000); ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ mdelay(5); ++ ++ reg_data |= 0x0001; ++ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data); ++ ++ /* ++ * Step 4: Start the Tx activity ++ */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197); ++#ifdef TITAN_GE_JUMBO_FRAMES ++ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000); ++#endif ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); ++ reg_data |= 0x0001; /* Enable TMAC */ ++ reg_data |= 0x6c70; /* PAUSE also set */ ++ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ udelay(30); ++ ++ /* Destination Address drop bit */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)); ++ reg_data |= 0x218; /* DA_DROP bit and pause */ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data); ++ ++ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3); ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000); ++#endif ++ /* Start the Rx activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); ++ reg_data |= 0x0001; /* RMAC Enable */ ++ reg_data |= 0x0010; /* CRC Check enable */ ++ reg_data |= 0x0040; /* Min Frame check enable */ ++ reg_data |= 0x4400; /* Max Frame check enable */ ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ udelay(30); ++ ++ /* ++ * Enable the Interrupts for Tx and Rx ++ */ ++ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ ++ if (port_num == 0) { ++ reg_data1 |= 0x3; ++#ifdef CONFIG_SMP ++ TITAN_GE_WRITE(0x0038, 0x003); ++#else ++ TITAN_GE_WRITE(0x0038, 0x303); ++#endif ++ } ++ ++ if (port_num == 1) { ++ reg_data1 |= 0x300; ++ } ++ ++ if (port_num == 2) ++ reg_data1 |= 0x30000; ++ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1); ++ TITAN_GE_WRITE(0x003c, 0x300); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */ ++ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */ ++ } ++ ++ /* Priority */ ++ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12)); ++ reg_data &= ~(0x00f00000); ++ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data); ++ ++ /* Step 5: GMII config */ ++ titan_ge_gmii_config(port_num); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(0x1a80, 0); ++ config_done = 1; ++ } ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Function to queue the packet for the Ethernet device ++ */ ++static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth, ++ struct sk_buff * skb) ++{ ++ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev; ++ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q; ++ volatile titan_ge_tx_desc *tx_curr; ++ int port_num = titan_ge_eth->port_num; ++ ++ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]); ++ tx_curr->buffer_addr = ++ dma_map_single(device, skb->data, skb_headlen(skb), ++ DMA_TO_DEVICE); ++ ++ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb; ++ tx_curr->buffer_len = skb_headlen(skb); ++ ++ /* Last descriptor enables interrupt and changes ownership */ ++ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5); ++ ++ /* Kick the XDMA to start the transfer from memory to the FIFO */ ++ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1); ++ ++ /* Current descriptor updated */ ++ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE; ++ ++ /* Prefetch the next descriptor */ ++ prefetch((const void *) ++ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]); ++} ++ ++/* ++ * Actually does the open of the Ethernet device ++ */ ++static int titan_ge_eth_open(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ struct device *device = &titan_ge_device[port_num]->dev; ++ unsigned long reg_data; ++ unsigned int phy_reg; ++ int err = 0; ++ ++ /* Stop the Rx activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ /* Clear the port interrupts */ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0); ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0); ++ } ++ ++ /* Set the MAC Address */ ++ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); ++ ++ if (config_done == 0) ++ titan_port_init(netdev, titan_ge_eth); ++ ++ titan_ge_update_afx(titan_ge_eth); ++ ++ /* Allocate the Tx ring now */ ++ titan_ge_eth->tx_ring_skbs = 0; ++ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE; ++ ++ /* Allocate space in the SRAM for the descriptors */ ++ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *) ++ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num); ++ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num; ++ ++ if (!titan_ge_eth->tx_desc_area) { ++ printk(KERN_ERR ++ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n", ++ netdev->name, TITAN_TX_RING_BYTES, port_num); ++ return -ENOMEM; ++ } ++ ++ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size); ++ ++ /* Now initialize the Tx descriptor ring */ ++ titan_ge_init_tx_desc_ring(titan_ge_eth, ++ titan_ge_eth->tx_ring_size, ++ (unsigned long) titan_ge_eth->tx_desc_area, ++ (unsigned long) titan_ge_eth->tx_dma); ++ ++ /* Allocate the Rx ring now */ ++ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE; ++ titan_ge_eth->rx_ring_skbs = 0; ++ ++ titan_ge_eth->rx_desc_area = ++ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num); ++ ++ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num; ++ ++ if (!titan_ge_eth->rx_desc_area) { ++ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", ++ netdev->name, TITAN_RX_RING_BYTES); ++ ++ printk(KERN_ERR "%s: Freeing previously allocated TX queues...", ++ netdev->name); ++ ++ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size, ++ (void *) titan_ge_eth->tx_desc_area, ++ titan_ge_eth->tx_dma); ++ ++ return -ENOMEM; ++ } ++ ++ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size); ++ ++ /* Now initialize the Rx ring */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ if ((titan_ge_init_rx_desc_ring ++ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE, ++ (unsigned long) titan_ge_eth->rx_desc_area, 0, ++ (unsigned long) titan_ge_eth->rx_dma)) == 0) ++#else ++ if ((titan_ge_init_rx_desc_ring ++ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE, ++ (unsigned long) titan_ge_eth->rx_desc_area, 0, ++ (unsigned long) titan_ge_eth->rx_dma)) == 0) ++#endif ++ panic("%s: Error initializing RX Ring\n", netdev->name); ++ ++ /* Fill the Rx ring with the SKBs */ ++ titan_ge_port_start(netdev, titan_ge_eth); ++ ++ /* ++ * Check if Interrupt Coalscing needs to be turned on. The ++ * values specified in the register is multiplied by ++ * (8 x 64 nanoseconds) to determine when an interrupt should ++ * be sent to the CPU. ++ */ ++ ++ if (TITAN_GE_TX_COAL) { ++ titan_ge_eth->tx_int_coal = ++ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num); ++ } ++ ++ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); ++ if (err == TITAN_GE_MDIO_ERROR) { ++ printk(KERN_ERR ++ "Could not read PHY control register 0x11 \n"); ++ return TITAN_ERROR; ++ } ++ if (!(phy_reg & 0x0400)) { ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ return TITAN_ERROR; ++ } else { ++ netif_carrier_on(netdev); ++ netif_start_queue(netdev); ++ } ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Queue the packet for Tx. Currently no support for zero copy, ++ * checksum offload and Scatter Gather. The chip does support ++ * Scatter Gather only. But, that wont help here since zero copy ++ * requires support for Tx checksumming also. ++ */ ++int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned long flags; ++ struct net_device_stats *stats; ++//printk("titan_ge_start_xmit\n"); ++ ++ stats = &titan_ge_eth->stats; ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <= ++ (skb_shinfo(skb)->nr_frags + 1)) { ++ netif_stop_queue(netdev); ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ printk(KERN_ERR "Tx OOD \n"); ++ return 1; ++ } ++ ++ titan_ge_tx_queue(titan_ge_eth, skb); ++ titan_ge_eth->tx_ring_skbs++; ++ ++ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) { ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ titan_ge_free_tx_queue(titan_ge_eth); ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ } ++ ++ stats->tx_bytes += skb->len; ++ stats->tx_packets++; ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ netdev->trans_start = jiffies; ++ ++ return 0; ++} ++ ++/* ++ * Actually does the Rx. Rx side checksumming supported. ++ */ ++static int titan_ge_rx(struct net_device *netdev, int port_num, ++ titan_ge_port_info * titan_ge_port, ++ titan_ge_packet * packet) ++{ ++ int rx_curr_desc, rx_used_desc; ++ volatile titan_ge_rx_desc *rx_desc; ++ ++ rx_curr_desc = titan_ge_port->rx_curr_desc_q; ++ rx_used_desc = titan_ge_port->rx_used_desc_q; ++ ++ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) ++ return TITAN_ERROR; ++ ++ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]); ++ ++ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) ++ return TITAN_ERROR; ++ ++ packet->skb = titan_ge_port->rx_skb[rx_curr_desc]; ++ packet->len = (rx_desc->cmd_sts & 0x7fff); ++ ++ /* ++ * At this point, we dont know if the checksumming ++ * actually helps relieve CPU. So, keep it for ++ * port 0 only ++ */ ++ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16); ++ packet->cmd_sts = rx_desc->cmd_sts; ++ ++ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE; ++ ++ /* Prefetch the next descriptor */ ++ prefetch((const void *) ++ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Free the Tx queue of the used SKBs ++ */ ++static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth) ++{ ++ unsigned long flags; ++ ++ /* Take the lock */ ++ spin_lock_irqsave(&(titan_ge_eth->lock), flags); ++ ++ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) ++ if (titan_ge_eth->tx_ring_skbs != 1) ++ titan_ge_eth->tx_ring_skbs--; ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Threshold beyond which we do the cleaning of ++ * Tx queue and new allocation for the Rx ++ * queue ++ */ ++#define TX_THRESHOLD 4 ++#define RX_THRESHOLD 10 ++ ++/* ++ * Receive the packets and send it to the kernel. ++ */ ++static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ titan_ge_packet packet; ++ struct net_device_stats *stats; ++ struct sk_buff *skb; ++ unsigned long received_packets = 0; ++ unsigned int ack; ++ ++ stats = &titan_ge_eth->stats; ++ ++ while ((--max) ++ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) { ++ skb = (struct sk_buff *) packet.skb; ++ ++ titan_ge_eth->rx_ring_skbs--; ++ ++ if (--titan_ge_eth->rx_work_limit < 0) ++ break; ++ received_packets++; ++ ++ stats->rx_packets++; ++ stats->rx_bytes += packet.len; ++ ++ if ((packet.cmd_sts & TITAN_GE_RX_PERR) || ++ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) || ++ (packet.cmd_sts & TITAN_GE_RX_TRUNC) || ++ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) { ++ stats->rx_dropped++; ++ dev_kfree_skb_any(skb); ++ ++ continue; ++ } ++ /* ++ * Either support fast path or slow path. Decision ++ * making can really slow down the performance. The ++ * idea is to cut down the number of checks and improve ++ * the fastpath. ++ */ ++ ++ skb_put(skb, packet.len - 2); ++ ++ /* ++ * Increment data pointer by two since thats where ++ * the MAC starts ++ */ ++ skb_reserve(skb, 2); ++ skb->protocol = eth_type_trans(skb, netdev); ++ netif_receive_skb(skb); ++ ++ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) { ++ ack = titan_ge_rx_task(netdev, titan_ge_eth); ++ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack); ++ titan_ge_eth->rx_threshold = 0; ++ } else ++ titan_ge_eth->rx_threshold++; ++ ++ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) { ++ titan_ge_eth->tx_threshold = 0; ++ titan_ge_free_tx_queue(titan_ge_eth); ++ } ++ else ++ titan_ge_eth->tx_threshold++; ++ ++ } ++ return received_packets; ++} ++ ++ ++/* ++ * Enable the Rx side interrupts ++ */ ++static void titan_ge_enable_int(unsigned int port_num, ++ titan_ge_port_info *titan_ge_eth, ++ struct net_device *netdev) ++{ ++ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ ++ if (port_num == 0) ++ reg_data |= 0x3; ++ if (port_num == 1) ++ reg_data |= 0x300; ++ if (port_num == 2) ++ reg_data |= 0x30000; ++ ++ /* Re-enable interrupts */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data); ++} ++ ++/* ++ * Main function to handle the polling for Rx side NAPI. ++ * Receive interrupts have been disabled at this point. ++ * The poll schedules the transmit followed by receive. ++ */ ++static int titan_ge_poll(struct net_device *netdev, int *budget) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ int port_num = titan_ge_eth->port_num; ++ int work_done = 0; ++ unsigned long flags, status; ++ ++ titan_ge_eth->rx_work_limit = *budget; ++ if (titan_ge_eth->rx_work_limit > netdev->quota) ++ titan_ge_eth->rx_work_limit = netdev->quota; ++ ++ do { ++ /* Do the transmit cleaning work here */ ++ titan_ge_free_tx_queue(titan_ge_eth); ++ ++ /* Ack the Rx interrupts */ ++ if (port_num == 0) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3); ++ if (port_num == 1) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300); ++ if (port_num == 2) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000); ++ ++ work_done += titan_ge_receive_queue(netdev, 0); ++ ++ /* Out of quota and there is work to be done */ ++ if (titan_ge_eth->rx_work_limit < 0) ++ goto not_done; ++ ++ /* Receive alloc_skb could lead to OOM */ ++ if (oom_flag == 1) { ++ oom_flag = 0; ++ goto oom; ++ } ++ ++ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); ++ } while (status & 0x30300); ++ ++ /* If we are here, then no more interrupts to process */ ++ goto done; ++ ++not_done: ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ return 1; ++ ++oom: ++ printk(KERN_ERR "OOM \n"); ++ netif_rx_complete(netdev); ++ return 0; ++ ++done: ++ /* ++ * No more packets on the poll list. Turn the interrupts ++ * back on and we should be able to catch the new ++ * packets in the interrupt handler ++ */ ++ if (!work_done) ++ work_done = 1; ++ ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ /* Remove us from the poll list */ ++ netif_rx_complete(netdev); ++ ++ /* Re-enable interrupts */ ++ titan_ge_enable_int(port_num, titan_ge_eth, netdev); ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * Close the network device ++ */ ++int titan_ge_stop(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ spin_lock_irq(&(titan_ge_eth->lock)); ++ titan_ge_eth_stop(netdev); ++ free_irq(netdev->irq, netdev); ++ spin_unlock_irq(&titan_ge_eth->lock); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Free the Tx ring ++ */ ++static void titan_ge_free_tx_rings(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int curr; ++ unsigned long reg_data; ++ ++ /* Stop the Tx DMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)); ++ reg_data |= 0xc0000000; ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)), reg_data); ++ ++ /* Disable the TMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ for (curr = 0; ++ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE); ++ curr++) { ++ if (titan_ge_eth->tx_skb[curr]) { ++ dev_kfree_skb(titan_ge_eth->tx_skb[curr]); ++ titan_ge_eth->tx_ring_skbs--; ++ } ++ } ++ ++ if (titan_ge_eth->tx_ring_skbs != 0) ++ printk ++ ("%s: Error on Tx descriptor free - could not free %d" ++ " descriptors\n", netdev->name, ++ titan_ge_eth->tx_ring_skbs); ++ ++#ifndef TITAN_RX_RING_IN_SRAM ++ dma_free_coherent(&titan_ge_device[port_num]->dev, ++ titan_ge_eth->tx_desc_area_size, ++ (void *) titan_ge_eth->tx_desc_area, ++ titan_ge_eth->tx_dma); ++#endif ++} ++ ++/* ++ * Free the Rx ring ++ */ ++static void titan_ge_free_rx_rings(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int curr; ++ unsigned long reg_data; ++ ++ /* Stop the Rx DMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)); ++ reg_data |= 0x000c0000; ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)), reg_data); ++ ++ /* Disable the RMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ for (curr = 0; ++ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE); ++ curr++) { ++ if (titan_ge_eth->rx_skb[curr]) { ++ dev_kfree_skb(titan_ge_eth->rx_skb[curr]); ++ titan_ge_eth->rx_ring_skbs--; ++ } ++ } ++ ++ if (titan_ge_eth->rx_ring_skbs != 0) ++ printk(KERN_ERR ++ "%s: Error in freeing Rx Ring. %d skb's still" ++ " stuck in RX Ring - ignoring them\n", netdev->name, ++ titan_ge_eth->rx_ring_skbs); ++ ++#ifndef TITAN_RX_RING_IN_SRAM ++ dma_free_coherent(&titan_ge_device[port_num]->dev, ++ titan_ge_eth->rx_desc_area_size, ++ (void *) titan_ge_eth->rx_desc_area, ++ titan_ge_eth->rx_dma); ++#endif ++} ++ ++/* ++ * Actually does the stop of the Ethernet device ++ */ ++static void titan_ge_eth_stop(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ netif_stop_queue(netdev); ++ ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ ++ titan_ge_free_tx_rings(netdev); ++ titan_ge_free_rx_rings(netdev); ++ ++ /* Disable the Tx and Rx Interrupts for all channels */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0); ++} ++ ++/* ++ * Update the MAC address. Note that we have to write the ++ * address in three station registers, 16 bits each. And this ++ * has to be done for TMAC and RMAC ++ */ ++static void titan_ge_update_mac_address(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ u8 p_addr[6]; ++ ++ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); ++ memcpy(p_addr, netdev->dev_addr, 6); ++ ++ /* Update the Address Filtering Match tables */ ++ titan_ge_update_afx(titan_ge_eth); ++ ++ printk("Station MAC : %d %d %d %d %d %d \n", ++ p_addr[5], p_addr[4], p_addr[3], ++ p_addr[2], p_addr[1], p_addr[0]); ++ ++ /* Set the MAC address here for TMAC and RMAC */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++} ++ ++/* ++ * Set the MAC address of the Ethernet device ++ */ ++static int titan_ge_set_mac_address(struct net_device *dev, void *addr) ++{ ++ titan_ge_port_info *tp = netdev_priv(dev); ++ struct sockaddr *sa = addr; ++ ++ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); ++ ++ spin_lock_irq(&tp->lock); ++ titan_ge_update_mac_address(dev); ++ spin_unlock_irq(&tp->lock); ++ ++ return 0; ++} ++ ++/* ++ * Get the Ethernet device stats ++ */ ++static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ return &titan_ge_eth->stats; ++} ++ ++/* ++ * Initialize the Rx descriptor ring for the Titan Ge ++ */ ++static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port, ++ int rx_desc_num, ++ int rx_buff_size, ++ unsigned long rx_desc_base_addr, ++ unsigned long rx_buff_base_addr, ++ unsigned long rx_dma) ++{ ++ volatile titan_ge_rx_desc *rx_desc; ++ unsigned long buffer_addr; ++ int index; ++ unsigned long titan_ge_rx_desc_bus = rx_dma; ++ ++ buffer_addr = rx_buff_base_addr; ++ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr; ++ ++ /* Check alignment */ ++ if (rx_buff_base_addr & 0xF) ++ return 0; ++ ++ /* Check Rx buffer size */ ++ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER)) ++ return 0; ++ ++ /* 64-bit alignment ++ if ((rx_buff_base_addr + rx_buff_size) & 0x7) ++ return 0; */ ++ ++ /* Initialize the Rx desc ring */ ++ for (index = 0; index < rx_desc_num; index++) { ++ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc); ++ rx_desc[index].cmd_sts = 0; ++ rx_desc[index].buffer_addr = buffer_addr; ++ titan_eth_port->rx_skb[index] = NULL; ++ buffer_addr += rx_buff_size; ++ } ++ ++ titan_eth_port->rx_curr_desc_q = 0; ++ titan_eth_port->rx_used_desc_q = 0; ++ ++ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr; ++ titan_eth_port->rx_desc_area_size = ++ rx_desc_num * sizeof(titan_ge_rx_desc); ++ ++ titan_eth_port->rx_dma = rx_dma; ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Initialize the Tx descriptor ring. Descriptors in the SRAM ++ */ ++static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port, ++ int tx_desc_num, ++ unsigned long tx_desc_base_addr, ++ unsigned long tx_dma) ++{ ++ titan_ge_tx_desc *tx_desc; ++ int index; ++ unsigned long titan_ge_tx_desc_bus = tx_dma; ++ ++ if (tx_desc_base_addr & 0xF) ++ return 0; ++ ++ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr; ++ ++ for (index = 0; index < tx_desc_num; index++) { ++ titan_ge_port->tx_dma_array[index] = ++ (dma_addr_t) titan_ge_tx_desc_bus; ++ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc); ++ tx_desc[index].cmd_sts = 0x0000; ++ tx_desc[index].buffer_len = 0; ++ tx_desc[index].buffer_addr = 0x00000000; ++ titan_ge_port->tx_skb[index] = NULL; ++ } ++ ++ titan_ge_port->tx_curr_desc_q = 0; ++ titan_ge_port->tx_used_desc_q = 0; ++ ++ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr; ++ titan_ge_port->tx_desc_area_size = ++ tx_desc_num * sizeof(titan_ge_tx_desc); ++ ++ titan_ge_port->tx_dma = tx_dma; ++ return TITAN_OK; ++} ++ ++/* ++ * Initialize the device as an Ethernet device ++ */ ++static int __init titan_ge_probe(struct device *device) ++{ ++ titan_ge_port_info *titan_ge_eth; ++ struct net_device *netdev; ++ int port = to_platform_device(device)->id; ++ int err; ++ ++ netdev = alloc_etherdev(sizeof(titan_ge_port_info)); ++ if (!netdev) { ++ err = -ENODEV; ++ goto out; ++ } ++ ++ netdev->open = titan_ge_open; ++ netdev->stop = titan_ge_stop; ++ netdev->hard_start_xmit = titan_ge_start_xmit; ++ netdev->get_stats = titan_ge_get_stats; ++ netdev->set_multicast_list = titan_ge_set_multi; ++ netdev->set_mac_address = titan_ge_set_mac_address; ++ ++ /* Tx timeout */ ++ netdev->tx_timeout = titan_ge_tx_timeout; ++ netdev->watchdog_timeo = 2 * HZ; ++ ++ /* Set these to very high values */ ++ netdev->poll = titan_ge_poll; ++ netdev->weight = 64; ++ ++ netdev->tx_queue_len = TITAN_GE_TX_QUEUE; ++ netif_carrier_off(netdev); ++ netdev->base_addr = 0; ++ ++ netdev->change_mtu = titan_ge_change_mtu; ++ ++ titan_ge_eth = netdev_priv(netdev); ++ /* Allocation of memory for the driver structures */ ++ ++ titan_ge_eth->port_num = port; ++ ++ /* Configure the Tx timeout handler */ ++ INIT_WORK(&titan_ge_eth->tx_timeout_task, ++ (void (*)(void *)) titan_ge_tx_timeout_task, netdev); ++ ++ spin_lock_init(&titan_ge_eth->lock); ++ ++ /* set MAC addresses */ ++ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6); ++ netdev->dev_addr[5] += port; ++ ++ err = register_netdev(netdev); ++ ++ if (err) ++ goto out_free_netdev; ++ ++ printk(KERN_NOTICE ++ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", ++ netdev->name, port, netdev->dev_addr[0], ++ netdev->dev_addr[1], netdev->dev_addr[2], ++ netdev->dev_addr[3], netdev->dev_addr[4], ++ netdev->dev_addr[5]); ++ ++ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n"); ++ ++ return 0; ++ ++out_free_netdev: ++ kfree(netdev); ++ ++out: ++ return err; ++} ++ ++static void __devexit titan_device_remove(struct device *device) ++{ ++} ++ ++/* ++ * Reset the Ethernet port ++ */ ++static void titan_ge_port_reset(unsigned int port_num) ++{ ++ unsigned int reg_data; ++ ++ /* Stop the Tx port activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x0001); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ /* Stop the Rx port activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x0001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ return; ++} ++ ++/* ++ * Return the Tx desc after use by the XDMA ++ */ ++static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port) ++{ ++ int tx_desc_used; ++ struct sk_buff *skb; ++ ++ tx_desc_used = titan_ge_eth->tx_used_desc_q; ++ ++ /* return right away */ ++ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q) ++ return TITAN_ERROR; ++ ++ /* Now the critical stuff */ ++ skb = titan_ge_eth->tx_skb[tx_desc_used]; ++ ++ dev_kfree_skb_any(skb); ++ ++ titan_ge_eth->tx_skb[tx_desc_used] = NULL; ++ titan_ge_eth->tx_used_desc_q = ++ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE; ++ ++ return 0; ++} ++ ++/* ++ * Coalescing for the Tx path ++ */ ++static unsigned long titan_ge_tx_coal(unsigned long delay, int port) ++{ ++ unsigned long rx_delay; ++ ++ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING); ++ delay = (delay << 16) | rx_delay; ++ ++ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay); ++ TITAN_GE_WRITE(0x5038, delay); ++ ++ return delay; ++} ++ ++static struct device_driver titan_soc_driver = { ++ .name = titan_string, ++ .bus = &platform_bus_type, ++ .probe = titan_ge_probe, ++ .remove = __devexit_p(titan_device_remove), ++}; ++ ++static void titan_platform_release (struct device *device) ++{ ++ struct platform_device *pldev; ++ ++ /* free device */ ++ pldev = to_platform_device (device); ++ kfree (pldev); ++} ++ ++/* ++ * Register the Titan GE with the kernel ++ */ ++static int __init titan_ge_init_module(void) ++{ ++ struct platform_device *pldev; ++ unsigned int version, device; ++ int i; ++ ++ printk(KERN_NOTICE ++ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n"); ++ ++ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE); ++ if (!titan_ge_base) { ++ printk("Mapping Titan GE failed\n"); ++ goto out; ++ } ++ ++ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID); ++ version = (device & 0x000f0000) >> 16; ++ device &= 0x0000ffff; ++ ++ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version); ++ ++#ifdef TITAN_RX_RING_IN_SRAM ++ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE, ++ TITAN_SRAM_SIZE); ++ if (!titan_ge_sram) { ++ printk("Mapping Titan SRAM failed\n"); ++ goto out_unmap_ge; ++ } ++#endif ++ ++ if (driver_register(&titan_soc_driver)) { ++ printk(KERN_ERR "Driver registration failed\n"); ++ goto out_unmap_sram; ++ } ++ ++ for (i = 0; i < 3; i++) { ++ titan_ge_device[i] = NULL; ++ ++ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) ++ continue; ++ ++ memset (pldev, 0, sizeof (*pldev)); ++ pldev->name = titan_string; ++ pldev->id = i; ++ pldev->dev.release = titan_platform_release; ++ titan_ge_device[i] = pldev; ++ ++ if (platform_device_register (pldev)) { ++ kfree (pldev); ++ titan_ge_device[i] = NULL; ++ continue; ++ } ++ ++ if (!pldev->dev.driver) { ++ /* ++ * The driver was not bound to this device, there was ++ * no hardware at this address. Unregister it, as the ++ * release fuction will take care of freeing the ++ * allocated structure ++ */ ++ titan_ge_device[i] = NULL; ++ platform_device_unregister (pldev); ++ } ++ } ++ ++ return 0; ++ ++out_unmap_sram: ++ iounmap((void *)titan_ge_sram); ++ ++out_unmap_ge: ++ iounmap((void *)titan_ge_base); ++ ++out: ++ return -ENOMEM; ++} ++ ++/* ++ * Unregister the Titan GE from the kernel ++ */ ++static void __exit titan_ge_cleanup_module(void) ++{ ++ int i; ++ ++ driver_unregister(&titan_soc_driver); ++ ++ for (i = 0; i < 3; i++) { ++ if (titan_ge_device[i]) { ++ platform_device_unregister (titan_ge_device[i]); ++ titan_ge_device[i] = NULL; ++ } ++ } ++ ++ iounmap((void *)titan_ge_sram); ++ iounmap((void *)titan_ge_base); ++} ++ ++MODULE_AUTHOR("Manish Lachwani "); ++MODULE_DESCRIPTION("Titan GE Ethernet driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(titan_ge_init_module); ++module_exit(titan_ge_cleanup_module); +diff --git a/drivers/net/titan_ge.h b/drivers/net/titan_ge.h +new file mode 100644 +index 0000000..3719f78 +--- /dev/null ++++ b/drivers/net/titan_ge.h +@@ -0,0 +1,415 @@ ++#ifndef _TITAN_GE_H_ ++#define _TITAN_GE_H_ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * These functions should be later moved to a more generic location since there ++ * will be others accessing it also ++ */ ++ ++/* ++ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in ++ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 ++ * register. ++ */ ++ ++#define TITAN_GE_BASE 0xfe000000UL ++#define TITAN_GE_SIZE 0x10000UL ++ ++extern unsigned long titan_ge_base; ++ ++#define TITAN_GE_WRITE(offset, data) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) = (data) ++ ++#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset)) ++ ++#ifndef msec_delay ++#define msec_delay(x) do { if(in_interrupt()) { \ ++ /* Don't mdelay in interrupt context! */ \ ++ BUG(); \ ++ } else { \ ++ set_current_state(TASK_UNINTERRUPTIBLE); \ ++ schedule_timeout((x * HZ)/1000); \ ++ } } while(0) ++#endif ++ ++#define TITAN_GE_PORT_0 ++ ++#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4) ++#define TITAN_SRAM_SIZE 0x2000UL ++ ++/* ++ * We may need these constants ++ */ ++#define TITAN_BIT0 0x00000001 ++#define TITAN_BIT1 0x00000002 ++#define TITAN_BIT2 0x00000004 ++#define TITAN_BIT3 0x00000008 ++#define TITAN_BIT4 0x00000010 ++#define TITAN_BIT5 0x00000020 ++#define TITAN_BIT6 0x00000040 ++#define TITAN_BIT7 0x00000080 ++#define TITAN_BIT8 0x00000100 ++#define TITAN_BIT9 0x00000200 ++#define TITAN_BIT10 0x00000400 ++#define TITAN_BIT11 0x00000800 ++#define TITAN_BIT12 0x00001000 ++#define TITAN_BIT13 0x00002000 ++#define TITAN_BIT14 0x00004000 ++#define TITAN_BIT15 0x00008000 ++#define TITAN_BIT16 0x00010000 ++#define TITAN_BIT17 0x00020000 ++#define TITAN_BIT18 0x00040000 ++#define TITAN_BIT19 0x00080000 ++#define TITAN_BIT20 0x00100000 ++#define TITAN_BIT21 0x00200000 ++#define TITAN_BIT22 0x00400000 ++#define TITAN_BIT23 0x00800000 ++#define TITAN_BIT24 0x01000000 ++#define TITAN_BIT25 0x02000000 ++#define TITAN_BIT26 0x04000000 ++#define TITAN_BIT27 0x08000000 ++#define TITAN_BIT28 0x10000000 ++#define TITAN_BIT29 0x20000000 ++#define TITAN_BIT30 0x40000000 ++#define TITAN_BIT31 0x80000000 ++ ++/* Flow Control */ ++#define TITAN_GE_FC_NONE 0x0 ++#define TITAN_GE_FC_FULL 0x1 ++#define TITAN_GE_FC_TX_PAUSE 0x2 ++#define TITAN_GE_FC_RX_PAUSE 0x3 ++ ++/* Duplex Settings */ ++#define TITAN_GE_FULL_DUPLEX 0x1 ++#define TITAN_GE_HALF_DUPLEX 0x2 ++ ++/* Speed settings */ ++#define TITAN_GE_SPEED_1000 0x1 ++#define TITAN_GE_SPEED_100 0x2 ++#define TITAN_GE_SPEED_10 0x3 ++ ++/* Debugging info only */ ++#undef TITAN_DEBUG ++ ++/* Keep the rings in the Titan's SSRAM */ ++#define TITAN_RX_RING_IN_SRAM ++ ++#ifdef CONFIG_64BIT ++#define TITAN_GE_IE_MASK 0xfffffffffb001b64 ++#define TITAN_GE_IE_STATUS 0xfffffffffb001b60 ++#else ++#define TITAN_GE_IE_MASK 0xfb001b64 ++#define TITAN_GE_IE_STATUS 0xfb001b60 ++#endif ++ ++/* Support for Jumbo Frames */ ++#undef TITAN_GE_JUMBO_FRAMES ++ ++/* Rx buffer size */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++#define TITAN_GE_JUMBO_BUFSIZE 9080 ++#else ++#define TITAN_GE_STD_BUFSIZE 1580 ++#endif ++ ++/* ++ * Tx and Rx Interrupt Coalescing parameter. These values are ++ * for 1 Ghz processor. Rx coalescing can be taken care of ++ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing ++ * is not adaptive. Hence, these values need to be adjusted ++ * based on load, CPU speed etc. ++ */ ++#define TITAN_GE_RX_COAL 150 ++#define TITAN_GE_TX_COAL 300 ++ ++#if defined(__BIG_ENDIAN) ++ ++/* Define the Rx descriptor */ ++typedef struct eth_rx_desc { ++ u32 reserved; /* Unused */ ++ u32 buffer_addr; /* CPU buffer address */ ++ u32 cmd_sts; /* Command and Status */ ++ u32 buffer; /* XDMA buffer address */ ++} titan_ge_rx_desc; ++ ++/* Define the Tx descriptor */ ++typedef struct eth_tx_desc { ++ u16 cmd_sts; /* Command, Status and Buffer count */ ++ u16 buffer_len; /* Length of the buffer */ ++ u32 buffer_addr; /* Physical address of the buffer */ ++} titan_ge_tx_desc; ++ ++#elif defined(__LITTLE_ENDIAN) ++ ++/* Define the Rx descriptor */ ++typedef struct eth_rx_desc { ++ u32 buffer_addr; /* CPU buffer address */ ++ u32 reserved; /* Unused */ ++ u32 buffer; /* XDMA buffer address */ ++ u32 cmd_sts; /* Command and Status */ ++} titan_ge_rx_desc; ++ ++/* Define the Tx descriptor */ ++typedef struct eth_tx_desc { ++ u32 buffer_addr; /* Physical address of the buffer */ ++ u16 buffer_len; /* Length of the buffer */ ++ u16 cmd_sts; /* Command, Status and Buffer count */ ++} titan_ge_tx_desc; ++#endif ++ ++/* Default Tx Queue Size */ ++#define TITAN_GE_TX_QUEUE 128 ++#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc)) ++ ++/* Default Rx Queue Size */ ++#define TITAN_GE_RX_QUEUE 64 ++#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc)) ++ ++/* Packet Structure */ ++typedef struct _pkt_info { ++ unsigned int len; ++ unsigned int cmd_sts; ++ unsigned int buffer; ++ struct sk_buff *skb; ++ unsigned int checksum; ++} titan_ge_packet; ++ ++ ++#define PHYS_CNT 3 ++ ++/* Titan Port specific data structure */ ++typedef struct _eth_port_ctrl { ++ unsigned int port_num; ++ u8 port_mac_addr[6]; ++ ++ /* Rx descriptor pointers */ ++ int rx_curr_desc_q, rx_used_desc_q; ++ ++ /* Tx descriptor pointers */ ++ int tx_curr_desc_q, tx_used_desc_q; ++ ++ /* Rx descriptor area */ ++ volatile titan_ge_rx_desc *rx_desc_area; ++ unsigned int rx_desc_area_size; ++ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE]; ++ ++ /* Tx Descriptor area */ ++ volatile titan_ge_tx_desc *tx_desc_area; ++ unsigned int tx_desc_area_size; ++ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE]; ++ ++ /* Timeout task */ ++ struct work_struct tx_timeout_task; ++ ++ /* DMA structures and handles */ ++ dma_addr_t tx_dma; ++ dma_addr_t rx_dma; ++ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE]; ++ ++ /* Device lock */ ++ spinlock_t lock; ++ ++ unsigned int tx_ring_skbs; ++ unsigned int rx_ring_size; ++ unsigned int tx_ring_size; ++ unsigned int rx_ring_skbs; ++ ++ struct net_device_stats stats; ++ ++ /* Tx and Rx coalescing */ ++ unsigned long rx_int_coal; ++ unsigned long tx_int_coal; ++ ++ /* Threshold for replenishing the Rx and Tx rings */ ++ unsigned int tx_threshold; ++ unsigned int rx_threshold; ++ ++ /* NAPI work limit */ ++ unsigned int rx_work_limit; ++} titan_ge_port_info; ++ ++/* Titan specific constants */ ++#define TITAN_ETH_PORT_IRQ 3 ++ ++/* Max Rx buffer */ ++#define TITAN_GE_MAX_RX_BUFFER 65536 ++ ++/* Tx and Rx Error */ ++#define TITAN_GE_ERROR ++ ++/* Rx Descriptor Command and Status */ ++ ++#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */ ++#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */ ++#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */ ++#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */ ++#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */ ++#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */ ++#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */ ++#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */ ++#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */ ++#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */ ++ ++/* Tx Descriptor Command */ ++#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */ ++#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */ ++ ++/* Return Status */ ++#define TITAN_OK 0x1 /* Good Status */ ++#define TITAN_ERROR 0x2 /* Error Status */ ++ ++/* MIB specific register offset */ ++#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */ ++#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */ ++#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */ ++#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */ ++#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */ ++ ++/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */ ++#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040 ++#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050 ++#define TITAN_GE_MSTATX_RXFRAMES 0x0060 ++#define TITAN_GE_MSTATX_RXOCTETS 0x0070 ++#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080 ++#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090 ++#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0 ++#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0 ++#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0 ++#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0 ++#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0 ++#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0 ++#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100 ++#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110 ++#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120 ++#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130 ++#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140 ++#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150 ++#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160 ++#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170 ++#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180 ++#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190 ++#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0 ++#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0 ++#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0 ++#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0 ++#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0 ++#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0 ++#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200 ++#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210 ++#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220 ++#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230 ++#define TITAN_GE_MSTATX_HASHFILTERED 0x0240 ++#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250 ++#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260 ++#define TITAN_GE_MSTATX_TXOCTETS 0x0270 ++#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280 ++#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290 ++#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0 ++#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0 ++#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0 ++#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0 ++#define TITAN_GE_MSTATX_TXMACERROR 0x02E0 ++#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0 ++#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300 ++#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310 ++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320 ++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330 ++#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340 ++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350 ++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360 ++#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370 ++#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380 ++#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390 ++#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0 ++#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0 ++#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0 ++#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0 ++#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0 ++#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0 ++#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400 ++#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410 ++#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420 ++#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430 ++#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440 ++ ++/* Interrupt specific defines */ ++#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */ ++#define TITAN_GE_RESET 0x0004 /* Reset reg */ ++#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */ ++#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */ ++#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */ ++#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/ ++#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/ ++#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */ ++#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */ ++#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/ ++#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */ ++#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/ ++#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */ ++#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */ ++#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */ ++#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */ ++#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */ ++#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */ ++#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */ ++#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */ ++ ++/* Rx MAC defines */ ++#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */ ++#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */ ++#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */ ++#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */ ++#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */ ++#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */ ++#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */ ++ ++/* Tx MAC defines */ ++#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */ ++#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */ ++#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */ ++#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */ ++#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */ ++#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */ ++#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */ ++#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */ ++#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */ ++#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */ ++ ++/* GMII register */ ++#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */ ++#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */ ++#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */ ++ ++/* Tx and Rx XDMA defines */ ++#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */ ++#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */ ++#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */ ++#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */ ++#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */ ++#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */ ++#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */ ++#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */ ++ ++/* AFX (Address Filter Exact) register offsets for Slice 0 */ ++#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/ ++#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/ ++#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */ ++#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */ ++#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */ ++#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */ ++#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */ ++#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */ ++ ++/* Traffic Groomer block */ ++#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */ ++ ++#endif /* _TITAN_GE_H_ */ ++ +diff --git a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c +new file mode 100644 +index 0000000..8a8785b +--- /dev/null ++++ b/drivers/net/titan_mdio.c +@@ -0,0 +1,217 @@ ++/* ++ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports ++ * ++ * Copyright (C) 2003 PMC-Sierra Inc. ++ * Author : Manish Lachwani (lachwani@pmc-sierra.com) ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY ++ * on the Titan. No support for the TBI as yet. ++ * ++ */ ++ ++#include "titan_mdio.h" ++ ++#define MDIO_DEBUG ++ ++/* ++ * Local constants ++ */ ++#define MAX_CLKA 1023 ++#define MAX_PHY_DEV 31 ++#define MAX_PHY_REG 31 ++#define WRITEADDRS_OPCODE 0x0 ++#define READ_OPCODE 0x2 ++#define WRITE_OPCODE 0x1 ++#define MAX_MDIO_POLL 100 ++ ++/* ++ * Titan MDIO and SCMB registers ++ */ ++#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */ ++#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */ ++#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */ ++#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */ ++#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */ ++#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */ ++ ++/* ++ * Function to poll the MDIO ++ */ ++static int titan_ge_mdio_poll(void) ++{ ++ int i, val; ++ ++ for (i = 0; i < MAX_MDIO_POLL; i++) { ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ ++ if (!(val & 0x8000)) ++ return TITAN_GE_MDIO_GOOD; ++ } ++ ++ return TITAN_GE_MDIO_ERROR; ++} ++ ++ ++/* ++ * Initialize and configure the MDIO ++ */ ++int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio) ++{ ++ unsigned long val; ++ ++ /* Reset the SCMB and program into MDIO mode*/ ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000); ++ ++ /* CLK A */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA); ++ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val); ++ ++ /* Preamble Suppresion */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ /* MDIO mode */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Set the PHY address in indirect mode ++ */ ++int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr) ++{ ++ volatile unsigned long val; ++ ++ /* Setup the PHY device */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ /* Write the new address */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Read the MDIO register. This is what the individual parametes mean: ++ * ++ * dev_addr : PHY ID ++ * reg_addr : register offset ++ * ++ * See the spec for the Titan MAC. We operate in the Direct Mode. ++ */ ++ ++#define MAX_RETRIES 2 ++ ++int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata) ++{ ++ volatile unsigned long val; ++ int retries = 0; ++ ++ /* Setup the PHY device */ ++ ++again: ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ val |= 0x4000; ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ udelay(30); ++ ++ /* Issue the read command */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ udelay(30); ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA); ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); ++ ++ udelay(30); ++ ++ if (val & 0x2) { ++ if (retries == MAX_RETRIES) ++ return TITAN_GE_MDIO_ERROR; ++ else { ++ retries++; ++ goto again; ++ } ++ } ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Write to the MDIO register ++ * ++ * dev_addr : PHY ID ++ * reg_addr : register that needs to be written to ++ * ++ */ ++int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data) ++{ ++ volatile unsigned long val; ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ /* Setup the PHY device */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ val |= 0x4000; ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ udelay(30); ++ ++ /* Setup the data to write */ ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data); ++ ++ udelay(30); ++ ++ /* Issue the write command */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ udelay(30); ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); ++ if (val & 0x2) ++ return TITAN_GE_MDIO_ERROR; ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ +diff --git a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h +new file mode 100644 +index 0000000..5d23344 +--- /dev/null ++++ b/drivers/net/titan_mdio.h +@@ -0,0 +1,56 @@ ++/* ++ * MDIO used to interact with the PHY when using GMII/MII ++ */ ++#ifndef _TITAN_MDIO_H ++#define _TITAN_MDIO_H ++ ++#include ++#include ++#include ++#include "titan_ge.h" ++ ++ ++#define TITAN_GE_MDIO_ERROR (-9000) ++#define TITAN_GE_MDIO_GOOD 0 ++ ++#define TITAN_GE_MDIO_BASE titan_ge_base ++ ++#define TITAN_GE_MDIO_READ(offset) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) ++ ++#define TITAN_GE_MDIO_WRITE(offset, data) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) = (data) ++ ++ ++/* GMII specific registers */ ++#define TITAN_GE_MARVEL_PHY_ID 0x00 ++#define TITAN_PHY_AUTONEG_ADV 0x04 ++#define TITAN_PHY_LP_ABILITY 0x05 ++#define TITAN_GE_MDIO_MII_CTRL 0x09 ++#define TITAN_GE_MDIO_MII_EXTENDED 0x0f ++#define TITAN_GE_MDIO_PHY_CTRL 0x10 ++#define TITAN_GE_MDIO_PHY_STATUS 0x11 ++#define TITAN_GE_MDIO_PHY_IE 0x12 ++#define TITAN_GE_MDIO_PHY_IS 0x13 ++#define TITAN_GE_MDIO_PHY_LED 0x18 ++#define TITAN_GE_MDIO_PHY_LED_OVER 0x19 ++#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */ ++ ++/* ++ * MDIO Config Structure ++ */ ++typedef struct { ++ unsigned int clka; ++ int mdio_spre; ++ int mdio_mode; ++} titan_ge_mdio_config; ++ ++/* ++ * Function Prototypes ++ */ ++int titan_ge_mdio_setup(titan_ge_mdio_config *); ++int titan_ge_mdio_inaddrs(int, int); ++int titan_ge_mdio_read(int, int, unsigned int *); ++int titan_ge_mdio_write(int, int, unsigned int); ++ ++#endif /* _TITAN_MDIO_H */ +diff --git a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c +index 3411671..4d252c1 100644 +--- a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c ++++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c +@@ -22,6 +22,10 @@ + + static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) + { ++#ifdef CONFIG_LEMOTE_MACH2F ++ /* Allow users to activate rfkill through only the /sys interface */ ++ return 1; ++#else + u8 gpio; + + gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); +@@ -29,6 +33,7 @@ static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) + gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); + + return gpio & priv->rfkill_mask; ++#endif + } + + void rtl8187_rfkill_init(struct ieee80211_hw *hw) +diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig +index 09fde58..eacabd1 100644 +--- a/drivers/platform/Kconfig ++++ b/drivers/platform/Kconfig +@@ -4,5 +4,8 @@ endif + if GOLDFISH + source "drivers/platform/goldfish/Kconfig" + endif ++if MIPS ++source "drivers/platform/mips/Kconfig" ++endif + + source "drivers/platform/chrome/Kconfig" +diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile +index 3656b7b..ca26925 100644 +--- a/drivers/platform/Makefile ++++ b/drivers/platform/Makefile +@@ -3,6 +3,7 @@ + # + + obj-$(CONFIG_X86) += x86/ ++obj-$(CONFIG_MIPS) += mips/ + obj-$(CONFIG_OLPC) += olpc/ + obj-$(CONFIG_GOLDFISH) += goldfish/ + obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ +diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig +new file mode 100644 +index 0000000..722d690 +--- /dev/null ++++ b/drivers/platform/mips/Kconfig +@@ -0,0 +1,60 @@ ++# ++# MIPS Platform Specific Drivers ++# ++ ++menuconfig MIPS_PLATFORM_DEVICES ++ bool "MIPS Platform Specific Device Drivers" ++ default y ++ help ++ Say Y here to get to see options for device drivers of various ++ MIPS platforms, including vendor-specific netbook/laptop/pc extension ++ drivers. This option alone does not add any kernel code. ++ ++ If you say N, all options in this submenu will be skipped and disabled. ++ ++if MIPS_PLATFORM_DEVICES ++ ++config LEMOTE_YEELOONG2F ++ tristate "Lemote YeeLoong Laptop" ++ depends on LEMOTE_MACH2F ++ select BACKLIGHT_LCD_SUPPORT ++ select LCD_CLASS_DEVICE ++ select BACKLIGHT_CLASS_DEVICE ++ select POWER_SUPPLY ++ select HWMON ++ select VIDEO_OUTPUT_CONTROL ++ select INPUT_SPARSEKMAP ++ select INPUT_EVDEV ++ depends on INPUT ++ default m ++ help ++ YeeLoong netbook is a mini laptop made by Lemote, which is basically ++ compatible to FuLoong2F mini PC, but it has an extra Embedded ++ Controller(kb3310b) for battery, hotkey, backlight, temperature and ++ fan management. ++ ++config LEMOTE_LYNLOONG2F ++ tristate "Lemote LynLoong PC" ++ depends on LEMOTE_MACH2F ++ select BACKLIGHT_LCD_SUPPORT ++ select BACKLIGHT_CLASS_DEVICE ++ select VIDEO_OUTPUT_CONTROL ++ default m ++ help ++ LynLoong PC is an AllINONE machine made by Lemote, which is basically ++ compatible to FuLoong2F Mini PC, the only difference is that it has a ++ size-fixed screen: 1360x768 with sisfb video driver. and also, it has ++ its own specific suspend support. ++ ++config GDIUM_LAPTOP ++ tristate "GDIUM laptop extras" ++ depends on DEXXON_GDIUM ++ select POWER_SUPPLY ++ select I2C ++ select INPUT_POLLDEV ++ default m ++ help ++ This mini-driver drives the ST7 chipset present in the Gdium laptops. ++ This gives battery support, wlan rfkill. ++ ++endif # MIPS_PLATFORM_DEVICES +diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile +new file mode 100644 +index 0000000..f013e78 +--- /dev/null ++++ b/drivers/platform/mips/Makefile +@@ -0,0 +1,9 @@ ++# ++# Makefile for MIPS Platform-Specific Drivers ++# ++ ++obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o # yeeloong_ecrom.o ++CFLAGS_yeeloong_laptop.o = -I$(srctree)/arch/mips/loongson/lemote-2f ++ ++obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o ++obj-$(CONFIG_GDIUM_LAPTOP) += gdium_laptop.o +diff --git a/drivers/platform/mips/gdium_laptop.c b/drivers/platform/mips/gdium_laptop.c +new file mode 100644 +index 0000000..41a65ad +--- /dev/null ++++ b/drivers/platform/mips/gdium_laptop.c +@@ -0,0 +1,927 @@ ++/* ++ * gdium_laptop -- Gdium laptop extras ++ * ++ * Arnaud Patard ++ * ++ * 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. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* For input device */ ++#define SCAN_INTERVAL 150 ++ ++/* For battery status */ ++#define BAT_SCAN_INTERVAL 500 ++ ++#define EC_FIRM_VERSION 0 ++ ++#if CONFIG_GDIUM_VERSION > 2 ++#define EC_REG_BASE 1 ++#else ++#define EC_REG_BASE 0 ++#endif ++ ++#define EC_STATUS (EC_REG_BASE+0) ++#define EC_STATUS_LID (1<<0) ++#define EC_STATUS_PWRBUT (1<<1) ++#define EC_STATUS_BATID (1<<2) /* this bit has no real meaning on v2. */ ++ /* Same as EC_STATUS_ADAPT */ ++ /* but on v3 it's BATID which mean bat present */ ++#define EC_STATUS_SYS_POWER (1<<3) ++#define EC_STATUS_WLAN (1<<4) ++#define EC_STATUS_ADAPT (1<<5) ++ ++#define EC_CTRL (EC_REG_BASE+1) ++#define EC_CTRL_DDR_CLK (1<<0) ++#define EC_CTRL_CHARGE_LED (1<<1) ++#define EC_CTRL_BEEP (1<<2) ++#define EC_CTRL_SUSB (1<<3) /* memory power */ ++#define EC_CTRL_TRICKLE (1<<4) ++#define EC_CTRL_WLAN_EN (1<<5) ++#define EC_CTRL_SUSC (1<<6) /* main power */ ++#define EC_CTRL_CHARGE_EN (1<<7) ++ ++#define EC_BAT_LOW (EC_REG_BASE+2) ++#define EC_BAT_HIGH (EC_REG_BASE+3) ++ ++#define EC_SIGN (EC_REG_BASE+4) ++#define EC_SIGN_OS 0xAE /* write 0xae to control pm stuff */ ++#define EC_SIGN_EC 0x00 /* write 0x00 to let the st7 manage pm stuff */ ++ ++#if 0 ++#define EC_TEST (EC_REG_BASE+5) /* Depending on firmware version this register */ ++ /* may be the programmation register so don't play */ ++ /* with it */ ++#endif ++ ++#define BAT_VOLT_PRESENT 500000 /* Min voltage to consider battery present uV */ ++#define BAT_MIN 7000000 /* Min battery voltage in uV */ ++#define BAT_MIN_MV 7000 /* Min battery voltage in mV */ ++#define BAT_TRICKLE_EN 8000000 /* Charging at 1.4A before 8.0V and then charging at 0.25A */ ++#define BAT_MAX 7950000 /* Max battery voltage ~8V in V */ ++#define BAT_MAX_MV 7950 /* Max battery voltage ~8V in V */ ++#define BAT_READ_ERROR 300000 /* battery read error of 0.3V */ ++#define BAT_READ_ERROR_MV 300 /* battery read error of 0.3V */ ++ ++#define SM502_WLAN_ON (224+16)/* SM502 GPIO16 may be used on gdium v2 (v3?) as wlan_on */ ++ /* when R422 is connected */ ++ ++static unsigned char verbose; ++static unsigned char gpio16; ++static unsigned char ec; ++module_param(verbose, byte, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(verbose, "Add some debugging messages"); ++module_param(gpio16, byte, S_IRUGO); ++MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502"); ++module_param(ec, byte, S_IRUGO); ++MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)"); ++ ++struct gdium_laptop_data { ++ struct i2c_client *client; ++ struct input_polled_dev *input_polldev; ++ struct dentry *debugfs; ++ struct mutex mutex; ++ struct platform_device *bat_pdev; ++ struct power_supply gdium_ac; ++ struct power_supply gdium_battery; ++ struct workqueue_struct *workqueue; ++ struct delayed_work work; ++ char charge_cmd; ++ /* important registers value */ ++ char status; ++ char ctrl; ++ /* mV */ ++ int battery_level; ++ char version; ++}; ++ ++/**********************************************************************/ ++/* Low level I2C functions */ ++/* All are supposed to be called with mutex held */ ++/**********************************************************************/ ++/* ++ * Return battery voltage in mV ++ * >= 0 battery voltage ++ * < 0 error ++ */ ++static s32 ec_read_battery(struct i2c_client *client) ++{ ++ unsigned char bat_low, bat_high; ++ s32 data; ++ unsigned int ret; ++ ++ /* ++ * a = battery high ++ * b = battery low ++ * bat = a << 2 | b & 0x03; ++ * battery voltage = (bat / 1024) * 5 * 2 ++ */ ++ data = i2c_smbus_read_byte_data(client, EC_BAT_LOW); ++ if (data < 0) { ++ dev_err(&client->dev, "ec_read_bat: read bat_low failed\n"); ++ return data; ++ } ++ bat_low = data & 0xff; ++ if (verbose) ++ dev_info(&client->dev, "bat_low %x\n", bat_low); ++ ++ data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH); ++ if (data < 0) { ++ dev_err(&client->dev, "ec_read_bat: read bat_high failed\n"); ++ return data; ++ } ++ bat_high = data & 0xff; ++ if (verbose) ++ dev_info(&client->dev, "bat_high %x\n", bat_high); ++ ++ ret = (bat_high << 2) | (bat_low & 3); ++ /* ++ * mV ++ */ ++ ret = (ret * 5 * 2) * 1000 / 1024; ++ ++ return ret; ++} ++ ++static s32 ec_read_version(struct i2c_client *client) ++{ ++#if CONFIG_GDIUM_VERSION > 2 ++ return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION); ++#else ++ return 0; ++#endif ++} ++ ++static s32 ec_read_status(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_STATUS); ++} ++ ++static s32 ec_read_ctrl(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_CTRL); ++} ++ ++static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue) ++{ ++ return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue); ++} ++ ++static s32 ec_read_sign(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_SIGN); ++} ++ ++static s32 ec_write_sign(struct i2c_client *client, unsigned char sign) ++{ ++ unsigned char value; ++ s32 ret; ++ ++ ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign); ++ if (ret < 0) { ++ dev_err(&client->dev, "ec_set_control: write failed\n"); ++ return ret; ++ } ++ ++ value = ec_read_sign(client); ++ if (value != sign) { ++ dev_err(&client->dev, "Failed to set control to %s\n", ++ sign == EC_SIGN_OS ? "OS" : "EC"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++#if 0 ++static int ec_power_off(struct i2c_client *client) ++{ ++ char value; ++ int ret; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) { ++ dev_err(&client->dev, "ec_power_off: read failed\n"); ++ return value; ++ } ++ value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC); ++ ret = ec_write_ctrl(client, value); ++ if (ret < 0) { ++ dev_err(&client->dev, "ec_power_off: write failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++static s32 ec_wlan_status(struct i2c_client *client) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ return (value & EC_CTRL_WLAN_EN) ? 1 : 0; ++} ++ ++static s32 ec_wlan_en(struct i2c_client *client, int on) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ value &= ~EC_CTRL_WLAN_EN; ++ if (on) ++ value |= EC_CTRL_WLAN_EN; ++ ++ return ec_write_ctrl(client, value&0xff); ++} ++ ++#if 0 ++static s32 ec_led_status(struct i2c_client *client) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ return (value & EC_CTRL_CHARGE_LED) ? 1 : 0; ++} ++#endif ++ ++/* Changing the charging led status has never worked */ ++static s32 ec_led_en(struct i2c_client *client, int on) ++{ ++#if 0 ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ value &= ~EC_CTRL_CHARGE_LED; ++ if (on) ++ value |= EC_CTRL_CHARGE_LED; ++ return ec_write_ctrl(client, value&0xff); ++#else ++ return 0; ++#endif ++} ++ ++static s32 ec_charge_en(struct i2c_client *client, int on, int trickle) ++{ ++ s32 value; ++ s32 set = 0; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ if (on) ++ set |= EC_CTRL_CHARGE_EN; ++ if (trickle) ++ set |= EC_CTRL_TRICKLE; ++ ++ /* Be clever : don't change values if you don't need to */ ++ if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set) ++ return 0; ++ ++ value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE); ++ value |= set; ++ ec_led_en(client, on); ++ return ec_write_ctrl(client, (unsigned char)(value&0xff)); ++ ++} ++ ++/**********************************************************************/ ++/* Input functions */ ++/**********************************************************************/ ++struct gdium_keys { ++ int last_state; ++ int key_code; ++ int mask; ++ int type; ++}; ++ ++static struct gdium_keys gkeys[] = { ++ { ++ .key_code = KEY_WLAN, ++ .mask = EC_STATUS_WLAN, ++ .type = EV_KEY, ++ }, ++ { ++ .key_code = KEY_POWER, ++ .mask = EC_STATUS_PWRBUT, ++ .type = EV_KEY, /*EV_PWR,*/ ++ }, ++ { ++ .key_code = SW_LID, ++ .mask = EC_STATUS_LID, ++ .type = EV_SW, ++ }, ++}; ++ ++static void gdium_laptop_keys_poll(struct input_polled_dev *dev) ++{ ++ int state, i; ++ struct gdium_laptop_data *data = dev->private; ++ struct i2c_client *client = data->client; ++ struct input_dev *input = dev->input; ++ s32 status; ++ ++ mutex_lock(&data->mutex); ++ status = ec_read_status(client); ++ mutex_unlock(&data->mutex); ++ ++ if (status < 0) { ++ /* ++ * Don't know exactly which version of the firmware ++ * has this bug but when the power button is pressed ++ * there are i2c read errors :( ++ */ ++ if ((data->version >= 0x13) && !gkeys[1].last_state) { ++ input_event(input, EV_KEY, KEY_POWER, 1); ++ input_sync(input); ++ gkeys[1].last_state = 1; ++ } ++ return; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(gkeys); i++) { ++ state = status & gkeys[i].mask; ++ if (state != gkeys[i].last_state) { ++ gkeys[i].last_state = state; ++ /* for power key, we want power & key press/release event */ ++ if (gkeys[i].type == EV_PWR) { ++ input_event(input, EV_KEY, gkeys[i].key_code, !!state); ++ input_sync(input); ++ } ++ /* Disable wifi on key press but not key release */ ++ /* ++ * On firmware >= 0x13 the EC_STATUS_WLAN has it's ++ * original meaning of Wifi status and no more the ++ * wifi button status so we have to ignore the event ++ * on theses versions ++ */ ++ if (state && (gkeys[i].key_code == KEY_WLAN) && (data->version < 0x13)) { ++ mutex_lock(&data->mutex); ++ ec_wlan_en(client, !ec_wlan_status(client)); ++ if (gpio16) ++ gpio_set_value(SM502_WLAN_ON, !ec_wlan_status(client)); ++ mutex_unlock(&data->mutex); ++ } ++ ++ input_event(input, gkeys[i].type, gkeys[i].key_code, !!state); ++ input_sync(input); ++ } ++ } ++} ++ ++static int gdium_laptop_input_init(struct gdium_laptop_data *data) ++{ ++ struct i2c_client *client = data->client; ++ struct input_dev *input; ++ int ret, i; ++ ++ data->input_polldev = input_allocate_polled_device(); ++ if (!data->input_polldev) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ input = data->input_polldev->input; ++ input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW); ++ data->input_polldev->poll = gdium_laptop_keys_poll; ++ data->input_polldev->poll_interval = SCAN_INTERVAL; ++ data->input_polldev->private = data; ++ input->name = "gdium-keys"; ++ input->dev.parent = &client->dev; ++ ++ input->id.bustype = BUS_HOST; ++ input->id.vendor = 0x0001; ++ input->id.product = 0x0001; ++ input->id.version = 0x0100; ++ ++ for (i = 0; i < ARRAY_SIZE(gkeys); i++) ++ input_set_capability(input, gkeys[i].type, gkeys[i].key_code); ++ ++ ret = input_register_polled_device(data->input_polldev); ++ if (ret) { ++ dev_err(&client->dev, "Unable to register button device\n"); ++ goto err_poll_dev; ++ } ++ ++ return 0; ++ ++err_poll_dev: ++ input_free_polled_device(data->input_polldev); ++err: ++ return ret; ++} ++ ++static void gdium_laptop_input_exit(struct gdium_laptop_data *data) ++{ ++ input_unregister_polled_device(data->input_polldev); ++ input_free_polled_device(data->input_polldev); ++} ++ ++/**********************************************************************/ ++/* Battery management */ ++/**********************************************************************/ ++static int gdium_ac_get_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ char status; ++ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_ac); ++ int ret = 0; ++ ++ if (!data) { ++ pr_err("gdium-ac: gdium_laptop_data not found\n"); ++ return -EINVAL; ++ } ++ ++ status = data->status; ++ switch (psp) { ++ case POWER_SUPPLY_PROP_ONLINE: ++ val->intval = !!(status & EC_STATUS_ADAPT); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#undef RET ++#define RET (val->intval) ++ ++static int gdium_battery_get_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ char status, ctrl; ++ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_battery); ++ int percentage_capacity = 0, charge_now = 0, time_to_empty = 0; ++ int ret = 0, tmp; ++ ++ if (!data) { ++ pr_err("gdium-battery: gdium_laptop_data not found\n"); ++ return -EINVAL; ++ } ++ ++ status = data->status; ++ ctrl = data->ctrl; ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ++ /* uAh */ ++ RET = 5000000; ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ++ /* This formula is gotten by gnuplot with the statistic data */ ++ time_to_empty = (data->battery_level - BAT_MIN_MV + BAT_READ_ERROR_MV) * 113 - 29870; ++ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) { ++ /* seconds */ ++ RET = time_to_empty / 10; ++ break; ++ } ++ /* fall through */ ++ case POWER_SUPPLY_PROP_CHARGE_NOW: ++ case POWER_SUPPLY_PROP_CAPACITY: { ++ tmp = data->battery_level * 1000; ++ /* > BAT_MIN to avoid negative values */ ++ percentage_capacity = 0; ++ if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN)) ++ percentage_capacity = (tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN); ++ ++ if (percentage_capacity > 100) ++ percentage_capacity = 100; ++ ++ if (psp == POWER_SUPPLY_PROP_CAPACITY) { ++ RET = percentage_capacity; ++ break; ++ } ++ charge_now = 50000 * percentage_capacity; ++ if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) { ++ /* uAh */ ++ RET = charge_now; ++ break; ++ } ++ } /* fall through */ ++ case POWER_SUPPLY_PROP_STATUS: { ++ if (status & EC_STATUS_ADAPT) ++ if (ctrl & EC_CTRL_CHARGE_EN) ++ RET = POWER_SUPPLY_STATUS_CHARGING; ++ else ++ RET = POWER_SUPPLY_STATUS_NOT_CHARGING; ++ else ++ RET = POWER_SUPPLY_STATUS_DISCHARGING; ++ ++ if (psp == POWER_SUPPLY_PROP_STATUS) ++ break; ++ /* mAh -> µA */ ++ switch (RET) { ++ case POWER_SUPPLY_STATUS_CHARGING: ++ RET = -(data->charge_cmd == 2) ? 1400000 : 250000; ++ break; ++ case POWER_SUPPLY_STATUS_DISCHARGING: ++ RET = charge_now / time_to_empty * 36000; ++ break; ++ case POWER_SUPPLY_STATUS_NOT_CHARGING: ++ default: ++ RET = 0; ++ break; ++ } ++ } break; ++ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: ++ RET = BAT_MAX+BAT_READ_ERROR; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: ++ RET = BAT_MIN-BAT_READ_ERROR; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ /* mV -> uV */ ++ RET = data->battery_level * 1000; ++ break; ++ case POWER_SUPPLY_PROP_PRESENT: ++#if CONFIG_GDIUM_VERSION > 2 ++ RET = !!(status & EC_STATUS_BATID); ++#else ++ RET = !!(data->battery_level > BAT_VOLT_PRESENT); ++#endif ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: ++ tmp = data->battery_level * 1000; ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ if (status & EC_STATUS_BATID) { ++ if (tmp >= BAT_MAX) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; ++ if (tmp >= BAT_MAX+BAT_READ_ERROR) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; ++ } else if (tmp <= BAT_MIN+BAT_READ_ERROR) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; ++ if (tmp <= BAT_MIN) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; ++ } else ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; ++ } ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_TYPE: ++ if (ctrl & EC_CTRL_TRICKLE) ++ RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; ++ else if (ctrl & EC_CTRL_CHARGE_EN) ++ RET = POWER_SUPPLY_CHARGE_TYPE_FAST; ++ else ++ RET = POWER_SUPPLY_CHARGE_TYPE_NONE; ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_MAX: ++ /* 1.4A ? */ ++ RET = 1400000; ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++#undef RET ++ ++static enum power_supply_property gdium_ac_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++}; ++ ++static enum power_supply_property gdium_battery_props[] = { ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_NOW, ++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, ++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_CURRENT_MAX, ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_CAPACITY_LEVEL, ++ POWER_SUPPLY_PROP_CHARGE_TYPE, ++}; ++ ++static void gdium_laptop_battery_work(struct work_struct *work) ++{ ++ struct gdium_laptop_data *data = container_of(work, struct gdium_laptop_data, work.work); ++ struct i2c_client *client; ++ int ret; ++ char old_status, old_charge_cmd; ++ char present; ++ s32 status; ++ ++ mutex_lock(&data->mutex); ++ client = data->client; ++ status = ec_read_status(client); ++ ret = ec_read_battery(client); ++ ++ if ((status < 0) || (ret < 0)) ++ goto i2c_read_error; ++ ++ old_status = data->status; ++ old_charge_cmd = data->charge_cmd; ++ data->status = status; ++ ++ /* ++ * Charge only if : ++ * - battery present ++ * - ac adapter plugged in ++ * - battery not fully charged ++ */ ++#if CONFIG_GDIUM_VERSION > 2 ++ present = !!(data->status & EC_STATUS_BATID); ++#else ++ present = !!(ret > BAT_VOLT_PRESENT); ++#endif ++ data->battery_level = 0; ++ if (present) { ++ data->battery_level = (unsigned int)ret; ++ if (data->status & EC_STATUS_ADAPT) ++ data->battery_level -= BAT_READ_ERROR_MV; ++ } ++ ++ data->charge_cmd = 0; ++ if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level <= BAT_MAX_MV)) ++ data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3; ++ ++ ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1); ++ ++ /* ++ * data->ctrl must be set _after_ calling ec_charge_en as this will change the ++ * control register content ++ */ ++ data->ctrl = ec_read_ctrl(client); ++ ++ if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) { ++ power_supply_changed(&data->gdium_ac); ++ /* Send charging/discharging state change */ ++ power_supply_changed(&data->gdium_battery); ++ } else if ((data->status & EC_STATUS_ADAPT) && ++ ((old_charge_cmd&2) != (data->charge_cmd&2))) ++ power_supply_changed(&data->gdium_battery); ++ ++i2c_read_error: ++ mutex_unlock(&data->mutex); ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++} ++ ++static int gdium_laptop_battery_init(struct gdium_laptop_data *data) ++{ ++ int ret; ++ ++ data->bat_pdev = platform_device_register_simple("gdium-battery", 0, NULL, 0); ++ if (IS_ERR(data->bat_pdev)) ++ return PTR_ERR(data->bat_pdev); ++ ++ data->gdium_battery.name = data->bat_pdev->name; ++ data->gdium_battery.properties = gdium_battery_props; ++ data->gdium_battery.num_properties = ARRAY_SIZE(gdium_battery_props); ++ data->gdium_battery.get_property = gdium_battery_get_props; ++ data->gdium_battery.use_for_apm = 1; ++ ++ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery); ++ if (ret) ++ goto err_platform; ++ ++ data->gdium_ac.name = "gdium-ac"; ++ data->gdium_ac.type = POWER_SUPPLY_TYPE_MAINS; ++ data->gdium_ac.properties = gdium_ac_props; ++ data->gdium_ac.num_properties = ARRAY_SIZE(gdium_ac_props); ++ data->gdium_ac.get_property = gdium_ac_get_props; ++/* data->gdium_ac.use_for_apm_ac = 1, */ ++ ++ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac); ++ if (ret) ++ goto err_battery; ++ ++ if (!ec) { ++ INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work); ++ data->workqueue = create_singlethread_workqueue("gdium-battery-work"); ++ if (!data->workqueue) { ++ ret = -ESRCH; ++ goto err_work; ++ } ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++ } ++ ++ return 0; ++ ++err_work: ++err_battery: ++ power_supply_unregister(&data->gdium_battery); ++err_platform: ++ platform_device_unregister(data->bat_pdev); ++ ++ return ret; ++} ++static void gdium_laptop_battery_exit(struct gdium_laptop_data *data) ++{ ++ if (!ec) { ++ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); ++ destroy_workqueue(data->workqueue); ++ } ++ power_supply_unregister(&data->gdium_battery); ++ power_supply_unregister(&data->gdium_ac); ++ platform_device_unregister(data->bat_pdev); ++} ++ ++/* Debug fs */ ++static int gdium_laptop_regs_show(struct seq_file *s, void *p) ++{ ++ struct gdium_laptop_data *data = s->private; ++ struct i2c_client *client = data->client; ++ ++ mutex_lock(&data->mutex); ++ seq_printf(s, "Version : 0x%02x\n", (unsigned char)ec_read_version(client)); ++ seq_printf(s, "Status : 0x%02x\n", (unsigned char)ec_read_status(client)); ++ seq_printf(s, "Ctrl : 0x%02x\n", (unsigned char)ec_read_ctrl(client)); ++ seq_printf(s, "Sign : 0x%02x\n", (unsigned char)ec_read_sign(client)); ++ seq_printf(s, "Bat Lo : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_LOW)); ++ seq_printf(s, "Bat Hi : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH)); ++ seq_printf(s, "Battery : %d uV\n", (unsigned int)ec_read_battery(client) * 1000); ++ seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", data->charge_cmd & 1 ? "T" : " "); ++ ++ mutex_unlock(&data->mutex); ++ return 0; ++} ++ ++static int gdium_laptop_regs_open(struct inode *inode, ++ struct file *file) ++{ ++ return single_open(file, gdium_laptop_regs_show, inode->i_private); ++} ++ ++static const struct file_operations gdium_laptop_regs_fops = { ++ .open = gdium_laptop_regs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++ ++static int gdium_laptop_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ struct gdium_laptop_data *data; ++ int ret; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&client->dev, ++ "%s: no smbus_byte support !\n", __func__); ++ return -ENODEV; ++ } ++ ++ data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(client, data); ++ data->client = client; ++ mutex_init(&data->mutex); ++ ++ ret = ec_read_version(client); ++ if (ret < 0) ++ goto err_alloc; ++ ++ data->version = (unsigned char)ret; ++ ++ ret = gdium_laptop_input_init(data); ++ if (ret) ++ goto err_alloc; ++ ++ ret = gdium_laptop_battery_init(data); ++ if (ret) ++ goto err_input; ++ ++ ++ if (!ec) { ++ ret = ec_write_sign(client, EC_SIGN_OS); ++ if (ret) ++ goto err_sign; ++ } ++ ++ if (gpio16) { ++ ret = gpio_request(SM502_WLAN_ON, "wlan-on"); ++ if (ret < 0) ++ goto err_sign; ++ gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client)); ++ gpio_direction_output(SM502_WLAN_ON, 1); ++ } ++ ++ dev_info(&client->dev, "Found firmware 0x%02x\n", data->version); ++ data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO, ++ NULL, data, &gdium_laptop_regs_fops); ++ ++ return 0; ++ ++err_sign: ++ gdium_laptop_battery_exit(data); ++err_input: ++ gdium_laptop_input_exit(data); ++err_alloc: ++ kfree(data); ++ return ret; ++} ++ ++static int gdium_laptop_remove(struct i2c_client *client) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (gpio16) ++ gpio_free(SM502_WLAN_ON); ++ ec_write_sign(client, EC_SIGN_EC); ++ if (data->debugfs) ++ debugfs_remove(data->debugfs); ++ ++ gdium_laptop_battery_exit(data); ++ gdium_laptop_input_exit(data); ++ ++ kfree(data); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (!ec) ++ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); ++ return 0; ++} ++ ++static int gdium_laptop_resume(struct i2c_client *client) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (!ec) ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++ return 0; ++} ++#else ++#define gdium_laptop_suspend NULL ++#define gdium_laptop_resume NULL ++#endif ++static const struct i2c_device_id gdium_id[] = { ++ { "gdium-laptop" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(i2c, gdium_id); ++ ++static struct i2c_driver gdium_laptop_driver = { ++ .driver = { ++ .name = "gdium-laptop", ++ .owner = THIS_MODULE, ++ }, ++ .probe = gdium_laptop_probe, ++ .remove = gdium_laptop_remove, ++ .shutdown = gdium_laptop_remove, ++ .suspend = gdium_laptop_suspend, ++ .resume = gdium_laptop_resume, ++ .id_table = gdium_id, ++}; ++ ++static int __init gdium_laptop_init(void) ++{ ++ return i2c_add_driver(&gdium_laptop_driver); ++} ++ ++static void __exit gdium_laptop_exit(void) ++{ ++ i2c_del_driver(&gdium_laptop_driver); ++} ++ ++module_init(gdium_laptop_init); ++module_exit(gdium_laptop_exit); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("Gdium laptop extras"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/lynloong_pc.c b/drivers/platform/mips/lynloong_pc.c +new file mode 100644 +index 0000000..68f29e4 +--- /dev/null ++++ b/drivers/platform/mips/lynloong_pc.c +@@ -0,0 +1,515 @@ ++/* ++ * Driver for LynLoong PC extras ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin , Xiang Yu ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include /* for backlight subdriver */ ++#include ++#include /* for video output subdriver */ ++#include /* for suspend support */ ++ ++#include ++#include ++ ++#include ++ ++static u32 gpio_base, mfgpt_base; ++ ++static void set_gpio_reg_high(int gpio, int reg) ++{ ++ u32 val; ++ ++ val = inl(gpio_base + reg); ++ val |= (1 << gpio); ++ val &= ~(1 << (16 + gpio)); ++ outl(val, gpio_base + reg); ++ mmiowb(); ++} ++ ++static void set_gpio_reg_low(int gpio, int reg) ++{ ++ u32 val; ++ ++ val = inl(gpio_base + reg); ++ val |= (1 << (16 + gpio)); ++ val &= ~(1 << gpio); ++ outl(val, gpio_base + reg); ++ mmiowb(); ++} ++ ++static void set_gpio_output_low(int gpio) ++{ ++ set_gpio_reg_high(gpio, GPIOL_OUT_EN); ++ set_gpio_reg_low(gpio, GPIOL_OUT_VAL); ++} ++ ++static void set_gpio_output_high(int gpio) ++{ ++ set_gpio_reg_high(gpio, GPIOL_OUT_EN); ++ set_gpio_reg_high(gpio, GPIOL_OUT_VAL); ++} ++ ++/* backlight subdriver */ ++ ++#define MAX_BRIGHTNESS 100 ++#define DEFAULT_BRIGHTNESS 50 ++#define MIN_BRIGHTNESS 0 ++static unsigned int level; ++ ++DEFINE_SPINLOCK(backlight_lock); ++/* Tune the brightness */ ++static void setup_mfgpt2(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&backlight_lock, flags); ++ ++ /* Set MFGPT2 comparator 1,2 */ ++ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1); ++ outw(MAX_BRIGHTNESS, MFGPT2_CMP2); ++ /* Clear MFGPT2 UP COUNTER */ ++ outw(0, MFGPT2_CNT); ++ /* Enable counter, compare mode, 32k */ ++ outw(0x8280, MFGPT2_SETUP); ++ ++ spin_unlock_irqrestore(&backlight_lock, flags); ++} ++ ++static int lynloong_set_brightness(struct backlight_device *bd) ++{ ++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && ++ bd->props.power == FB_BLANK_UNBLANK) ? ++ bd->props.brightness : 0; ++ ++ if (level > MAX_BRIGHTNESS) ++ level = MAX_BRIGHTNESS; ++ else if (level < MIN_BRIGHTNESS) ++ level = MIN_BRIGHTNESS; ++ ++ setup_mfgpt2(); ++ ++ return 0; ++} ++ ++static int lynloong_get_brightness(struct backlight_device *bd) ++{ ++ return level; ++} ++ ++static struct backlight_ops backlight_ops = { ++ .get_brightness = lynloong_get_brightness, ++ .update_status = lynloong_set_brightness, ++}; ++ ++static struct backlight_device *lynloong_backlight_dev; ++ ++static int lynloong_backlight_init(void) ++{ ++ int ret; ++ u32 hi; ++ struct backlight_properties props; ++ ++ /* Get gpio_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); ++ /* Get mfgpt_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base); ++ /* Get gpio_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); ++ ++ /* Select for mfgpt */ ++ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL); ++ /* Enable brightness controlling */ ++ set_gpio_output_high(7); ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.max_brightness = MAX_BRIGHTNESS; ++ props.type = BACKLIGHT_PLATFORM; ++ lynloong_backlight_dev = backlight_device_register("backlight0", NULL, ++ NULL, &backlight_ops, &props); ++ ++ if (IS_ERR(lynloong_backlight_dev)) { ++ ret = PTR_ERR(lynloong_backlight_dev); ++ return ret; ++ } ++ ++ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS; ++ backlight_update_status(lynloong_backlight_dev); ++ ++ return 0; ++} ++ ++static void lynloong_backlight_exit(void) ++{ ++ if (lynloong_backlight_dev) { ++ backlight_device_unregister(lynloong_backlight_dev); ++ lynloong_backlight_dev = NULL; ++ } ++ /* Disable brightness controlling */ ++ set_gpio_output_low(7); ++} ++ ++/* video output driver */ ++static int vo_status = 1; ++ ++static int lcd_video_output_get(struct output_device *od) ++{ ++ return vo_status; ++} ++ ++static int lcd_video_output_set(struct output_device *od) ++{ ++ int i; ++ unsigned long status; ++ ++ status = !!od->request_state; ++ ++ if (status == 0) { ++ /* Set the current status as off */ ++ vo_status = 0; ++ /* Turn off the backlight */ ++ set_gpio_output_low(11); ++ for (i = 0; i < 0x500; i++) ++ delay(); ++ /* Turn off the LCD */ ++ set_gpio_output_high(8); ++ } else { ++ /* Turn on the LCD */ ++ set_gpio_output_low(8); ++ for (i = 0; i < 0x500; i++) ++ delay(); ++ /* Turn on the backlight */ ++ set_gpio_output_high(11); ++ /* Set the current status as on */ ++ vo_status = 1; ++ } ++ ++ return 0; ++} ++ ++static struct output_properties lcd_output_properties = { ++ .set_state = lcd_video_output_set, ++ .get_status = lcd_video_output_get, ++}; ++ ++static struct output_device *lcd_output_dev; ++ ++static void lynloong_lcd_vo_set(int status) ++{ ++ lcd_output_dev->request_state = status; ++ lcd_video_output_set(lcd_output_dev); ++} ++ ++static int lynloong_vo_init(void) ++{ ++ int ret; ++ ++ /* Register video output device: lcd */ ++ lcd_output_dev = video_output_register("LCD", NULL, NULL, ++ &lcd_output_properties); ++ ++ if (IS_ERR(lcd_output_dev)) { ++ ret = PTR_ERR(lcd_output_dev); ++ lcd_output_dev = NULL; ++ return ret; ++ } ++ /* Ensure LCD is on by default */ ++ lynloong_lcd_vo_set(1); ++ ++ return 0; ++} ++ ++static void lynloong_vo_exit(void) ++{ ++ if (lcd_output_dev) { ++ video_output_unregister(lcd_output_dev); ++ lcd_output_dev = NULL; ++ } ++} ++ ++/* suspend support */ ++ ++#ifdef CONFIG_PM ++ ++static u32 smb_base; ++ ++/* I2C operations */ ++ ++static int i2c_wait(void) ++{ ++ char c; ++ int i; ++ ++ udelay(1000); ++ for (i = 0; i < 20; i++) { ++ c = inb(smb_base | SMB_STS); ++ if (c & (SMB_STS_BER | SMB_STS_NEGACK)) ++ return -1; ++ if (c & SMB_STS_SDAST) ++ return 0; ++ udelay(100); ++ } ++ return -2; ++} ++ ++static void i2c_read_single(int addr, int regNo, char *value) ++{ ++ unsigned char c; ++ ++ /* Start condition */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ ++ /* Send slave address */ ++ outb(addr & 0xfe, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Send register index */ ++ outb(regNo, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Start condition again */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ ++ /* Send salve address again */ ++ outb(1 | addr, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Read data */ ++ *value = inb(smb_base | SMB_SDA); ++ ++ /* Stop condition */ ++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); ++ i2c_wait(); ++} ++ ++static void i2c_write_single(int addr, int regNo, char value) ++{ ++ unsigned char c; ++ ++ /* Start condition */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ /* Send slave address */ ++ outb(addr & 0xfe, smb_base | SMB_SDA); ++ i2c_wait();; ++ ++ /* Send register index */ ++ outb(regNo, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Write data */ ++ outb(value, smb_base | SMB_SDA); ++ i2c_wait(); ++ /* Stop condition */ ++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); ++ i2c_wait(); ++} ++ ++static void stop_clock(int clk_reg, int clk_sel) ++{ ++ u8 value; ++ ++ i2c_read_single(0xd3, clk_reg, &value); ++ value &= ~(1 << clk_sel); ++ i2c_write_single(0xd2, clk_reg, value); ++} ++ ++static void enable_clock(int clk_reg, int clk_sel) ++{ ++ u8 value; ++ ++ i2c_read_single(0xd3, clk_reg, &value); ++ value |= (1 << clk_sel); ++ i2c_write_single(0xd2, clk_reg, value); ++} ++ ++static char cached_clk_freq; ++static char cached_pci_fixed_freq; ++ ++static void decrease_clk_freq(void) ++{ ++ char value; ++ ++ i2c_read_single(0xd3, 1, &value); ++ cached_clk_freq = value; ++ ++ /* Select frequency by software */ ++ value |= (1 << 1); ++ /* CPU, 3V66, PCI : 100, 66, 33(1) */ ++ value |= (1 << 2); ++ i2c_write_single(0xd2, 1, value); ++ ++ /* Cache the pci frequency */ ++ i2c_read_single(0xd3, 14, &value); ++ cached_pci_fixed_freq = value; ++ ++ /* Enable PCI fix mode */ ++ value |= (1 << 5); ++ /* 3V66, PCI : 64MHz, 32MHz */ ++ value |= (1 << 3); ++ i2c_write_single(0xd2, 14, value); ++ ++} ++ ++static void resume_clk_freq(void) ++{ ++ i2c_write_single(0xd2, 1, cached_clk_freq); ++ i2c_write_single(0xd2, 14, cached_pci_fixed_freq); ++} ++ ++static void stop_clocks(void) ++{ ++ /* CPU Clock Register */ ++ stop_clock(2, 5); /* not used */ ++ stop_clock(2, 6); /* not used */ ++ stop_clock(2, 7); /* not used */ ++ ++ /* PCI Clock Register */ ++ stop_clock(3, 1); /* 8100 */ ++ stop_clock(3, 5); /* SIS */ ++ stop_clock(3, 0); /* not used */ ++ stop_clock(3, 6); /* not used */ ++ ++ /* PCI 48M Clock Register */ ++ stop_clock(4, 6); /* USB grounding */ ++ stop_clock(4, 5); /* REF(5536_14M) */ ++ ++ /* 3V66 Control Register */ ++ stop_clock(5, 0); /* VCH_CLK..., grounding */ ++} ++ ++static void enable_clocks(void) ++{ ++ enable_clock(3, 1); /* 8100 */ ++ enable_clock(3, 5); /* SIS */ ++ ++ enable_clock(4, 6); ++ enable_clock(4, 5); /* REF(5536_14M) */ ++ ++ enable_clock(5, 0); /* VCH_CLOCK, grounding */ ++} ++ ++static int lynloong_suspend(struct device *dev) ++{ ++ /* Disable AMP */ ++ set_gpio_output_high(6); ++ /* Turn off LCD */ ++ lynloong_lcd_vo_set(0); ++ ++ /* Stop the clocks of some devices */ ++ stop_clocks(); ++ ++ /* Decrease the external clock frequency */ ++ decrease_clk_freq(); ++ ++ return 0; ++} ++ ++static int lynloong_resume(struct device *dev) ++{ ++ /* Turn on the LCD */ ++ lynloong_lcd_vo_set(1); ++ ++ /* Resume clock frequency, enable the relative clocks */ ++ resume_clk_freq(); ++ enable_clocks(); ++ ++ /* Enable AMP */ ++ set_gpio_output_low(6); ++ ++ return 0; ++} ++ ++static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend, ++ lynloong_resume); ++#endif /* !CONFIG_PM */ ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "lynloong_pc", ++ }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "lynloong_pc", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &lynloong_pm_ops, ++#endif ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int __init lynloong_init(void) ++{ ++ int ret; ++ ++ pr_info("LynLoong platform specific driver loaded.\n"); ++ ++ /* Register platform stuff */ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) { ++ pr_err("Failed to register LynLoong platform driver.\n"); ++ return ret; ++ } ++ ++ ret = lynloong_backlight_init(); ++ if (ret) { ++ pr_err("Failed to register LynLoong backlight driver.\n"); ++ return ret; ++ } ++ ++ ret = lynloong_vo_init(); ++ if (ret) { ++ pr_err("Failed to register LynLoong backlight driver.\n"); ++ lynloong_vo_exit(); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit lynloong_exit(void) ++{ ++ lynloong_vo_exit(); ++ lynloong_backlight_exit(); ++ platform_driver_unregister(&platform_driver); ++ ++ pr_info("LynLoong platform specific driver unloaded.\n"); ++} ++ ++module_init(lynloong_init); ++module_exit(lynloong_exit); ++ ++MODULE_AUTHOR("Wu Zhangjin ; Xiang Yu "); ++MODULE_DESCRIPTION("LynLoong PC driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/yeeloong_ecrom.c b/drivers/platform/mips/yeeloong_ecrom.c +new file mode 100644 +index 0000000..1bfe4cf +--- /dev/null ++++ b/drivers/platform/mips/yeeloong_ecrom.c +@@ -0,0 +1,944 @@ ++/* ++ * Driver for flushing/dumping ROM of EC on YeeLoong laptop ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: liujl ++ * ++ * NOTE : ++ * The EC resources accessing and programming are supported. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define EC_MISC_DEV "ec_misc" ++#define EC_IOC_MAGIC 'E' ++ ++/* ec registers range */ ++#define EC_MAX_REGADDR 0xFFFF ++#define EC_MIN_REGADDR 0xF000 ++#define EC_RAM_ADDR 0xF800 ++ ++/* version burned address */ ++#define VER_ADDR 0xf7a1 ++#define VER_MAX_SIZE 7 ++#define EC_ROM_MAX_SIZE 0x10000 ++ ++/* ec internal register */ ++#define REG_POWER_MODE 0xF710 ++#define FLAG_NORMAL_MODE 0x00 ++#define FLAG_IDLE_MODE 0x01 ++#define FLAG_RESET_MODE 0x02 ++ ++/* ec update program flag */ ++#define PROGRAM_FLAG_NONE 0x00 ++#define PROGRAM_FLAG_IE 0x01 ++#define PROGRAM_FLAG_ROM 0x02 ++ ++/* XBI relative registers */ ++#define REG_XBISEG0 0xFEA0 ++#define REG_XBISEG1 0xFEA1 ++#define REG_XBIRSV2 0xFEA2 ++#define REG_XBIRSV3 0xFEA3 ++#define REG_XBIRSV4 0xFEA4 ++#define REG_XBICFG 0xFEA5 ++#define REG_XBICS 0xFEA6 ++#define REG_XBIWE 0xFEA7 ++#define REG_XBISPIA0 0xFEA8 ++#define REG_XBISPIA1 0xFEA9 ++#define REG_XBISPIA2 0xFEAA ++#define REG_XBISPIDAT 0xFEAB ++#define REG_XBISPICMD 0xFEAC ++#define REG_XBISPICFG 0xFEAD ++#define REG_XBISPIDATR 0xFEAE ++#define REG_XBISPICFG2 0xFEAF ++ ++/* commands definition for REG_XBISPICMD */ ++#define SPICMD_WRITE_STATUS 0x01 ++#define SPICMD_BYTE_PROGRAM 0x02 ++#define SPICMD_READ_BYTE 0x03 ++#define SPICMD_WRITE_DISABLE 0x04 ++#define SPICMD_READ_STATUS 0x05 ++#define SPICMD_WRITE_ENABLE 0x06 ++#define SPICMD_HIGH_SPEED_READ 0x0B ++#define SPICMD_POWER_DOWN 0xB9 ++#define SPICMD_SST_EWSR 0x50 ++#define SPICMD_SST_SEC_ERASE 0x20 ++#define SPICMD_SST_BLK_ERASE 0x52 ++#define SPICMD_SST_CHIP_ERASE 0x60 ++#define SPICMD_FRDO 0x3B ++#define SPICMD_SEC_ERASE 0xD7 ++#define SPICMD_BLK_ERASE 0xD8 ++#define SPICMD_CHIP_ERASE 0xC7 ++ ++/* bits definition for REG_XBISPICFG */ ++#define SPICFG_AUTO_CHECK 0x01 ++#define SPICFG_SPI_BUSY 0x02 ++#define SPICFG_DUMMY_READ 0x04 ++#define SPICFG_EN_SPICMD 0x08 ++#define SPICFG_LOW_SPICS 0x10 ++#define SPICFG_EN_SHORT_READ 0x20 ++#define SPICFG_EN_OFFSET_READ 0x40 ++#define SPICFG_EN_FAST_READ 0x80 ++ ++/* watchdog timer registers */ ++#define REG_WDTCFG 0xfe80 ++#define REG_WDTPF 0xfe81 ++#define REG_WDT 0xfe82 ++ ++/* lpc configure register */ ++#define REG_LPCCFG 0xfe95 ++ ++/* 8051 reg */ ++#define REG_PXCFG 0xff14 ++ ++/* Fan register in KB3310 */ ++#define REG_ECFAN_SPEED_LEVEL 0xf4e4 ++#define REG_ECFAN_SWITCH 0xf4d2 ++ ++/* the ec flash rom id number */ ++#define EC_ROM_PRODUCT_ID_SPANSION 0x01 ++#define EC_ROM_PRODUCT_ID_MXIC 0xC2 ++#define EC_ROM_PRODUCT_ID_AMIC 0x37 ++#define EC_ROM_PRODUCT_ID_EONIC 0x1C ++ ++/* misc ioctl operations */ ++#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int) ++#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int) ++#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int) ++#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int) ++#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int) ++ ++/* start address for programming of EC content or IE */ ++/* ec running code start address */ ++#define EC_START_ADDR 0x00000000 ++/* ec information element storing address */ ++#define IE_START_ADDR 0x00020000 ++ ++/* EC state */ ++#define EC_STATE_IDLE 0x00 /* ec in idle state */ ++#define EC_STATE_BUSY 0x01 /* ec in busy state */ ++ ++/* timeout value for programming */ ++#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */ ++/* command checkout timeout including cmd to port or state flag check */ ++#define EC_CMD_TIMEOUT 0x1000 ++#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */ ++#define EC_MAX_DELAY_UNIT (10) /* every time for polling */ ++#define SPI_FINISH_WAIT_TIME 10 ++/* EC content max size */ ++#define EC_CONTENT_MAX_SIZE (64 * 1024) ++#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR) ++ ++/* the register operation access struct */ ++struct ec_reg { ++ u32 addr; /* the address of kb3310 registers */ ++ u8 val; /* the register value */ ++}; ++ ++struct ec_info { ++ u32 start_addr; ++ u32 size; ++ u8 *buf; ++}; ++ ++/* open for using rom protection action */ ++#define EC_ROM_PROTECTION ++ ++/* enable the chip reset mode */ ++static int ec_init_reset_mode(void) ++{ ++ int timeout; ++ unsigned char status = 0; ++ int ret = 0; ++ ++ /* make chip goto reset mode */ ++ ret = ec_query_seq(CMD_INIT_RESET_MODE); ++ if (ret < 0) { ++ printk(KERN_ERR "ec init reset mode failed.\n"); ++ goto out; ++ } ++ ++ /* make the action take active */ ++ timeout = EC_CMD_TIMEOUT; ++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; ++ while (timeout--) { ++ if (status) { ++ udelay(EC_REG_DELAY); ++ break; ++ } ++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; ++ udelay(EC_REG_DELAY); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR "ec rom fixup : can't check reset status.\n"); ++ ret = -EINVAL; ++ } else ++ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout, ++ EC_CMD_TIMEOUT - timeout, status); ++ ++ /* set MCU to reset mode */ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_PXCFG); ++ status |= (1 << 0); ++ ec_write(REG_PXCFG, status); ++ udelay(EC_REG_DELAY); ++ ++ /* disable FWH/LPC */ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_LPCCFG); ++ status &= ~(1 << 7); ++ ec_write(REG_LPCCFG, status); ++ udelay(EC_REG_DELAY); ++ ++ printk(KERN_INFO "entering reset mode ok..............\n"); ++ ++ out: ++ return ret; ++} ++ ++/* make ec exit from reset mode */ ++static void ec_exit_reset_mode(void) ++{ ++ unsigned char regval; ++ ++ udelay(EC_REG_DELAY); ++ regval = ec_read(REG_LPCCFG); ++ regval |= (1 << 7); ++ ec_write(REG_LPCCFG, regval); ++ regval = ec_read(REG_PXCFG); ++ regval &= ~(1 << 0); ++ ec_write(REG_PXCFG, regval); ++ printk(KERN_INFO "exit reset mode ok..................\n"); ++ ++ return; ++} ++ ++/* make ec disable WDD */ ++static void ec_disable_WDD(void) ++{ ++ unsigned char status; ++ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_WDTCFG); ++ ec_write(REG_WDTPF, 0x03); ++ ec_write(REG_WDTCFG, (status & 0x80) | 0x48); ++ printk(KERN_INFO "Disable WDD ok..................\n"); ++ ++ return; ++} ++ ++/* make ec enable WDD */ ++static void ec_enable_WDD(void) ++{ ++ unsigned char status; ++ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_WDTCFG); ++ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */ ++ ec_write(REG_WDTCFG, (status & 0x80) | 0x03); ++ printk(KERN_INFO "Enable WDD ok..................\n"); ++ ++ return; ++} ++ ++/* make ec goto idle mode */ ++static int ec_init_idle_mode(void) ++{ ++ int timeout; ++ unsigned char status = 0; ++ int ret = 0; ++ ++ ec_query_seq(CMD_INIT_IDLE_MODE); ++ ++ /* make the action take active */ ++ timeout = EC_CMD_TIMEOUT; ++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; ++ while (timeout--) { ++ if (status) { ++ udelay(EC_REG_DELAY); ++ break; ++ } ++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; ++ udelay(EC_REG_DELAY); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR "ec rom fixup : can't check out the status.\n"); ++ ret = -EINVAL; ++ } else ++ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout, ++ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE)); ++ ++ printk(KERN_INFO "entering idle mode ok...................\n"); ++ ++ return ret; ++} ++ ++/* make ec exit from idle mode */ ++static int ec_exit_idle_mode(void) ++{ ++ ++ ec_query_seq(CMD_EXIT_IDLE_MODE); ++ ++ printk(KERN_INFO "exit idle mode ok...................\n"); ++ ++ return 0; ++} ++ ++static int ec_instruction_cycle(void) ++{ ++ unsigned long timeout; ++ int ret = 0; ++ ++ timeout = EC_FLASH_TIMEOUT; ++ while (timeout-- >= 0) { ++ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY)) ++ break; ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ return ret; ++} ++ ++/* To see if the ec is in busy state or not. */ ++static inline int ec_flash_busy(unsigned long timeout) ++{ ++ /* assurance the first command be going to rom */ ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++#if 1 ++ timeout = timeout / EC_MAX_DELAY_UNIT; ++ while (timeout-- > 0) { ++ /* check the rom's status of busy flag */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) ++ return EC_STATE_IDLE; ++ udelay(EC_MAX_DELAY_UNIT); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_FLASH_BUSY : timeout for check rom flag.\n"); ++ return EC_STATE_BUSY; ++ } ++#else ++ /* check the rom's status of busy flag */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++ ++ timeout = timeout / EC_MAX_DELAY_UNIT; ++ while (timeout-- > 0) { ++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) ++ return EC_STATE_IDLE; ++ udelay(EC_MAX_DELAY_UNIT); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_FLASH_BUSY : timeout for check rom flag.\n"); ++ return EC_STATE_BUSY; ++ } ++#endif ++ ++ return EC_STATE_IDLE; ++} ++ ++static int rom_instruction_cycle(unsigned char cmd) ++{ ++ unsigned long timeout = 0; ++ ++ switch (cmd) { ++ case SPICMD_READ_STATUS: ++ case SPICMD_WRITE_ENABLE: ++ case SPICMD_WRITE_DISABLE: ++ case SPICMD_READ_BYTE: ++ case SPICMD_HIGH_SPEED_READ: ++ timeout = 0; ++ break; ++ case SPICMD_WRITE_STATUS: ++ timeout = 300 * 1000; ++ break; ++ case SPICMD_BYTE_PROGRAM: ++ timeout = 5 * 1000; ++ break; ++ case SPICMD_SST_SEC_ERASE: ++ case SPICMD_SEC_ERASE: ++ timeout = 1000 * 1000; ++ break; ++ case SPICMD_SST_BLK_ERASE: ++ case SPICMD_BLK_ERASE: ++ timeout = 3 * 1000 * 1000; ++ break; ++ case SPICMD_SST_CHIP_ERASE: ++ case SPICMD_CHIP_ERASE: ++ timeout = 20 * 1000 * 1000; ++ break; ++ default: ++ timeout = EC_SPICMD_STANDARD_TIMEOUT; ++ } ++ if (timeout == 0) ++ return ec_instruction_cycle(); ++ if (timeout < EC_SPICMD_STANDARD_TIMEOUT) ++ timeout = EC_SPICMD_STANDARD_TIMEOUT; ++ ++ return ec_flash_busy(timeout); ++} ++ ++/* delay for start/stop action */ ++static void delay_spi(int n) ++{ ++ while (n--) ++ inb(EC_IO_PORT_HIGH); ++} ++ ++/* start the action to spi rom function */ ++static void ec_start_spi(void) ++{ ++ unsigned char val; ++ ++ delay_spi(SPI_FINISH_WAIT_TIME); ++ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK; ++ ec_write(REG_XBISPICFG, val); ++ delay_spi(SPI_FINISH_WAIT_TIME); ++} ++ ++/* stop the action to spi rom function */ ++static void ec_stop_spi(void) ++{ ++ unsigned char val; ++ ++ delay_spi(SPI_FINISH_WAIT_TIME); ++ val = ++ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK)); ++ ec_write(REG_XBISPICFG, val); ++ delay_spi(SPI_FINISH_WAIT_TIME); ++} ++ ++/* read one byte from xbi interface */ ++static int ec_read_byte(unsigned int addr, unsigned char *byte) ++{ ++ int ret = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* write the address */ ++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); ++ /* start action */ ++ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ); ++ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ *byte = ec_read(REG_XBISPIDAT); ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* write one byte to ec rom */ ++static int ec_write_byte(unsigned int addr, unsigned char byte) ++{ ++ int ret = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* write the address */ ++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); ++ ec_write(REG_XBISPIDAT, byte); ++ /* start action */ ++ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM); ++ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* unprotect SPI ROM */ ++/* EC_ROM_unprotect function code */ ++static int EC_ROM_unprotect(void) ++{ ++ unsigned char status; ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); ++ return 1; ++ } ++ ++ /* unprotect the status register of rom */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n"); ++ return 1; ++ } ++ status = ec_read(REG_XBISPIDAT); ++ ec_write(REG_XBISPIDAT, status & 0x02); ++ if (ec_instruction_cycle() < 0) { ++ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n"); ++ return 1; ++ } ++ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); ++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n"); ++ return 1; ++ } ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* erase one block or chip or sector as needed */ ++static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr) ++{ ++ unsigned char status; ++ int ret = 0, i = 0; ++ int unprotect_count = 3; ++ int check_flag = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++#ifdef EC_ROM_PROTECTION ++ /* added for re-check SPICMD_READ_STATUS */ ++ while (unprotect_count-- > 0) { ++ if (EC_ROM_unprotect()) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* first time:500ms --> 5.5sec -->10.5sec */ ++ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++) ++ udelay(50000); ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) ++ == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); ++ } else { ++ status = ec_read(REG_XBISPIDAT); ++ printk(KERN_INFO "Read unprotect status : 0x%x\n", ++ status); ++ if ((status & 0x1C) == 0x00) { ++ printk(KERN_INFO ++ "Read unprotect status OK1 : 0x%x\n", ++ status & 0x1C); ++ check_flag = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!check_flag) { ++ printk(KERN_INFO "SPI ROM unprotect fail.\n"); ++ return 1; ++ } ++#endif ++ ++ /* block address fill */ ++ if (erase_cmd == SPICMD_BLK_ERASE) { ++ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0); ++ } ++ ++ /* erase the whole chip first */ ++ ec_write(REG_XBISPICMD, erase_cmd); ++ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* update the whole rom content with H/W mode ++ * PLEASE USING ec_unit_erase() FIRSTLY ++ */ ++static int ec_program_rom(struct ec_info *info, int flag) ++{ ++ unsigned int addr = 0; ++ unsigned long size = 0; ++ unsigned char *ptr = NULL; ++ unsigned char data; ++ unsigned char val = 0; ++ int ret = 0; ++ int i, j; ++ unsigned char status; ++ ++ /* modify for program serial No. ++ * set IE_START_ADDR & use idle mode, ++ * disable WDD ++ */ ++ if (flag == PROGRAM_FLAG_ROM) { ++ ret = ec_init_reset_mode(); ++ addr = info->start_addr + EC_START_ADDR; ++ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n"); ++ } else if (flag == PROGRAM_FLAG_IE) { ++ ret = ec_init_idle_mode(); ++ ec_disable_WDD(); ++ addr = info->start_addr + IE_START_ADDR; ++ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n"); ++ } else { ++ return 0; ++ } ++ ++ if (ret < 0) { ++ if (flag == PROGRAM_FLAG_IE) ++ ec_enable_WDD(); ++ return ret; ++ } ++ ++ size = info->size; ++ ptr = info->buf; ++ printk(KERN_INFO "starting update ec ROM..............\n"); ++ ++ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr); ++ if (ret) { ++ printk(KERN_ERR "program ec : erase block failed.\n"); ++ goto out; ++ } ++ printk(KERN_ERR "program ec : erase block OK.\n"); ++ ++ i = 0; ++ while (i < size) { ++ data = *(ptr + i); ++ ec_write_byte(addr, data); ++ ec_read_byte(addr, &val); ++ if (val != data) { ++ ec_write_byte(addr, data); ++ ec_read_byte(addr, &val); ++ if (val != data) { ++ printk(KERN_INFO ++ "EC : Second flash program failed at:\t"); ++ printk(KERN_INFO ++ "addr : 0x%x, source : 0x%x, dest: 0x%x\n", ++ addr, data, val); ++ printk(KERN_INFO "This should not happen... STOP\n"); ++ break; ++ } ++ } ++ i++; ++ addr++; ++ } ++ ++#ifdef EC_ROM_PROTECTION ++ /* we should start spi access firstly */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n"); ++ goto out1; ++ } ++ ++ /* protect the status register of rom */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); ++ goto out1; ++ } ++ status = ec_read(REG_XBISPIDAT); ++ ++ ec_write(REG_XBISPIDAT, status | 0x1C); ++ if (ec_instruction_cycle() < 0) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : write status value failed.\n"); ++ goto out1; ++ } ++ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); ++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n"); ++ goto out1; ++ } ++#endif ++ ++ /* disable the write action to spi rom */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n"); ++ goto out1; ++ } ++ ++ out1: ++ /* we should stop spi access firstly */ ++ ec_stop_spi(); ++ out: ++ /* for security */ ++ for (j = 0; j < 2000; j++) ++ udelay(1000); ++ ++ /* modify for program serial No. ++ * after program No exit idle mode ++ * and enable WDD ++ */ ++ if (flag == PROGRAM_FLAG_ROM) { ++ /* exit from the reset mode */ ++ ec_exit_reset_mode(); ++ } else { ++ /* ec exit from idle mode */ ++ ret = ec_exit_idle_mode(); ++ ec_enable_WDD(); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* ioctl */ ++static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd, ++ u_long arg) ++{ ++ struct ec_info ecinfo; ++ void __user *ptr = (void __user *)arg; ++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); ++ int ret = 0; ++ ++ switch (cmd) { ++ case IOCTL_RDREG: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg read : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_MAX_REGADDR) ++ || (ecreg->addr < EC_MIN_REGADDR)) { ++ printk(KERN_ERR ++ "reg read : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ecreg->val = ec_read(ecreg->addr); ++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg read : copy to user error.\n"); ++ return -EFAULT; ++ } ++ break; ++ case IOCTL_WRREG: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg write : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_MAX_REGADDR) ++ || (ecreg->addr < EC_MIN_REGADDR)) { ++ printk(KERN_ERR ++ "reg write : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ec_write(ecreg->addr, ecreg->val); ++ break; ++ case IOCTL_READ_EC: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "spi read : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_RAM_ADDR) ++ && (ecreg->addr < EC_MAX_REGADDR)) { ++ printk(KERN_ERR ++ "spi read : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ec_read_byte(ecreg->addr, &(ecreg->val)); ++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "spi read : copy to user error.\n"); ++ return -EFAULT; ++ } ++ break; ++ case IOCTL_PROGRAM_IE: ++ ecinfo.start_addr = EC_START_ADDR; ++ ecinfo.size = EC_CONTENT_MAX_SIZE; ++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); ++ if (ecinfo.buf == NULL) { ++ printk(KERN_ERR "program ie : kmalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size); ++ if (ret) { ++ printk(KERN_ERR "program ie : copy from user error.\n"); ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ return -EFAULT; ++ } ++ ++ /* use ec_program_rom to write serial No */ ++ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE); ++ ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ break; ++ case IOCTL_PROGRAM_EC: ++ ecinfo.start_addr = EC_START_ADDR; ++ if (get_user((ecinfo.size), (u32 *) ptr)) { ++ printk(KERN_ERR "program ec : get user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) { ++ printk(KERN_ERR "program ec : size out of limited.\n"); ++ return -EINVAL; ++ } ++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); ++ if (ecinfo.buf == NULL) { ++ printk(KERN_ERR "program ec : kmalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size); ++ if (ret) { ++ printk(KERN_ERR "program ec : copy from user error.\n"); ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ return -EFAULT; ++ } ++ ++ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM); ++ ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static long misc_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg); ++} ++ ++static int misc_open(struct inode *inode, struct file *filp) ++{ ++ struct ec_reg *ecreg = NULL; ++ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL); ++ if (ecreg) ++ filp->private_data = ecreg; ++ ++ return ecreg ? 0 : -ENOMEM; ++} ++ ++static int misc_release(struct inode *inode, struct file *filp) ++{ ++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); ++ ++ filp->private_data = NULL; ++ kfree(ecreg); ++ ++ return 0; ++} ++ ++static const struct file_operations ecmisc_fops = { ++ .open = misc_open, ++ .release = misc_release, ++ .read = NULL, ++ .write = NULL, ++#ifdef CONFIG_64BIT ++ .compat_ioctl = misc_compat_ioctl, ++#else ++ .ioctl = misc_ioctl, ++#endif ++}; ++ ++static struct miscdevice ecmisc_device = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = EC_MISC_DEV, ++ .fops = &ecmisc_fops ++}; ++ ++static int __init ecmisc_init(void) ++{ ++ int ret; ++ ++ printk(KERN_INFO "EC misc device init.\n"); ++ ret = misc_register(&ecmisc_device); ++ ++ return ret; ++} ++ ++static void __exit ecmisc_exit(void) ++{ ++ printk(KERN_INFO "EC misc device exit.\n"); ++ misc_deregister(&ecmisc_device); ++} ++ ++module_init(ecmisc_init); ++module_exit(ecmisc_exit); ++ ++MODULE_AUTHOR("liujl "); ++MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c +new file mode 100644 +index 0000000..32a2bdb +--- /dev/null ++++ b/drivers/platform/mips/yeeloong_laptop.c +@@ -0,0 +1,1360 @@ ++/* ++ * Driver for YeeLoong laptop extras ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin , Liu Junliang ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include /* for backlight subdriver */ ++#include ++#include /* for hwmon subdriver */ ++#include ++#include /* for video output subdriver */ ++#include /* for lcd output subdriver */ ++#include /* for hotkey subdriver */ ++#include ++#include ++#include ++#include /* for AC & Battery subdriver */ ++#include /* for register_reboot_notifier */ ++#include /* for register_pm_notifier */ ++ ++#include ++ ++#include /* for loongson_cmdline */ ++#include ++ ++#define ON 1 ++#define OFF 0 ++#define EVENT_START EVENT_LID ++ ++/* common function */ ++#define EC_VER_LEN 64 ++ ++static int ec_version_before(char *version) ++{ ++ char *p, ec_ver[EC_VER_LEN]; ++ ++ p = strstr(loongson_cmdline, "EC_VER="); ++ if (!p) ++ memset(ec_ver, 0, EC_VER_LEN); ++ else { ++ strncpy(ec_ver, p, EC_VER_LEN); ++ p = strstr(ec_ver, " "); ++ if (p) ++ *p = '\0'; ++ } ++ ++ return (strncasecmp(ec_ver, version, 64) < 0); ++} ++ ++/* backlight subdriver */ ++#define MIN_BRIGHTNESS 1 ++#define MAX_BRIGHTNESS 8 ++ ++static int yeeloong_set_brightness(struct backlight_device *bd) ++{ ++ unsigned char level; ++ static unsigned char old_level; ++ ++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && ++ bd->props.power == FB_BLANK_UNBLANK) ? ++ bd->props.brightness : 0; ++ ++ level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS); ++ ++ /* Avoid to modify the brightness when EC is tuning it */ ++ if (old_level != level) { ++ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level) ++ ec_write(REG_DISPLAY_BRIGHTNESS, level); ++ old_level = level; ++ } ++ ++ return 0; ++} ++ ++static int yeeloong_get_brightness(struct backlight_device *bd) ++{ ++ return ec_read(REG_DISPLAY_BRIGHTNESS); ++} ++ ++static struct backlight_ops backlight_ops = { ++ .get_brightness = yeeloong_get_brightness, ++ .update_status = yeeloong_set_brightness, ++}; ++ ++static struct backlight_device *yeeloong_backlight_dev; ++ ++static int yeeloong_backlight_init(void) ++{ ++ int ret; ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.max_brightness = MAX_BRIGHTNESS; ++ props.type = BACKLIGHT_PLATFORM; ++ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL, ++ NULL, &backlight_ops, &props); ++ ++ if (IS_ERR(yeeloong_backlight_dev)) { ++ ret = PTR_ERR(yeeloong_backlight_dev); ++ yeeloong_backlight_dev = NULL; ++ return ret; ++ } ++ ++ yeeloong_backlight_dev->props.brightness = ++ yeeloong_get_brightness(yeeloong_backlight_dev); ++ backlight_update_status(yeeloong_backlight_dev); ++ ++ return 0; ++} ++ ++static void yeeloong_backlight_exit(void) ++{ ++ if (yeeloong_backlight_dev) { ++ backlight_device_unregister(yeeloong_backlight_dev); ++ yeeloong_backlight_dev = NULL; ++ } ++} ++ ++/* AC & Battery subdriver */ ++ ++static struct power_supply yeeloong_ac, yeeloong_bat; ++ ++#define RET (val->intval) ++ ++#define BAT_CAP_CRITICAL 5 ++#define BAT_CAP_HIGH 95 ++ ++#define get_bat(type) \ ++ ec_read(REG_BAT_##type) ++ ++#define get_bat_l(type) \ ++ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW)) ++ ++static int yeeloong_get_ac_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ if (psp == POWER_SUPPLY_PROP_ONLINE) ++ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN); ++ ++ return 0; ++} ++ ++static enum power_supply_property yeeloong_ac_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++}; ++ ++static struct power_supply yeeloong_ac = { ++ .name = "yeeloong-ac", ++ .type = POWER_SUPPLY_TYPE_MAINS, ++ .properties = yeeloong_ac_props, ++ .num_properties = ARRAY_SIZE(yeeloong_ac_props), ++ .get_property = yeeloong_get_ac_props, ++}; ++ ++static inline bool is_bat_in(void) ++{ ++ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN); ++} ++ ++static int get_bat_temp(void) ++{ ++ return get_bat_l(TEMPERATURE) * 10; ++} ++ ++static int get_bat_current(void) ++{ ++ return -(s16)get_bat_l(CURRENT); ++} ++ ++static int get_bat_voltage(void) ++{ ++ return get_bat_l(VOLTAGE); ++} ++ ++static char *get_manufacturer(void) ++{ ++ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO"; ++} ++ ++static int get_relative_cap(void) ++{ ++ /* ++ * When the relative capacity becomes 2, the hardware is observed to ++ * have been turned off forcely. so, we must tune it be suitable to ++ * make the software do related actions. ++ */ ++ int tmp = get_bat_l(RELATIVE_CAP); ++ ++ if (tmp <= (BAT_CAP_CRITICAL * 2)) ++ tmp -= 3; ++ ++ return tmp; ++} ++ ++static int yeeloong_get_bat_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ switch (psp) { ++ /* Fixed information */ ++ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: ++ /* mV -> µV */ ++ RET = get_bat_l(DESIGN_VOL) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ++ /* mAh->µAh */ ++ RET = get_bat_l(DESIGN_CAP) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ /* µAh */ ++ RET = get_bat_l(FULLCHG_CAP) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_MANUFACTURER: ++ val->strval = get_manufacturer(); ++ break; ++ /* Dynamic information */ ++ case POWER_SUPPLY_PROP_PRESENT: ++ RET = is_bat_in(); ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ /* mA -> µA */ ++ RET = is_bat_in() ? get_bat_current() * 1000 : 0; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ /* mV -> µV */ ++ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0; ++ break; ++ case POWER_SUPPLY_PROP_TEMP: ++ /* Celcius */ ++ RET = is_bat_in() ? get_bat_temp() : 0; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY: ++ RET = is_bat_in() ? get_relative_cap() : 0; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: { ++ int status; ++ ++ if (!is_bat_in()) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ break; ++ } ++ ++ status = get_bat(STATUS); ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; ++ ++ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ break; ++ } ++ ++ if (status & BIT_BAT_STATUS_FULL) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; ++ else { ++ int curr_cap = get_relative_cap(); ++ ++ if (status & BIT_BAT_STATUS_LOW) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; ++ if (curr_cap <= BAT_CAP_CRITICAL) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; ++ } else if (curr_cap >= BAT_CAP_HIGH) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; ++ } ++ } break; ++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ++ /* seconds */ ++ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0; ++ break; ++ case POWER_SUPPLY_PROP_STATUS: { ++ int charge = get_bat(CHARGE); ++ ++ RET = POWER_SUPPLY_STATUS_UNKNOWN; ++ if (charge & FLAG_BAT_CHARGE_DISCHARGE) ++ RET = POWER_SUPPLY_STATUS_DISCHARGING; ++ else if (charge & FLAG_BAT_CHARGE_CHARGE) ++ RET = POWER_SUPPLY_STATUS_CHARGING; ++ } break; ++ case POWER_SUPPLY_PROP_HEALTH: { ++ int status; ++ ++ if (!is_bat_in()) { ++ RET = POWER_SUPPLY_HEALTH_UNKNOWN; ++ break; ++ } ++ ++ status = get_bat(STATUS); ++ RET = POWER_SUPPLY_HEALTH_GOOD; ++ ++ if (status & (BIT_BAT_STATUS_DESTROY | ++ BIT_BAT_STATUS_LOW)) ++ RET = POWER_SUPPLY_HEALTH_DEAD; ++ if (get_bat(CHARGE_STATUS) & ++ BIT_BAT_CHARGE_STATUS_OVERTEMP) ++ RET = POWER_SUPPLY_HEALTH_OVERHEAT; ++ } break; ++ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */ ++ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10; ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++#undef RET ++ ++static enum power_supply_property yeeloong_bat_props[] = { ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL, ++ POWER_SUPPLY_PROP_CHARGE_NOW, ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_HEALTH, ++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_CAPACITY_LEVEL, ++ POWER_SUPPLY_PROP_TEMP, ++ POWER_SUPPLY_PROP_MANUFACTURER, ++}; ++ ++static struct power_supply yeeloong_bat = { ++ .name = "yeeloong-bat", ++ .type = POWER_SUPPLY_TYPE_BATTERY, ++ .properties = yeeloong_bat_props, ++ .num_properties = ARRAY_SIZE(yeeloong_bat_props), ++ .get_property = yeeloong_get_bat_props, ++}; ++ ++static int ac_bat_initialized; ++ ++static int yeeloong_bat_init(void) ++{ ++ int ret; ++ ++ ret = power_supply_register(NULL, &yeeloong_ac); ++ if (ret) ++ return ret; ++ ret = power_supply_register(NULL, &yeeloong_bat); ++ if (ret) { ++ power_supply_unregister(&yeeloong_ac); ++ return ret; ++ } ++ ac_bat_initialized = 1; ++ ++ return 0; ++} ++ ++static void yeeloong_bat_exit(void) ++{ ++ ac_bat_initialized = 0; ++ ++ power_supply_unregister(&yeeloong_ac); ++ power_supply_unregister(&yeeloong_bat); ++} ++/* hwmon subdriver */ ++ ++#define MIN_FAN_SPEED 0 ++#define MAX_FAN_SPEED 3 ++ ++#define get_fan(type) \ ++ ec_read(REG_FAN_##type) ++ ++#define set_fan(type, val) \ ++ ec_write(REG_FAN_##type, val) ++ ++static inline int get_fan_speed_level(void) ++{ ++ return get_fan(SPEED_LEVEL); ++} ++static inline void set_fan_speed_level(int speed) ++{ ++ set_fan(SPEED_LEVEL, speed); ++} ++ ++static inline int get_fan_mode(void) ++{ ++ return get_fan(AUTO_MAN_SWITCH); ++} ++static inline void set_fan_mode(int mode) ++{ ++ set_fan(AUTO_MAN_SWITCH, mode); ++} ++ ++/* ++ * 3 different modes: Full speed(0); manual mode(1); auto mode(2) ++ */ ++static int get_fan_pwm_enable(void) ++{ ++ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 : ++ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1; ++} ++ ++static void set_fan_pwm_enable(int mode) ++{ ++ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL); ++ if (mode == 0) ++ set_fan_speed_level(MAX_FAN_SPEED); ++} ++ ++static int get_fan_pwm(void) ++{ ++ return get_fan_speed_level(); ++} ++ ++static void set_fan_pwm(int value) ++{ ++ if (get_fan_mode() != BIT_FAN_MANUAL) ++ return; ++ ++ value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED); ++ ++ /* We must ensure the fan is on */ ++ if (value > 0) ++ set_fan(CONTROL, ON); ++ ++ set_fan_speed_level(value); ++} ++ ++static inline int get_fan_speed(void) ++{ ++ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW); ++} ++ ++static int get_fan_rpm(void) ++{ ++ return FAN_SPEED_DIVIDER / get_fan_speed(); ++} ++ ++static int get_cpu_temp(void) ++{ ++ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000; ++} ++ ++static int get_cpu_temp_max(void) ++{ ++ return 60 * 1000; ++} ++ ++static int get_bat_temp_alarm(void) ++{ ++ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP); ++} ++ ++static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long value; ++ ++ if (!count) ++ return 0; ++ ++ ret = kstrtoul(buf, 10, &value); ++ if (ret) ++ return ret; ++ ++ set(value); ++ ++ return count; ++} ++ ++static ssize_t show_sys_hwmon(int (*get) (void), char *buf) ++{ ++ return sprintf(buf, "%d\n", get()); ++} ++ ++#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ ++ static ssize_t show_##_name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++ { \ ++ return show_sys_hwmon(_set, buf); \ ++ } \ ++ static ssize_t store_##_name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ return store_sys_hwmon(_get, buf, count); \ ++ } \ ++ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); ++ ++CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL); ++CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm); ++CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable, ++ set_fan_pwm_enable); ++CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL); ++CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL); ++CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL); ++CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL); ++CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL); ++CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL); ++ ++static ssize_t ++show_name(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "yeeloong\n"); ++} ++ ++static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); ++ ++static struct attribute *hwmon_attributes[] = { ++ &sensor_dev_attr_pwm1.dev_attr.attr, ++ &sensor_dev_attr_pwm1_enable.dev_attr.attr, ++ &sensor_dev_attr_fan1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_max.dev_attr.attr, ++ &sensor_dev_attr_temp2_input.dev_attr.attr, ++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, ++ &sensor_dev_attr_curr1_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_name.dev_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group hwmon_attribute_group = { ++ .attrs = hwmon_attributes ++}; ++ ++static struct device *yeeloong_hwmon_dev; ++ ++static int yeeloong_hwmon_init(void) ++{ ++ int ret; ++ ++ yeeloong_hwmon_dev = hwmon_device_register(NULL); ++ if (IS_ERR(yeeloong_hwmon_dev)) { ++ yeeloong_hwmon_dev = NULL; ++ return PTR_ERR(yeeloong_hwmon_dev); ++ } ++ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj, ++ &hwmon_attribute_group); ++ if (ret) { ++ hwmon_device_unregister(yeeloong_hwmon_dev); ++ yeeloong_hwmon_dev = NULL; ++ return ret; ++ } ++ /* ensure fan is set to auto mode */ ++ set_fan_pwm_enable(2); ++ ++ return 0; ++} ++ ++static void yeeloong_hwmon_exit(void) ++{ ++ if (yeeloong_hwmon_dev) { ++ sysfs_remove_group(&yeeloong_hwmon_dev->kobj, ++ &hwmon_attribute_group); ++ hwmon_device_unregister(yeeloong_hwmon_dev); ++ yeeloong_hwmon_dev = NULL; ++ } ++} ++ ++/* video output subdriver */ ++ ++#define LCD 0 ++#define CRT 1 ++#define VOD_NUM 2 /* The total number of video output device*/ ++ ++static struct output_device *vod[VOD_NUM]; ++ ++static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT}; ++ ++static int get_vo_dev(struct output_device *od) ++{ ++ int i, dev; ++ ++ dev = -1; ++ for (i = 0; i < VOD_NUM; i++) ++ if (od == vod[i]) ++ dev = i; ++ ++ return dev; ++} ++ ++static int vo_get_status(int dev) ++{ ++ return ec_read(vor[dev]); ++} ++ ++static int yeeloong_vo_get_status(struct output_device *od) ++{ ++ int vd; ++ ++ vd = get_vo_dev(od); ++ if (vd != -1) ++ return vo_get_status(vd); ++ ++ return -ENODEV; ++} ++ ++static void vo_set_state(int dev, int state) ++{ ++ int addr; ++ unsigned long value; ++ ++ switch (dev) { ++ case LCD: ++ addr = 0x31; ++ break; ++ case CRT: ++ addr = 0x21; ++ break; ++ default: ++ /* return directly if the wrong video output device */ ++ return; ++ } ++ ++ outb(addr, 0x3c4); ++ value = inb(0x3c5); ++ ++ switch (dev) { ++ case LCD: ++ value |= (state ? 0x03 : 0x02); ++ break; ++ case CRT: ++ if (state) ++ clear_bit(7, &value); ++ else ++ set_bit(7, &value); ++ break; ++ default: ++ break; ++ } ++ ++ outb(addr, 0x3c4); ++ outb(value, 0x3c5); ++ ++ if (dev == LCD) ++ ec_write(REG_BACKLIGHT_CTRL, state); ++} ++ ++static int yeeloong_vo_set_state(struct output_device *od) ++{ ++ int vd; ++ ++ vd = get_vo_dev(od); ++ if (vd == -1) ++ return -ENODEV; ++ ++ if (vd == CRT && !vo_get_status(vd)) ++ return 0; ++ ++ vo_set_state(vd, !!od->request_state); ++ ++ return 0; ++} ++ ++static struct output_properties vop = { ++ .set_state = yeeloong_vo_set_state, ++ .get_status = yeeloong_vo_get_status, ++}; ++ ++static int yeeloong_vo_init(void) ++{ ++ int ret, i; ++ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; ++ ++ /* Register video output device: lcd, crt */ ++ for (i = 0; i < VOD_NUM; i++) { ++ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop); ++ if (IS_ERR(vod[i])) { ++ if (i != 0) ++ video_output_unregister(vod[i-1]); ++ ret = PTR_ERR(vod[i]); ++ vod[i] = NULL; ++ return ret; ++ } ++ } ++ /* Ensure LCD is on by default */ ++ vo_set_state(LCD, ON); ++ ++ /* ++ * Turn off CRT by default, and will be enabled when the CRT ++ * connectting event reported by SCI ++ */ ++ vo_set_state(CRT, OFF); ++ ++ return 0; ++} ++ ++static void yeeloong_vo_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < VOD_NUM; i++) { ++ if (vod[i]) { ++ video_output_unregister(vod[i]); ++ vod[i] = NULL; ++ } ++ } ++} ++ ++/* lcd subdriver */ ++ ++struct lcd_device *lcd[VOD_NUM]; ++ ++static int get_lcd_dev(struct lcd_device *ld) ++{ ++ int i, dev; ++ ++ dev = -1; ++ for (i = 0; i < VOD_NUM; i++) ++ if (ld == lcd[i]) ++ dev = i; ++ ++ return dev; ++} ++ ++static int yeeloong_lcd_set_power(struct lcd_device *ld, int power) ++{ ++ int dev = get_lcd_dev(ld); ++ ++ if (power == FB_BLANK_UNBLANK) ++ vo_set_state(dev, ON); ++ if (power == FB_BLANK_POWERDOWN) ++ vo_set_state(dev, OFF); ++ ++ return 0; ++} ++ ++static int yeeloong_lcd_get_power(struct lcd_device *ld) ++{ ++ return vo_get_status(get_lcd_dev(ld)); ++} ++ ++static struct lcd_ops lcd_ops = { ++ .set_power = yeeloong_lcd_set_power, ++ .get_power = yeeloong_lcd_get_power, ++}; ++ ++static int yeeloong_lcd_init(void) ++{ ++ int ret, i; ++ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; ++ ++ /* Register video output device: lcd, crt */ ++ for (i = 0; i < VOD_NUM; i++) { ++ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops); ++ if (IS_ERR(lcd[i])) { ++ if (i != 0) ++ lcd_device_unregister(lcd[i-1]); ++ ret = PTR_ERR(lcd[i]); ++ lcd[i] = NULL; ++ return ret; ++ } ++ } ++#if 0 ++ /* This has been done by the vide output driver */ ++ ++ /* Ensure LCD is on by default */ ++ vo_set_state(LCD, ON); ++ ++ /* ++ * Turn off CRT by default, and will be enabled when the CRT ++ * connectting event reported by SCI ++ */ ++ vo_set_state(CRT, OFF); ++#endif ++ return 0; ++} ++ ++static void yeeloong_lcd_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < VOD_NUM; i++) { ++ if (lcd[i]) { ++ lcd_device_unregister(lcd[i]); ++ lcd[i] = NULL; ++ } ++ } ++} ++ ++/* hotkey subdriver */ ++ ++static struct input_dev *yeeloong_hotkey_dev; ++ ++static atomic_t reboot_flag, sleep_flag; ++#define in_sleep() (&sleep_flag) ++#define in_reboot() (&reboot_flag) ++ ++static const struct key_entry yeeloong_keymap[] = { ++ {KE_SW, EVENT_LID, { SW_LID } }, ++ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */ ++ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */ ++ {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */ ++ {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */ ++ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */ ++ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */ ++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */ ++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */ ++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */ ++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */ ++ {KE_END, 0} ++}; ++ ++static int is_fake_event(u16 keycode) ++{ ++ switch (keycode) { ++ case KEY_SLEEP: ++ case SW_LID: ++ return atomic_read(in_sleep()) | atomic_read(in_reboot()); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct key_entry *get_event_key_entry(int event, int status) ++{ ++ struct key_entry *ke; ++ static int old_brightness_status = -1; ++ static int old_volume_status = -1; ++ ++ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event); ++ if (!ke) ++ return NULL; ++ ++ switch (event) { ++ case EVENT_DISPLAY_BRIGHTNESS: ++ /* current status > old one, means up */ ++ if ((status < old_brightness_status) || (0 == status)) ++ ke++; ++ old_brightness_status = status; ++ break; ++ case EVENT_AUDIO_VOLUME: ++ if ((status < old_volume_status) || (0 == status)) ++ ke++; ++ old_volume_status = status; ++ break; ++ default: ++ break; ++ } ++ ++ return ke; ++} ++ ++static int report_lid_switch(int status) ++{ ++ static int old_status; ++ ++ /* ++ * LID is a switch button, so, two continuous same status should be ++ * ignored ++ */ ++ if (old_status != status) { ++ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status); ++ input_sync(yeeloong_hotkey_dev); ++ } ++ old_status = status; ++ ++ return status; ++} ++ ++static int crt_detect_handler(int status) ++{ ++ /* ++ * When CRT is inserted, enable its output and disable the LCD output, ++ * otherwise, do reversely. ++ */ ++ vo_set_state(CRT, status); ++ vo_set_state(LCD, !status); ++ ++ return status; ++} ++ ++static int displaytoggle_handler(int status) ++{ ++ /* EC(>=PQ1D26) does this job for us, we can not do it again, ++ * otherwise, the brightness will not resume to the normal level! */ ++ if (ec_version_before("EC_VER=PQ1D26")) ++ vo_set_state(LCD, status); ++ ++ return status; ++} ++ ++static int mypow(int x, int y) ++{ ++ int i, j = x; ++ ++ for (i = 1; i < y; i++) ++ j *= j; ++ ++ return j; ++} ++ ++static int switchvideomode_handler(int status) ++{ ++ /* Default status: CRT|LCD = 0|1 = 1 */ ++ static int bin_state = 1; ++ int i; ++ ++ /* ++ * Only enable switch video output button ++ * when CRT is connected ++ */ ++ if (!vo_get_status(CRT)) ++ return 0; ++ /* ++ * 2. no CRT connected: LCD on, CRT off ++ * 3. BOTH on ++ * 0. BOTH off ++ * 1. LCD off, CRT on ++ */ ++ ++ bin_state++; ++ if (bin_state > mypow(2, VOD_NUM) - 1) ++ bin_state = 0; ++ ++ for (i = 0; i < VOD_NUM; i++) ++ vo_set_state(i, bin_state & (1 << i)); ++ ++ return bin_state; ++} ++ ++static int camera_handler(int status) ++{ ++ int value; ++ ++ value = ec_read(REG_CAMERA_CONTROL); ++ ec_write(REG_CAMERA_CONTROL, value | (1 << 1)); ++ ++ return status; ++} ++ ++static int usb2_handler(int status) ++{ ++ pr_emerg("USB2 Over Current occurred\n"); ++ ++ return status; ++} ++ ++static int usb0_handler(int status) ++{ ++ pr_emerg("USB0 Over Current occurred\n"); ++ ++ return status; ++} ++ ++static int ac_bat_handler(int status) ++{ ++ if (ac_bat_initialized) { ++ power_supply_changed(&yeeloong_ac); ++ power_supply_changed(&yeeloong_bat); ++ } ++ ++ return status; ++} ++ ++struct sci_event { ++ int reg; ++ sci_handler handler; ++}; ++ ++static const struct sci_event se[] = { ++ [EVENT_AC_BAT] = {0, ac_bat_handler}, ++ [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL}, ++ [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL}, ++ [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler}, ++ [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler}, ++ [EVENT_BLACK_SCREEN] = {REG_DISPLAY_LCD, displaytoggle_handler}, ++ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL}, ++ [EVENT_LID] = {REG_LID_DETECT, NULL}, ++ [EVENT_DISPLAY_TOGGLE] = {0, switchvideomode_handler}, ++ [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler}, ++ [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler}, ++ [EVENT_WLAN] = {REG_WLAN, NULL}, ++}; ++ ++static void do_event_action(int event) ++{ ++ int status = -1; ++ struct key_entry *ke; ++ struct sci_event *sep; ++ ++ sep = (struct sci_event *)&se[event]; ++ ++ if (sep->reg != 0) ++ status = ec_read(sep->reg); ++ ++ if (status == -1) { ++ /* ec_read hasn't been called, status is invalid */ ++ return; ++ } ++ ++ if (sep->handler != NULL) ++ status = sep->handler(status); ++ ++ pr_debug("%s: event: %d status: %d\n", __func__, event, status); ++ ++ /* Report current key to user-space */ ++ ke = get_event_key_entry(event, status); ++ ++ /* ++ * Ignore the LID and SLEEP event when we are already in sleep or ++ * reboot state, this will avoid the recursive pm operations. but note: ++ * the report_lid_switch() called in arch/mips/loongson/lemote-2f/pm.c ++ * is necessary, because it is used to wake the system from sleep ++ * state. In the future, perhaps SW_LID should works like SLEEP, no ++ * need to function as a SWITCH, just report the state when the LID is ++ * closed is enough, this event can tell the software to "SLEEP", no ++ * need to tell the softwares when we are resuming from "SLEEP". ++ */ ++ if (ke && !is_fake_event(ke->keycode)) { ++ if (ke->keycode == SW_LID) ++ report_lid_switch(status); ++ else ++ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1, ++ true); ++ } ++} ++ ++/* ++ * SCI(system control interrupt) main interrupt routine ++ * ++ * We will do the query and get event number together so the interrupt routine ++ * should be longer than 120us now at least 3ms elpase for it. ++ */ ++static irqreturn_t sci_irq_handler(int irq, void *dev_id) ++{ ++ int ret, event; ++ ++ if (SCI_IRQ_NUM != irq) ++ return IRQ_NONE; ++ ++ /* Query the event number */ ++ ret = ec_query_event_num(); ++ if (ret < 0) ++ return IRQ_NONE; ++ ++ event = ec_get_event_num(); ++ if (event < EVENT_START || event > EVENT_END) ++ return IRQ_NONE; ++ ++ /* Execute corresponding actions */ ++ do_event_action(event); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Config and init some msr and gpio register properly. ++ */ ++static int sci_irq_init(void) ++{ ++ u32 hi, lo; ++ u32 gpio_base; ++ unsigned long flags; ++ int ret; ++ ++ /* Get gpio base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); ++ gpio_base = lo & 0xff00; ++ ++ /* Filter the former kb3310 interrupt for security */ ++ ret = ec_query_event_num(); ++ if (ret) ++ return ret; ++ ++ /* For filtering next number interrupt */ ++ udelay(10000); ++ ++ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN ++ * gpio : ++ * input, pull-up, no-invert, event-count and value 0, ++ * no-filter, no edge mode ++ * gpio27 map to Virtual gpio0 ++ * msr : ++ * no primary and lpc ++ * Unrestricted Z input to IG10 from Virtual gpio 0. ++ */ ++ local_irq_save(flags); ++ _rdmsr(0x80000024, &hi, &lo); ++ lo &= ~(1 << 10); ++ _wrmsr(0x80000024, hi, lo); ++ _rdmsr(0x80000025, &hi, &lo); ++ lo &= ~(1 << 10); ++ _wrmsr(0x80000025, hi, lo); ++ _rdmsr(0x80000023, &hi, &lo); ++ lo |= (0x0a << 0); ++ _wrmsr(0x80000023, hi, lo); ++ local_irq_restore(flags); ++ ++ /* Set gpio27 as sci interrupt ++ * ++ * input, pull-up, no-fliter, no-negedge, invert ++ * the sci event is just about 120us ++ */ ++ asm(".set noreorder\n"); ++ /* input enable */ ++ outl(0x00000800, (gpio_base | 0xA0)); ++ /* revert the input */ ++ outl(0x00000800, (gpio_base | 0xA4)); ++ /* event-int enable */ ++ outl(0x00000800, (gpio_base | 0xB8)); ++ asm(".set reorder\n"); ++ ++ return 0; ++} ++ ++static int notify_reboot(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ switch (event) { ++ case SYS_RESTART: ++ case SYS_HALT: ++ case SYS_POWER_OFF: ++ atomic_set(in_reboot(), 1); ++ break; ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static int notify_pm(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ switch (event) { ++ case PM_HIBERNATION_PREPARE: ++ case PM_SUSPEND_PREPARE: ++ atomic_inc(in_sleep()); ++ break; ++ case PM_POST_HIBERNATION: ++ case PM_POST_SUSPEND: ++ case PM_RESTORE_PREPARE: /* do we need this ?? */ ++ atomic_dec(in_sleep()); ++ break; ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event, ++ atomic_read(in_sleep())); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block reboot_notifier = { ++ .notifier_call = notify_reboot, ++}; ++ ++static struct notifier_block pm_notifier = { ++ .notifier_call = notify_pm, ++}; ++ ++static int yeeloong_hotkey_init(void) ++{ ++ int ret = 0; ++ ++ ret = register_reboot_notifier(&reboot_notifier); ++ if (ret) { ++ pr_err("Can't register reboot notifier\n"); ++ goto end; ++ } ++ ++ ret = register_pm_notifier(&pm_notifier); ++ if (ret) { ++ pr_err("Can't register pm notifier\n"); ++ goto free_reboot_notifier; ++ } ++ ++ ret = sci_irq_init(); ++ if (ret) { ++ pr_err("Can't init SCI interrupt\n"); ++ goto free_pm_notifier; ++ } ++ ++ ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler, ++ IRQF_ONESHOT, "sci", NULL); ++ if (ret) { ++ pr_err("Can't thread SCI interrupt handler\n"); ++ goto free_pm_notifier; ++ } ++ ++ yeeloong_hotkey_dev = input_allocate_device(); ++ ++ if (!yeeloong_hotkey_dev) { ++ ret = -ENOMEM; ++ goto free_irq; ++ } ++ ++ yeeloong_hotkey_dev->name = "HotKeys"; ++ yeeloong_hotkey_dev->phys = "button/input0"; ++ yeeloong_hotkey_dev->id.bustype = BUS_HOST; ++ yeeloong_hotkey_dev->dev.parent = NULL; ++ ++ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL); ++ if (ret) { ++ pr_err("Failed to setup input device keymap\n"); ++ goto free_dev; ++ } ++ ++ ret = input_register_device(yeeloong_hotkey_dev); ++ if (ret) ++ goto free_keymap; ++ ++ /* Update the current status of LID */ ++ report_lid_switch(ON); ++ ++#ifdef CONFIG_LOONGSON_SUSPEND ++ /* Install the real yeeloong_report_lid_status for pm.c */ ++ yeeloong_report_lid_status = report_lid_switch; ++#endif ++ return 0; ++ ++free_keymap: ++ sparse_keymap_free(yeeloong_hotkey_dev); ++free_dev: ++ input_free_device(yeeloong_hotkey_dev); ++free_irq: ++ free_irq(SCI_IRQ_NUM, NULL); ++free_pm_notifier: ++ unregister_pm_notifier(&pm_notifier); ++free_reboot_notifier: ++ unregister_reboot_notifier(&reboot_notifier); ++end: ++ return ret; ++} ++ ++static void yeeloong_hotkey_exit(void) ++{ ++ /* Free irq */ ++ free_irq(SCI_IRQ_NUM, NULL); ++ ++#ifdef CONFIG_LOONGSON_SUSPEND ++ /* Uninstall yeeloong_report_lid_status for pm.c */ ++ if (yeeloong_report_lid_status == report_lid_switch) ++ yeeloong_report_lid_status = NULL; ++#endif ++ ++ if (yeeloong_hotkey_dev) { ++ sparse_keymap_free(yeeloong_hotkey_dev); ++ input_unregister_device(yeeloong_hotkey_dev); ++ yeeloong_hotkey_dev = NULL; ++ } ++} ++ ++#ifdef CONFIG_PM ++static void usb_ports_set(int status) ++{ ++ status = !!status; ++ ++ ec_write(REG_USB0_FLAG, status); ++ ec_write(REG_USB1_FLAG, status); ++ ec_write(REG_USB2_FLAG, status); ++} ++ ++static int yeeloong_suspend(struct device *dev) ++ ++{ ++ if (ec_version_before("EC_VER=PQ1D27")) ++ vo_set_state(LCD, OFF); ++ vo_set_state(CRT, OFF); ++ usb_ports_set(OFF); ++ ++ return 0; ++} ++ ++static int yeeloong_resume(struct device *dev) ++{ ++ int ret; ++ ++ if (ec_version_before("EC_VER=PQ1D27")) ++ vo_set_state(LCD, ON); ++ vo_set_state(CRT, ON); ++ usb_ports_set(ON); ++ ++ ret = sci_irq_init(); ++ if (ret) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend, ++ yeeloong_resume); ++#endif ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "yeeloong_laptop", ++ }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "yeeloong_laptop", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &yeeloong_pm_ops, ++#endif ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int __init yeeloong_init(void) ++{ ++ int ret; ++ ++ pr_info("YeeLoong Laptop platform specific driver loaded.\n"); ++ ++ /* Register platform stuff */ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) { ++ pr_err("Failed to register YeeLoong platform driver.\n"); ++ return ret; ++ } ++ ++#define yeeloong_init_drv(drv, alias) do { \ ++ pr_info("Registered YeeLoong " alias " driver.\n"); \ ++ ret = yeeloong_ ## drv ## _init(); \ ++ if (ret) { \ ++ pr_err("Failed to register YeeLoong " alias " driver.\n"); \ ++ yeeloong_ ## drv ## _exit(); \ ++ return ret; \ ++ } \ ++} while (0) ++ ++ yeeloong_init_drv(backlight, "backlight"); ++ yeeloong_init_drv(bat, "battery and AC"); ++ yeeloong_init_drv(hwmon, "hardware monitor"); ++ yeeloong_init_drv(vo, "video output"); ++ yeeloong_init_drv(lcd, "lcd output"); ++ yeeloong_init_drv(hotkey, "hotkey input"); ++ ++ return 0; ++} ++ ++static void __exit yeeloong_exit(void) ++{ ++ yeeloong_hotkey_exit(); ++ yeeloong_lcd_exit(); ++ yeeloong_vo_exit(); ++ yeeloong_hwmon_exit(); ++ yeeloong_bat_exit(); ++ yeeloong_backlight_exit(); ++ platform_driver_unregister(&platform_driver); ++ ++ pr_info("YeeLoong platform specific driver unloaded.\n"); ++} ++ ++module_init(yeeloong_init); ++module_exit(yeeloong_exit); ++ ++MODULE_AUTHOR("Wu Zhangjin ; Liu Junliang "); ++MODULE_DESCRIPTION("YeeLoong laptop driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index b5b5c3d..f908003 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -727,6 +727,7 @@ comment "Platform RTC drivers" + config RTC_DRV_CMOS + tristate "PC-style 'CMOS'" + depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 ++ depends on !DEXXON_GDIUM + default y if X86 + help + Say "yes" here to get direct support for the real time clock +diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +index f940056..a9bb1db 100644 +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -450,6 +450,26 @@ void usb_amd_dev_put(void) + } + EXPORT_SYMBOL_GPL(usb_amd_dev_put); + ++#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) ++static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) ++{ ++ u16 cmd; ++ return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); ++} ++ ++#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) ++#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) ++ ++static int mmio_resource_enabled(struct pci_dev *pdev, int idx) ++{ ++ return pci_resource_start(pdev, idx) && mmio_enabled(pdev); ++} ++#endif ++ ++#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) + /* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. +@@ -531,15 +551,6 @@ reset_needed: + } + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + +-static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) +-{ +- u16 cmd; +- return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); +-} +- +-#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) +-#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) +- + static void quirk_usb_handoff_uhci(struct pci_dev *pdev) + { + unsigned long base = 0; +@@ -557,12 +568,11 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev) + if (base) + uhci_check_and_reset_hc(pdev, base); + } ++#else ++#define quirk_usb_handoff_uhci(x) do { } while (0) ++#endif /* CONFIG_USB_UHCI_HCD* */ + +-static int mmio_resource_enabled(struct pci_dev *pdev, int idx) +-{ +- return pci_resource_start(pdev, idx) && mmio_enabled(pdev); +-} +- ++#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + static void quirk_usb_handoff_ohci(struct pci_dev *pdev) + { + void __iomem *base; +@@ -641,7 +651,11 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) + /* Now the controller is safely in SUSPEND and nothing can wake it up */ + iounmap(base); + } ++#else ++#define quirk_usb_handoff_ohci(x) do { } while(0) ++#endif /* CONFIG_USB_OHCI_HCD* */ + ++#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) + static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { + { + /* Pegatron Lucid (ExoPC) */ +@@ -816,6 +830,9 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev) + + iounmap(base); + } ++#else ++#define quirk_usb_disable_ehci(x) do { } while (0) ++#endif /* CONFIG_USB_EHCI_HCD* */ + + /* + * handshake - spin reading a register until handshake completes +@@ -956,6 +973,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) + } + EXPORT_SYMBOL_GPL(usb_disable_xhci_ports); + ++#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) + /** + * PCI Quirks for xHCI. + * +@@ -1064,6 +1082,9 @@ hc_init: + + iounmap(base); + } ++#else ++#define quirk_usb_handoff_xhci(x) do { } while (0) ++#endif /* CONFIG_USB_UHCI_HCD* */ + + static void quirk_usb_early_handoff(struct pci_dev *pdev) + { +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index f0c0c53..84dff90 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -79,6 +79,9 @@ static void option_instat_callback(struct urb *urb); + #define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 + #define OPTION_PRODUCT_GTM380_MODEM 0x7201 + ++#define HUAWO_VENDOR_ID 0x21F5 ++#define HUAWO_PRODUCT_E1621 0x2008 ++ + #define HUAWEI_VENDOR_ID 0x12D1 + #define HUAWEI_PRODUCT_E173 0x140C + #define HUAWEI_PRODUCT_E1750 0x1406 +@@ -633,6 +636,7 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, + { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, ++ { USB_DEVICE(HUAWO_VENDOR_ID, HUAWO_PRODUCT_E1621) }, /* QUANTA 6500 chips, Unicom extensive use of this card */ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 8bf495f..f6a15b6 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -36,6 +36,12 @@ config VGASTATE + tristate + default n + ++config VIDEO_OUTPUT_CONTROL ++ tristate "Lowlevel video output switch controls" ++ help ++ This framework adds support for low-level control of the video ++ output switch. ++ + config VIDEOMODE_HELPERS + bool + +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 9ad3c17..3d869d9 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -7,6 +7,8 @@ obj-y += backlight/ + + obj-y += fbdev/ + ++#video output switch sysfs driver ++obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o + obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o + ifeq ($(CONFIG_OF),y) + obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o +diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig +index b3dd417..452035ad 100644 +--- a/drivers/video/fbdev/Kconfig ++++ b/drivers/video/fbdev/Kconfig +@@ -2450,6 +2450,19 @@ config FB_SIMPLE + Configuration re: surface address, size, and format must be provided + through device tree, or plain old platform data. + ++config FB_SM712 ++ tristate "Silicon Motion SM712 framebuffer support" ++ depends on FB && PCI ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ Frame buffer driver for the Silicon Motion SM712 chip. ++ ++ This driver is also available as a module. The module will be ++ called sm712fb. If you want to compile it as a module, say M ++ here and read . ++ + source "drivers/video/fbdev/omap/Kconfig" + source "drivers/video/fbdev/omap2/Kconfig" + source "drivers/video/fbdev/exynos/Kconfig" +diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile +index 1979aff..9b694f9 100644 +--- a/drivers/video/fbdev/Makefile ++++ b/drivers/video/fbdev/Makefile +@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o + obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o + obj-$(CONFIG_FB_PS3) += ps3fb.o + obj-$(CONFIG_FB_SM501) += sm501fb.o ++obj-$(CONFIG_FB_SM712) += sm712fb/ + obj-$(CONFIG_FB_UDL) += udlfb.o + obj-$(CONFIG_FB_SMSCUFX) += smscufx.o + obj-$(CONFIG_FB_XILINX) += xilinxfb.o +diff --git a/drivers/video/fbdev/sm712fb/Makefile b/drivers/video/fbdev/sm712fb/Makefile +new file mode 100644 +index 0000000..9bf3519 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_FB_SM712) += sm712fb.o ++ ++sm712fb-objs := sm712fb_drv.o sm712fb_accel.o +diff --git a/drivers/video/fbdev/sm712fb/TODO b/drivers/video/fbdev/sm712fb/TODO +new file mode 100644 +index 0000000..dcfd4e7 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/TODO +@@ -0,0 +1,7 @@ ++TODO: ++- Dual head support ++- refine the code, convert more registers magic numbers to macros ++- Does it really works on Big Endian machines? ++ ++Please send any patches to Greg Kroah-Hartman and ++Tom Li . +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.c b/drivers/video/fbdev/sm712fb/sm712fb_accel.c +new file mode 100644 +index 0000000..12fce1f +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.c +@@ -0,0 +1,246 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#include ++#include ++#include ++ ++#include "sm712fb_drv.h" ++#include "sm712fb_accel.h" ++ ++static inline u32 bytes_to_dword(const u8 *bytes, int length) ++{ ++ u32 dword = 0; ++ ++ switch (length) { ++ case 4: ++#ifdef __BIG_ENDIAN ++ dword += bytes[3]; ++#else ++ dword += bytes[3] << 24; ++#endif ++ case 3: ++#ifdef __BIG_ENDIAN ++ dword += bytes[2] << 8; ++#else ++ dword += bytes[2] << 16; ++#endif ++ case 2: ++#ifdef __BIG_ENDIAN ++ dword += bytes[1] << 16; ++#else ++ dword += bytes[1] << 8; ++#endif ++ case 1: ++#ifdef __BIG_ENDIAN ++ dword += bytes[0] << 24; ++#else ++ dword += bytes[0]; ++#endif ++ } ++ return dword; ++} ++ ++int sm712fb_init_accel(struct sm712fb_info *fb) ++{ ++ u8 reg; ++ ++ /* reset the 2D engine */ ++ sm712_write_seq(fb, 0x21, sm712_read_seq(fb, 0x21) & 0xf8); ++ reg = sm712_read_seq(fb, 0x15); ++ sm712_write_seq(fb, 0x15, reg | 0x30); ++ sm712_write_seq(fb, 0x15, reg); ++ ++ if (sm712fb_wait(fb) != 0) ++ return -1; ++ ++ sm712_write_dpr(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0)); ++ ++ /* same width for DPR_PITCH and DPR_SRC_WINDOW */ ++ sm712_write_dpr(fb, DPR_PITCH, ++ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); ++ sm712_write_dpr(fb, DPR_SRC_WINDOW, ++ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); ++ ++ sm712_write_dpr(fb, DPR_BYTE_BIT_MASK, 0xffffffff); ++ sm712_write_dpr(fb, DPR_COLOR_COMPARE_MASK, 0); ++ sm712_write_dpr(fb, DPR_COLOR_COMPARE, 0); ++ sm712_write_dpr(fb, DPR_SRC_BASE, 0); ++ sm712_write_dpr(fb, DPR_DST_BASE, 0); ++ sm712_read_dpr(fb, DPR_DST_BASE); ++ ++ return 0; ++} ++ ++int sm712fb_wait(struct sm712fb_info *fb) ++{ ++ int i; ++ u8 reg; ++ ++ for (i = 0; i < 10000; i++) { ++ reg = sm712_read_seq(fb, SCR_DE_STATUS); ++ if ((reg & SCR_DE_STATUS_MASK) == SCR_DE_ENGINE_IDLE) ++ return 0; ++ udelay(1); ++ } ++ return -EBUSY; ++} ++ ++void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ++{ ++ u32 width = rect->width, height = rect->height; ++ u32 dx = rect->dx, dy = rect->dy; ++ u32 color; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((rect->dx >= info->var.xres_virtual) || ++ (rect->dy >= info->var.yres_virtual)) ++ return; ++ ++ if (info->fix.visual == FB_VISUAL_TRUECOLOR || ++ info->fix.visual == FB_VISUAL_DIRECTCOLOR) ++ color = ((u32 *) (info->pseudo_palette))[rect->color]; ++ else ++ color = rect->color; ++ ++ sm712_write_dpr(sfb, DPR_FG_COLOR, color); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | ++ (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} ++ ++void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) ++{ ++ u32 sx = area->sx, sy = area->sy; ++ u32 dx = area->dx, dy = area->dy; ++ u32 height = area->height, width = area->width; ++ u32 direction; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((sx >= info->var.xres_virtual) || (sy >= info->var.yres_virtual)) ++ return; ++ ++ if (sy < dy || (sy == dy && sx <= dx)) { ++ sx += width - 1; ++ dx += width - 1; ++ sy += height - 1; ++ dy += height - 1; ++ direction = DE_CTRL_RTOL; ++ } else ++ direction = 0; ++ ++ sm712_write_dpr(sfb, DPR_SRC_COORDS, DPR_COORDS(sx, sy)); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_DE_CTRL, ++ DE_CTRL_START | DE_CTRL_ROP_ENABLE | direction | ++ (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} ++ ++void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image) ++{ ++ u32 dx = image->dx, dy = image->dy; ++ u32 width = image->width, height = image->height; ++ u32 fg_color, bg_color; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ u32 imgidx = 0; ++ u32 line = image->width >> 3; ++ ++ int i, j; ++ u32 total_bytes, total_dwords, remain_bytes; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((image->dx >= info->var.xres_virtual) || ++ (image->dy >= info->var.yres_virtual)) ++ return; ++ ++ if (unlikely(image->depth != 1)) { ++ /* unsupported depth, fallback to draw Tux */ ++ cfb_imageblit(info, image); ++ return; ++ } ++ ++ if (info->fix.visual == FB_VISUAL_TRUECOLOR || ++ info->fix.visual == FB_VISUAL_DIRECTCOLOR) { ++ fg_color = ((u32 *) (info->pseudo_palette))[image->fg_color]; ++ bg_color = ((u32 *) (info->pseudo_palette))[image->bg_color]; ++ } else { ++ fg_color = image->fg_color; ++ bg_color = image->bg_color; ++ } ++ ++ /* total bytes we need to write */ ++ total_bytes = (width + 7) / 8; ++ ++ /* split the bytes into dwords and remainder bytes */ ++ total_dwords = (total_bytes & ~3) / 4; ++ remain_bytes = total_bytes & 3; ++ ++ sm712_write_dpr(sfb, DPR_SRC_COORDS, 0); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_FG_COLOR, fg_color); ++ sm712_write_dpr(sfb, DPR_BG_COLOR, bg_color); ++ ++ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | ++ (DE_CTRL_COMMAND_HOST_WRITE << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_HOST_MONO << DE_CTRL_HOST_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ ++ for (i = 0; i < height; i++) { ++ /* cast bytes data into dwords and write to the dataport */ ++ for (j = 0; j < total_dwords; j++) { ++ sm712_write_dataport(sfb, ++ bytes_to_dword(&image-> ++ data[imgidx] + ++ j * 4, 4)); ++ } ++ ++ if (remain_bytes) { ++ sm712_write_dataport(sfb, ++ bytes_to_dword(&image-> ++ data[imgidx] + ++ (total_dwords * 4), ++ remain_bytes)); ++ } ++ imgidx += line; ++ } ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.h b/drivers/video/fbdev/sm712fb/sm712fb_accel.h +new file mode 100644 +index 0000000..6f79177 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.h +@@ -0,0 +1,33 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#ifndef _SM712FB_ACCEL_H ++#define _SM712FB_ACCEL_H ++ ++int sm712fb_init_accel(struct sm712fb_info *fb); ++int sm712fb_wait(struct sm712fb_info *fb); ++void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); ++void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area); ++void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image); ++ ++#endif +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.c b/drivers/video/fbdev/sm712fb/sm712fb_drv.c +new file mode 100644 +index 0000000..7f7cd4f +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.c +@@ -0,0 +1,1022 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PM ++#include ++#endif ++ ++#include "sm712fb_drv.h" ++#include "sm712fb_accel.h" ++#include "sm712fb_modedb.h" ++ ++static struct fb_var_screeninfo sm712fb_var = { ++ .xres = 1024, ++ .yres = 600, ++ .xres_virtual = 1024, ++ .yres_virtual = 600, ++ .bits_per_pixel = 16, ++ .red = {16, 8, 0}, ++ .green = {8, 8, 0}, ++ .blue = {0, 8, 0}, ++ .activate = FB_ACTIVATE_NOW, ++ .height = -1, ++ .width = -1, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .nonstd = 0, ++ .accel_flags = FB_ACCELF_TEXT, ++}; ++ ++static struct fb_fix_screeninfo sm712fb_fix = { ++ .id = "smXXXfb", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .line_length = 800 * 3, ++ .accel = FB_ACCEL_SMI_LYNX, ++ .type_aux = 0, ++ .xpanstep = 0, ++ .ypanstep = 0, ++ .ywrapstep = 0, ++}; ++ ++struct vesa_mode { ++ char index[6]; ++ u16 lfb_width; ++ u16 lfb_height; ++ u16 lfb_depth; ++}; ++ ++static bool accel = 1; ++ ++static struct vesa_mode vesa_mode_table[] = { ++ {"0x301", 640, 480, 8}, ++ {"0x303", 800, 600, 8}, ++ {"0x305", 1024, 768, 8}, ++ {"0x307", 1280, 1024, 8}, ++ ++ {"0x311", 640, 480, 16}, ++ {"0x314", 800, 600, 16}, ++ {"0x317", 1024, 768, 16}, ++ {"0x31A", 1280, 1024, 16}, ++ ++ {"0x312", 640, 480, 24}, ++ {"0x315", 800, 600, 24}, ++ {"0x318", 1024, 768, 24}, ++ {"0x31B", 1280, 1024, 24}, ++}; ++ ++struct screen_info sm712_scr_info; ++ ++static int sm712fb_setup(char *options) ++{ ++ char *this_opt; ++ ++ if (!options || !*options) ++ return 0; ++ ++ while ((this_opt = strsep(&options, ",")) != NULL) { ++ if (!*this_opt) ++ continue; ++ ++ if (!strcmp(this_opt, "accel:0")) ++ accel = false; ++ else if (!strcmp(this_opt, "accel:1")) ++ accel = true; ++ } ++ return 0; ++} ++ ++/* process command line options, get vga parameter */ ++static int __init sm712_vga_setup(char *options) ++{ ++ int i; ++ ++ if (!options || !*options) ++ return -EINVAL; ++ ++ sm712_scr_info.lfb_width = 0; ++ sm712_scr_info.lfb_height = 0; ++ sm712_scr_info.lfb_depth = 0; ++ ++ pr_debug("sm712_vga_setup = %s\n", options); ++ ++ for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { ++ if (strstr(options, vesa_mode_table[i].index)) { ++ sm712_scr_info.lfb_width = vesa_mode_table[i].lfb_width; ++ sm712_scr_info.lfb_height = ++ vesa_mode_table[i].lfb_height; ++ sm712_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; ++ return 0; ++ } ++ } ++ ++ return -1; ++} ++ ++__setup("vga=", sm712_vga_setup); ++ ++static void sm712_setpalette(int regno, unsigned red, unsigned green, ++ unsigned blue, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb = info->par; ++ ++ /* set bit 5:4 = 01 (write LCD RAM only) */ ++ sm712_write_seq(sfb, 0x66, (sm712_read_seq(sfb, 0x66) & 0xC3) | 0x10); ++ ++ sm712_writeb(sfb->mmio, DAC_REG, regno); ++ sm712_writeb(sfb->mmio, DAC_VAL, red >> 10); ++ sm712_writeb(sfb->mmio, DAC_VAL, green >> 10); ++ sm712_writeb(sfb->mmio, DAC_VAL, blue >> 10); ++} ++ ++/* chan_to_field ++ * ++ * convert a colour value into a field position ++ * ++ * from pxafb.c ++ */ ++ ++static inline unsigned int chan_to_field(unsigned int chan, ++ struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++static int sm712_blank(int blank_mode, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb = info->par; ++ ++ /* clear DPMS setting */ ++ switch (blank_mode) { ++ case FB_BLANK_UNBLANK: ++ /* Screen On: HSync: On, VSync : On */ ++ sm712_write_seq(sfb, 0x01, ++ (sm712_read_seq(sfb, 0x01) & (~0x20))); ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) & 0x77)); ++ sm712_write_seq(sfb, 0x22, ++ (sm712_read_seq(sfb, 0x22) & (~0x30))); ++ sm712_write_seq(sfb, 0x23, ++ (sm712_read_seq(sfb, 0x23) & (~0xc0))); ++ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); ++ sm712_write_seq(sfb, 0x31, (sm712_read_seq(sfb, 0x31) | 0x03)); ++ break; ++ case FB_BLANK_NORMAL: ++ /* Screen Off: HSync: On, VSync : On Soft blank */ ++ sm712_write_seq(sfb, 0x01, ++ (sm712_read_seq(sfb, 0x01) & (~0x20))); ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x22, ++ (sm712_read_seq(sfb, 0x22) & (~0x30))); ++ sm712_write_seq(sfb, 0x23, ++ (sm712_read_seq(sfb, 0x23) & (~0xc0))); ++ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ break; ++ case FB_BLANK_VSYNC_SUSPEND: ++ /* Screen On: HSync: On, VSync : Off */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x0c); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x20)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0x20)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ case FB_BLANK_HSYNC_SUSPEND: ++ /* Screen On: HSync: Off, VSync : On */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x0c); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x10)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ case FB_BLANK_POWERDOWN: ++ /* Screen On: HSync: Off, VSync : Off */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x5a); ++ sm712_write_seq(sfb, 0x6b, 0x20); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x30)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int sm712_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned trans, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb; ++ u32 val; ++ ++ sfb = info->par; ++ ++ if (regno > 255) ++ return 1; ++ ++ switch (sfb->fb.fix.visual) { ++ case FB_VISUAL_DIRECTCOLOR: ++ case FB_VISUAL_TRUECOLOR: ++ /* ++ * 16/32 bit true-colour, use pseudo-palette for 16 base color ++ */ ++ if (regno < 16) { ++ if (sfb->fb.var.bits_per_pixel == 16) { ++ u32 *pal = sfb->fb.pseudo_palette; ++ ++ val = chan_to_field(red, &sfb->fb.var.red); ++ val |= chan_to_field(green, &sfb->fb.var.green); ++ val |= chan_to_field(blue, &sfb->fb.var.blue); ++#ifdef __BIG_ENDIAN ++ pal[regno] = ++ ((red & 0xf800) >> 8) | ++ ((green & 0xe000) >> 13) | ++ ((green & 0x1c00) << 3) | ++ ((blue & 0xf800) >> 3); ++#else ++ pal[regno] = val; ++#endif ++ } else { ++ u32 *pal = sfb->fb.pseudo_palette; ++ ++ val = chan_to_field(red, &sfb->fb.var.red); ++ val |= chan_to_field(green, &sfb->fb.var.green); ++ val |= chan_to_field(blue, &sfb->fb.var.blue); ++#ifdef __BIG_ENDIAN ++ val = ++ (val & 0xff00ff00 >> 8) | ++ (val & 0x00ff00ff << 8); ++#endif ++ pal[regno] = val; ++ } ++ } ++ break; ++ ++ case FB_VISUAL_PSEUDOCOLOR: ++ /* color depth 8 bit */ ++ sm712_setpalette(regno, red, green, blue, info); ++ break; ++ ++ default: ++ return 1; /* unknown type */ ++ } ++ ++ return 0; ++ ++} ++ ++#ifdef __BIG_ENDIAN ++static ssize_t sm712fb_read(struct fb_info *info, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ ++ u32 *buffer, *dst; ++ u32 __iomem *src; ++ int c, i, cnt = 0, err = 0; ++ unsigned long total_size; ++ ++ if (!info || !info->screen_base) ++ return -ENODEV; ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return -EPERM; ++ ++ total_size = info->screen_size; ++ ++ if (total_size == 0) ++ total_size = info->fix.smem_len; ++ ++ if (p >= total_size) ++ return 0; ++ ++ if (count >= total_size) ++ count = total_size; ++ ++ if (count + p > total_size) ++ count = total_size - p; ++ ++ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ src = (u32 __iomem *) (info->screen_base + p); ++ ++ if (info->fbops->fb_sync) ++ info->fbops->fb_sync(info); ++ ++ while (count) { ++ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; ++ dst = buffer; ++ for (i = c >> 2; i--;) { ++ *dst = fb_readl(src++); ++ *dst = ++ (*dst & 0xff00ff00 >> 8) | (*dst & 0x00ff00ff << 8); ++ dst++; ++ } ++ if (c & 3) { ++ u8 *dst8 = (u8 *) dst; ++ u8 __iomem *src8 = (u8 __iomem *) src; ++ ++ for (i = c & 3; i--;) { ++ if (i & 1) { ++ *dst8++ = fb_readb(++src8); ++ } else { ++ *dst8++ = fb_readb(--src8); ++ src8 += 2; ++ } ++ } ++ src = (u32 __iomem *) src8; ++ } ++ ++ if (copy_to_user(buf, buffer, c)) { ++ err = -EFAULT; ++ break; ++ } ++ *ppos += c; ++ buf += c; ++ cnt += c; ++ count -= c; ++ } ++ ++ kfree(buffer); ++ ++ return (err) ? err : cnt; ++} ++ ++static ssize_t ++sm712fb_write(struct fb_info *info, const char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ ++ u32 *buffer, *src; ++ u32 __iomem *dst; ++ int c, i, cnt = 0, err = 0; ++ unsigned long total_size; ++ ++ if (!info || !info->screen_base) ++ return -ENODEV; ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return -EPERM; ++ ++ total_size = info->screen_size; ++ ++ if (total_size == 0) ++ total_size = info->fix.smem_len; ++ ++ if (p > total_size) ++ return -EFBIG; ++ ++ if (count > total_size) { ++ err = -EFBIG; ++ count = total_size; ++ } ++ ++ if (count + p > total_size) { ++ if (!err) ++ err = -ENOSPC; ++ ++ count = total_size - p; ++ } ++ ++ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ dst = (u32 __iomem *) (info->screen_base + p); ++ ++ if (info->fbops->fb_sync) ++ info->fbops->fb_sync(info); ++ ++ while (count) { ++ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; ++ src = buffer; ++ ++ if (copy_from_user(src, buf, c)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ for (i = c >> 2; i--;) { ++ fb_writel((*src & 0xff00ff00 >> 8) | ++ (*src & 0x00ff00ff << 8), dst++); ++ src++; ++ } ++ if (c & 3) { ++ u8 *src8 = (u8 *) src; ++ u8 __iomem *dst8 = (u8 __iomem *) dst; ++ ++ for (i = c & 3; i--;) { ++ if (i & 1) { ++ fb_writeb(*src8++, ++dst8); ++ } else { ++ fb_writeb(*src8++, --dst8); ++ dst8 += 2; ++ } ++ } ++ dst = (u32 __iomem *) dst8; ++ } ++ ++ *ppos += c; ++ buf += c; ++ cnt += c; ++ count -= c; ++ } ++ ++ kfree(buffer); ++ ++ return (cnt) ? cnt : err; ++} ++#endif /* ! __BIG_ENDIAN */ ++ ++static void sm712_set_timing(struct sm712fb_info *sfb) ++{ ++ int i = 0, j = 0; ++ u32 m_nScreenStride; ++ ++ dev_dbg(&sfb->pdev->dev, ++ "sfb->width=%d sfb->height=%d " ++ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n", ++ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz); ++ ++ for (j = 0; j < numVGAModes; j++) { ++ if (VGAMode[j].mmSizeX != sfb->width || ++ VGAMode[j].mmSizeY != sfb->height || ++ VGAMode[j].bpp != sfb->fb.var.bits_per_pixel || ++ VGAMode[j].hz != sfb->hz) { ++ continue; ++ } ++ ++ dev_dbg(&sfb->pdev->dev, ++ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d " ++ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n", ++ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, ++ VGAMode[j].bpp, VGAMode[j].hz); ++ ++ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j); ++ ++ sm712_writeb(sfb->mmio, 0x3c6, 0x0); ++ ++ sm712_write_seq(sfb, 0, 0x1); ++ ++ sm712_writeb(sfb->mmio, 0x3c2, VGAMode[j].Init_MISC); ++ ++ /* init SEQ register SR00 - SR04 */ ++ for (i = 0; i < SR00_SR04_SIZE; i++) ++ sm712_write_seq(sfb, i, VGAMode[j].Init_SR00_SR04[i]); ++ ++ /* init SEQ register SR10 - SR24 */ ++ for (i = 0; i < SR10_SR24_SIZE; i++) ++ sm712_write_seq(sfb, i + 0x10, ++ VGAMode[j].Init_SR10_SR24[i]); ++ ++ /* init SEQ register SR30 - SR75 */ ++ for (i = 0; i < SR30_SR75_SIZE; i++) ++ if ((i + 0x30) != 0x62 && ++ (i + 0x30) != 0x6a && (i + 0x30) != 0x6b) ++ sm712_write_seq(sfb, i + 0x30, ++ VGAMode[j].Init_SR30_SR75[i]); ++ ++ /* init SEQ register SR80 - SR93 */ ++ for (i = 0; i < SR80_SR93_SIZE; i++) ++ sm712_write_seq(sfb, i + 0x80, ++ VGAMode[j].Init_SR80_SR93[i]); ++ ++ /* init SEQ register SRA0 - SRAF */ ++ for (i = 0; i < SRA0_SRAF_SIZE; i++) ++ sm712_write_seq(sfb, i + 0xa0, ++ VGAMode[j].Init_SRA0_SRAF[i]); ++ ++ /* init Graphic register GR00 - GR08 */ ++ for (i = 0; i < GR00_GR08_SIZE; i++) ++ sm712_write_grph(sfb, i, VGAMode[j].Init_GR00_GR08[i]); ++ ++ /* init Attribute register AR00 - AR14 */ ++ for (i = 0; i < AR00_AR14_SIZE; i++) ++ sm712_write_attr(sfb, i, VGAMode[j].Init_AR00_AR14[i]); ++ ++ /* init CRTC register CR00 - CR18 */ ++ for (i = 0; i < CR00_CR18_SIZE; i++) ++ sm712_write_crtc(sfb, i, VGAMode[j].Init_CR00_CR18[i]); ++ ++ /* init CRTC register CR30 - CR4D */ ++ for (i = 0; i < CR30_CR4D_SIZE; i++) ++ sm712_write_crtc(sfb, i + 0x30, ++ VGAMode[j].Init_CR30_CR4D[i]); ++ ++ /* init CRTC register CR90 - CRA7 */ ++ for (i = 0; i < CR90_CRA7_SIZE; i++) ++ sm712_write_crtc(sfb, i + 0x90, ++ VGAMode[j].Init_CR90_CRA7[i]); ++ } ++ sm712_writeb(sfb->mmio, 0x3c2, 0x67); ++ ++ /* set VPR registers */ ++ sm712_writel(sfb->vpr, 0x0C, 0x0); ++ sm712_writel(sfb->vpr, 0x40, 0x0); ++ ++ /* set data width */ ++ m_nScreenStride = (sfb->width * sfb->fb.var.bits_per_pixel) / 64; ++ switch (sfb->fb.var.bits_per_pixel) { ++ case 8: ++ sm712_writel(sfb->vpr, 0x0, 0x0); ++ break; ++ case 16: ++ sm712_writel(sfb->vpr, 0x0, 0x00020000); ++ break; ++ case 24: ++ sm712_writel(sfb->vpr, 0x0, 0x00040000); ++ break; ++ case 32: ++ sm712_writel(sfb->vpr, 0x0, 0x00030000); ++ break; ++ } ++ sm712_writel(sfb->vpr, 0x10, ++ (u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride)); ++} ++ ++static void sm712fb_setmode(struct sm712fb_info *sfb) ++{ ++ switch (sfb->fb.var.bits_per_pixel) { ++ case 32: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 4; ++ sfb->fb.var.red.length = 8; ++ sfb->fb.var.green.length = 8; ++ sfb->fb.var.blue.length = 8; ++ sfb->fb.var.red.offset = 16; ++ sfb->fb.var.green.offset = 8; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 24: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 3; ++ sfb->fb.var.red.length = 8; ++ sfb->fb.var.green.length = 8; ++ sfb->fb.var.blue.length = 8; ++ sfb->fb.var.red.offset = 16; ++ sfb->fb.var.green.offset = 8; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 8: ++ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres; ++ sfb->fb.var.red.length = 3; ++ sfb->fb.var.green.length = 3; ++ sfb->fb.var.blue.length = 2; ++ sfb->fb.var.red.offset = 5; ++ sfb->fb.var.green.offset = 2; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 16: ++ default: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 2; ++ sfb->fb.var.red.length = 5; ++ sfb->fb.var.green.length = 6; ++ sfb->fb.var.blue.length = 5; ++ sfb->fb.var.red.offset = 11; ++ sfb->fb.var.green.offset = 5; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ } ++ ++ sfb->width = sfb->fb.var.xres; ++ sfb->height = sfb->fb.var.yres; ++ sfb->hz = 60; ++ sm712_set_timing(sfb); ++} ++ ++static int sm712_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ /* sanity checks */ ++ if (var->xres_virtual < var->xres) ++ var->xres_virtual = var->xres; ++ ++ if (var->yres_virtual < var->yres) ++ var->yres_virtual = var->yres; ++ ++ /* set valid default bpp */ ++ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && ++ (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) ++ var->bits_per_pixel = 16; ++ ++ return 0; ++} ++ ++static int sm712_set_par(struct fb_info *info) ++{ ++ sm712fb_setmode(info->par); ++ ++ return 0; ++} ++ ++static struct fb_ops sm712fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = sm712_check_var, ++ .fb_set_par = sm712_set_par, ++ .fb_setcolreg = sm712_setcolreg, ++ .fb_blank = sm712_blank, ++ .fb_fillrect = cfb_fillrect, ++ .fb_imageblit = cfb_imageblit, ++ .fb_copyarea = cfb_copyarea, ++#ifdef __BIG_ENDIAN ++ .fb_read = sm712fb_read, ++ .fb_write = sm712fb_write, ++#endif ++}; ++ ++/* ++ * alloc struct sm712fb_info and assign default values ++ */ ++static struct sm712fb_info *sm712_fb_info_new(struct pci_dev *pdev) ++{ ++ struct sm712fb_info *sfb; ++ ++ sfb = kzalloc(sizeof(*sfb), GFP_KERNEL); ++ ++ if (!sfb) ++ return NULL; ++ ++ sfb->pdev = pdev; ++ ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT; ++ sfb->fb.fbops = &sm712fb_ops; ++ sfb->fb.fix = sm712fb_fix; ++ sfb->fb.var = sm712fb_var; ++ sfb->fb.pseudo_palette = sfb->colreg; ++ sfb->fb.par = sfb; ++ sfb->accel = accel; ++ ++ return sfb; ++} ++ ++/* ++ * free struct sm712fb_info ++ */ ++static void sm712_fb_info_free(struct sm712fb_info *sfb) ++{ ++ kfree(sfb); ++} ++ ++/* ++ * Map in the screen memory ++ */ ++ ++static int sm712_map_smem(struct sm712fb_info *sfb, ++ struct pci_dev *pdev, u_long smem_len) ++{ ++ ++ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); ++ ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 32) ++ sfb->fb.fix.smem_start += 0x800000; ++#endif ++ ++ sfb->fb.fix.smem_len = smem_len; ++ ++ sfb->fb.screen_base = sfb->lfb; ++ ++ if (!sfb->fb.screen_base) { ++ dev_err(&pdev->dev, ++ "%s: unable to map screen memory\n", sfb->fb.fix.id); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Unmap in the screen memory ++ * ++ */ ++static void sm712_unmap_smem(struct sm712fb_info *sfb) ++{ ++ if (sfb && sfb->fb.screen_base) { ++ iounmap(sfb->fb.screen_base); ++ sfb->fb.screen_base = NULL; ++ sfb->lfb = NULL; ++ } ++} ++ ++static inline void sm712_init_hw(struct sm712fb_info *sfb) ++{ ++ /* enable linear memory mode and packed pixel format */ ++ outb_p(0x18, 0x3c4); ++ outb_p(0x11, 0x3c5); ++ ++ /* set MCLK = 14.31818 * (0x16 / 0x2) */ ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x62, 0x3e); ++ ++ /* enable PCI burst */ ++ sm712_write_seq(sfb, 0x17, 0x20); ++ ++#ifdef __BIG_ENDIAN ++ /* enable word swap */ ++ if (sfb->fb.var.bits_per_pixel == 32) ++ sm712_write_seq(sfb, 0x17, 0x30); ++#endif ++ ++ if (!sfb->accel) { ++ dev_info(&sfb->pdev->dev, "2d acceleration was disabled by user.\n"); ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; ++ return; ++ } ++ ++ if (sm712fb_init_accel(sfb) < 0) { ++ dev_info(&sfb->pdev->dev, "failed to enable 2d accleration.\n"); ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; ++ return; ++ } else { ++ sm712fb_ops.fb_fillrect = sm712fb_fillrect; ++ sm712fb_ops.fb_copyarea = sm712fb_copyarea; ++ sm712fb_ops.fb_imageblit = sm712fb_imageblit; ++ sfb->fb.flags |= FBINFO_HWACCEL_COPYAREA | ++ FBINFO_HWACCEL_FILLRECT | ++ FBINFO_HWACCEL_IMAGEBLIT | ++ FBINFO_READS_FAST; ++ dev_info(&sfb->pdev->dev, "sm712fb: enable 2d acceleration.\n"); ++ } ++} ++ ++static int sm712fb_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct sm712fb_info *sfb; ++ int err; ++ unsigned long mmio_base; ++ ++#ifndef MODULE ++ char *option = NULL; ++ ++ if (!fb_get_options("sm712fb", &option)) ++ sm712fb_setup(option); ++#endif ++ ++ dev_info(&pdev->dev, "Silicon Motion display driver."); ++ ++ err = pci_enable_device(pdev); /* enable SMTC chip */ ++ if (err) ++ return err; ++ ++ sprintf(sm712fb_fix.id, "sm712fb"); ++ ++ sfb = sm712_fb_info_new(pdev); ++ ++ if (!sfb) { ++ err = -ENOMEM; ++ goto free_fail; ++ } ++ ++ sfb->chip_id = ent->device; ++ ++ pci_set_drvdata(pdev, sfb); ++ ++ /* get mode parameter from sm712_scr_info */ ++ if (sm712_scr_info.lfb_width != 0) { ++ sfb->fb.var.xres = sm712_scr_info.lfb_width; ++ sfb->fb.var.yres = sm712_scr_info.lfb_height; ++ sfb->fb.var.bits_per_pixel = sm712_scr_info.lfb_depth; ++ } else { ++ /* default resolution 1024x600 16bit mode */ ++ sfb->fb.var.xres = SM712_DEFAULT_XRES; ++ sfb->fb.var.yres = SM712_DEFAULT_YRES; ++ sfb->fb.var.bits_per_pixel = SM712_DEFAULT_BPP; ++ } ++ ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 24) ++ sfb->fb.var.bits_per_pixel = (sm712_scr_info.lfb_depth = 32); ++#endif ++ ++ /* Map address and memory detection */ ++ mmio_base = pci_resource_start(pdev, 0); ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); ++ ++ if (sfb->chip_id != 0x712) { ++ dev_err(&pdev->dev, ++ "No valid Silicon Motion display chip was detected!"); ++ ++ goto fb_fail; ++ } ++ ++ sfb->fb.fix.mmio_start = mmio_base + SM712_REG_BASE; ++ sfb->fb.fix.mmio_len = SM712_REG_SIZE; ++#ifdef __BIG_ENDIAN ++ sfb->lfb = ioremap(mmio_base, 0x00c00000); ++#else ++ sfb->lfb = ioremap(mmio_base, 0x00800000); ++#endif ++ sfb->mmio = sfb->lfb + SM712_MMIO_BASE; ++ sfb->dpr = sfb->lfb + SM712_DPR_BASE; ++ sfb->vpr = sfb->lfb + SM712_VPR_BASE; ++ sfb->dataport = sfb->lfb + SM712_DATAPORT_BASE; ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 32) { ++ sfb->lfb += 0x800000; ++ dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb); ++ } ++#endif ++ if (!sfb->mmio) { ++ dev_err(&pdev->dev, ++ "%s: unable to map memory mapped IO!", sfb->fb.fix.id); ++ err = -ENOMEM; ++ goto fb_fail; ++ } ++ ++ sm712_init_hw(sfb); ++ ++ /* can support 32 bpp */ ++ if (15 == sfb->fb.var.bits_per_pixel) ++ sfb->fb.var.bits_per_pixel = 16; ++ ++ sfb->fb.var.xres_virtual = sfb->fb.var.xres; ++ sfb->fb.var.yres_virtual = sfb->fb.var.yres; ++ err = sm712_map_smem(sfb, pdev, SM712_VRAM_SIZE); ++ if (err) ++ goto fail; ++ ++ sm712fb_setmode(sfb); ++ ++ err = register_framebuffer(&sfb->fb); ++ if (err < 0) ++ goto fail; ++ ++ dev_info(&pdev->dev, ++ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.", ++ sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres, ++ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); ++ ++ return 0; ++ ++fail: ++ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail."); ++ ++ sm712_unmap_smem(sfb); ++fb_fail: ++ sm712_fb_info_free(sfb); ++free_fail: ++ pci_disable_device(pdev); ++ ++ return err; ++} ++ ++/* ++ * 0x712 (LynxEM+) ++ */ ++static const struct pci_device_id sm712fb_pci_table[] = { ++ {PCI_DEVICE(0x126f, 0x712),}, ++ {0,} ++}; ++ ++static void sm712fb_pci_remove(struct pci_dev *pdev) ++{ ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ sm712_unmap_smem(sfb); ++ unregister_framebuffer(&sfb->fb); ++ sm712_fb_info_free(sfb); ++} ++ ++#ifdef CONFIG_PM ++static int sm712fb_pci_suspend(struct device *device) ++{ ++ struct pci_dev *pdev = to_pci_dev(device); ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ ++ /* set the hw in sleep mode use external clock and self memory refresh ++ * so that we can turn off internal PLLs later on ++ */ ++ sm712_write_seq(sfb, 0x20, (sm712_read_seq(sfb, 0x20) | 0xc0)); ++ sm712_write_seq(sfb, 0x69, (sm712_read_seq(sfb, 0x69) & 0xf7)); ++ ++ console_lock(); ++ fb_set_suspend(&sfb->fb, 1); ++ console_unlock(); ++ ++ /* additionally turn off all function blocks including internal PLLs */ ++ sm712_write_seq(sfb, 0x21, 0xff); ++ ++ return 0; ++} ++ ++static int sm712fb_pci_resume(struct device *device) ++{ ++ struct pci_dev *pdev = to_pci_dev(device); ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ ++ /* reinit hardware */ ++ sm712_init_hw(sfb); ++ ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0xc0)); ++ sm712_write_seq(sfb, 0x33, ((sm712_read_seq(sfb, 0x33) | 0x08) & 0xfb)); ++ ++ sm712fb_setmode(sfb); ++ ++ console_lock(); ++ fb_set_suspend(&sfb->fb, 0); ++ console_unlock(); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(sm712_pm_ops, sm712fb_pci_suspend, sm712fb_pci_resume); ++#define SM712_PM_OPS (&sm712_pm_ops) ++ ++#else /* !CONFIG_PM */ ++ ++#define SM712_PM_OPS NULL ++ ++#endif /* !CONFIG_PM */ ++ ++static struct pci_driver sm712fb_driver = { ++ .name = "sm712fb", ++ .id_table = sm712fb_pci_table, ++ .probe = sm712fb_pci_probe, ++ .remove = sm712fb_pci_remove, ++ .driver.pm = SM712_PM_OPS, ++}; ++ ++module_pci_driver(sm712fb_driver); ++ ++module_param(accel, bool, S_IRUGO); ++MODULE_PARM_DESC(accel, "Enable or disable 2D Acceleration"); ++ ++MODULE_AUTHOR("Siliconmotion "); ++MODULE_DESCRIPTION("Framebuffer driver for Silicon Motion SM712 Graphic Cards"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.h b/drivers/video/fbdev/sm712fb/sm712fb_drv.h +new file mode 100644 +index 0000000..bf81bff +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.h +@@ -0,0 +1,130 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#ifndef _SM712FB_DRV_H ++#define _SM712FB_DRV_H ++ ++/* ++* Private structure ++*/ ++struct sm712fb_info { ++ struct pci_dev *pdev; ++ struct fb_info fb; ++ u16 chip_id; ++ u8 chip_rev_id; ++ ++ void __iomem *lfb; /* linear frame buffer, the base address */ ++ ++ void __iomem *dpr; /* drawing processor control regs */ ++ void __iomem *vpr; /* video processor control regs */ ++ void __iomem *cpr; /* capture processor control regs */ ++ void __iomem *mmio; /* memory map IO port */ ++ void __iomem *dataport; /* 2d drawing engine data port */ ++ ++ u_int width; ++ u_int height; ++ u_int hz; ++ ++ u32 colreg[17]; ++ ++ bool accel; ++}; ++ ++/* constants for registers operations */ ++ ++#include "sm712fb_io.h" ++ ++#define FB_ACCEL_SMI_LYNX 88 ++ ++#define SM712_DEFAULT_XRES 1024 ++#define SM712_DEFAULT_YRES 600 ++#define SM712_DEFAULT_BPP 16 ++ ++#define SM712_VRAM_SIZE 0x00400000 ++ ++#define SM712_REG_BASE 0x00400000 ++#define SM712_REG_SIZE 0x00400000 ++ ++#define SM712_MMIO_BASE 0x00700000 ++ ++#define SM712_DPR_BASE 0x00408000 ++#define SM712_DPR_SIZE (0x6C + 1) ++ ++#define DPR_COORDS(x, y) (((x) << 16) | (y)) ++ ++#define DPR_SRC_COORDS 0x00 ++#define DPR_DST_COORDS 0x04 ++#define DPR_SPAN_COORDS 0x08 ++#define DPR_DE_CTRL 0x0c ++#define DPR_PITCH 0x10 ++#define DPR_FG_COLOR 0x14 ++#define DPR_BG_COLOR 0x18 ++#define DPR_STRETCH 0x1c ++#define DPR_COLOR_COMPARE 0x20 ++#define DPR_COLOR_COMPARE_MASK 0x24 ++#define DPR_BYTE_BIT_MASK 0x28 ++#define DPR_CROP_TOPLEFT_COORDS 0x2c ++#define DPR_CROP_BOTRIGHT_COORDS 0x30 ++#define DPR_SRC_WINDOW 0x3c ++#define DPR_SRC_BASE 0x40 ++#define DPR_DST_BASE 0x44 ++ ++#define DE_CTRL_START 0x80000000 ++#define DE_CTRL_RTOL 0x08000000 ++#define DE_CTRL_COMMAND_MASK 0x001f0000 ++#define DE_CTRL_COMMAND_SHIFT 16 ++#define DE_CTRL_COMMAND_BITBLT 0x00 ++#define DE_CTRL_COMMAND_SOLIDFILL 0x01 ++#define DE_CTRL_COMMAND_HOST_WRITE 0x08 ++#define DE_CTRL_ROP_ENABLE 0x00008000 ++#define DE_CTRL_ROP_MASK 0x000000ff ++#define DE_CTRL_ROP_SHIFT 0 ++#define DE_CTRL_ROP_SRC 0x0c ++ ++#define DE_CTRL_HOST_SHIFT 22 ++#define DE_CTRL_HOST_MONO 1 ++ ++#define SCR_DE_STATUS 0x16 ++#define SCR_DE_STATUS_MASK 0x18 ++#define SCR_DE_ENGINE_IDLE 0x10 ++ ++#define SM712_VPR_BASE 0x0040c000 ++#define SM712_VPR_SIZE (0x44 + 1) ++ ++#define SM712_DATAPORT_BASE 0x00400000 ++ ++#define SR00_SR04_SIZE (0x04 - 0x00 + 1) ++#define SR10_SR24_SIZE (0x24 - 0x10 + 1) ++#define SR30_SR75_SIZE (0x75 - 0x30 + 1) ++#define SR80_SR93_SIZE (0x93 - 0x80 + 1) ++#define SRA0_SRAF_SIZE (0xAF - 0xA0 + 1) ++#define GR00_GR08_SIZE (0x08 - 0x00 + 1) ++#define AR00_AR14_SIZE (0x14 - 0x00 + 1) ++#define CR00_CR18_SIZE (0x18 - 0x00 + 1) ++#define CR30_CR4D_SIZE (0x4D - 0x30 + 1) ++#define CR90_CRA7_SIZE (0xA7 - 0x90 + 1) ++ ++#define DAC_REG (0x3c8) ++#define DAC_VAL (0x3c9) ++ ++#endif +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_io.h b/drivers/video/fbdev/sm712fb/sm712fb_io.h +new file mode 100644 +index 0000000..93346a0 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_io.h +@@ -0,0 +1,90 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ */ ++ ++ ++#define sm712_writeb(base, reg, dat) writeb(dat, base + reg) ++#define sm712_writew(base, reg, dat) writew(dat, base + reg) ++#define sm712_writel(base, reg, dat) writel(dat, base + reg) ++ ++#define sm712_readb(base, reg) readb(base + reg) ++#define sm712_readw(base, reg) readw(base + reg) ++#define sm712_readl(base, reg) readl(base + reg) ++ ++ ++static inline void sm712_write_crtc(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3d4, reg); ++ sm712_writeb(fb->mmio, 0x3d5, val); ++} ++ ++static inline u8 sm712_read_crtc(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3d4, reg); ++ return sm712_readb(fb->mmio, 0x3d5); ++} ++ ++static inline void sm712_write_grph(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3ce, reg); ++ sm712_writeb(fb->mmio, 0x3cf, val); ++} ++ ++static inline u8 sm712_read_grph(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3ce, reg); ++ return sm712_readb(fb->mmio, 0x3cf); ++} ++ ++static inline void sm712_write_attr(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_readb(fb->mmio, 0x3da); ++ sm712_writeb(fb->mmio, 0x3c0, reg); ++ sm712_readb(fb->mmio, 0x3c1); ++ sm712_writeb(fb->mmio, 0x3c0, val); ++} ++ ++static inline void sm712_write_seq(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3c4, reg); ++ sm712_writeb(fb->mmio, 0x3c5, val); ++} ++ ++static inline u8 sm712_read_seq(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3c4, reg); ++ return sm712_readb(fb->mmio, 0x3c5); ++} ++ ++static inline u32 sm712_read_dpr(struct sm712fb_info *fb, u8 reg) ++{ ++ return sm712_readl(fb->dpr, reg); ++} ++ ++static inline void sm712_write_dpr(struct sm712fb_info *fb, u8 reg, u32 val) ++{ ++ sm712_writel(fb->dpr, reg, val); ++} ++ ++static inline void sm712_write_dataport(struct sm712fb_info *fb, u32 val) ++{ ++ sm712_writel(fb->dataport, 0, val); ++} +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_modedb.h b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h +new file mode 100644 +index 0000000..16ee7e3 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h +@@ -0,0 +1,682 @@ ++/* The next structure holds all information relevant for a specific video mode. ++ */ ++ ++struct ModeInit { ++ int mmSizeX; ++ int mmSizeY; ++ int bpp; ++ int hz; ++ unsigned char Init_MISC; ++ unsigned char Init_SR00_SR04[SR00_SR04_SIZE]; ++ unsigned char Init_SR10_SR24[SR10_SR24_SIZE]; ++ unsigned char Init_SR30_SR75[SR30_SR75_SIZE]; ++ unsigned char Init_SR80_SR93[SR80_SR93_SIZE]; ++ unsigned char Init_SRA0_SRAF[SRA0_SRAF_SIZE]; ++ unsigned char Init_GR00_GR08[GR00_GR08_SIZE]; ++ unsigned char Init_AR00_AR14[AR00_AR14_SIZE]; ++ unsigned char Init_CR00_CR18[CR00_CR18_SIZE]; ++ unsigned char Init_CR30_CR4D[CR30_CR4D_SIZE]; ++ unsigned char Init_CR90_CRA7[CR90_CRA7_SIZE]; ++}; ++ ++/********************************************************************** ++ SM712 Mode table. ++ **********************************************************************/ ++struct ModeInit VGAMode[] = { ++ { ++ /* mode#0: 640 x 480 16Bpp 60Hz */ ++ 640, 480, 16, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ { ++ /* mode#1: 640 x 480 24Bpp 60Hz */ ++ 640, 480, 24, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ { ++ /* mode#0: 640 x 480 32Bpp 60Hz */ ++ 640, 480, 32, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ ++ { /* mode#2: 800 x 600 16Bpp 60Hz */ ++ 800, 600, 16, 60, ++ /* Init_MISC */ ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, ++ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, ++ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ { /* mode#3: 800 x 600 24Bpp 60Hz */ ++ 800, 600, 24, 60, ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ { /* mode#7: 800 x 600 32Bpp 60Hz */ ++ 800, 600, 32, 60, ++ /* Init_MISC */ ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, ++ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, ++ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ /* We use 1024x768 table to light 1024x600 panel for lemote */ ++ { /* mode#4: 1024 x 600 16Bpp 60Hz */ ++ 1024, 600, 16, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, ++ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x00, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, ++ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, ++ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, ++ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#5: 1024 x 768 24Bpp 60Hz */ ++ 1024, 768, 24, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, ++ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#4: 1024 x 768 32Bpp 60Hz */ ++ 1024, 768, 32, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, ++ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#6: 320 x 240 16Bpp 60Hz */ ++ 320, 240, 16, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, ++ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ ++ { /* mode#8: 320 x 240 32Bpp 60Hz */ ++ 320, 240, 32, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, ++ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++}; ++ ++#define numVGAModes ARRAY_SIZE(VGAMode) +diff --git a/drivers/video/output.c b/drivers/video/output.c +new file mode 100644 +index 0000000..1446c49 +--- /dev/null ++++ b/drivers/video/output.c +@@ -0,0 +1,133 @@ ++/* ++ * output.c - Display Output Switch driver ++ * ++ * Copyright (C) 2006 Luming Yu ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++ ++MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Luming Yu "); ++ ++static ssize_t state_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ ssize_t ret_size = 0; ++ struct output_device *od = to_output_device(dev); ++ if (od->props) ++ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); ++ return ret_size; ++} ++ ++static ssize_t state_store(struct device *dev, struct device_attribute *attr, ++ const char *buf,size_t count) ++{ ++ char *endp; ++ struct output_device *od = to_output_device(dev); ++ int request_state = simple_strtoul(buf,&endp,0); ++ size_t size = endp - buf; ++ ++ if (isspace(*endp)) ++ size++; ++ if (size != count) ++ return -EINVAL; ++ ++ if (od->props) { ++ od->request_state = request_state; ++ od->props->set_state(od); ++ } ++ return count; ++} ++static DEVICE_ATTR_RW(state); ++ ++static void video_output_release(struct device *dev) ++{ ++ struct output_device *od = to_output_device(dev); ++ kfree(od); ++} ++ ++static struct attribute *video_output_attrs[] = { ++ &dev_attr_state.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(video_output); ++ ++static struct class video_output_class = { ++ .name = "video_output", ++ .dev_release = video_output_release, ++ .dev_groups = video_output_groups, ++}; ++ ++struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op) ++{ ++ struct output_device *new_dev; ++ int ret_code = 0; ++ ++ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); ++ if (!new_dev) { ++ ret_code = -ENOMEM; ++ goto error_return; ++ } ++ new_dev->props = op; ++ new_dev->dev.class = &video_output_class; ++ new_dev->dev.parent = dev; ++ dev_set_name(&new_dev->dev, "%s", name); ++ dev_set_drvdata(&new_dev->dev, devdata); ++ ret_code = device_register(&new_dev->dev); ++ if (ret_code) { ++ kfree(new_dev); ++ goto error_return; ++ } ++ return new_dev; ++ ++error_return: ++ return ERR_PTR(ret_code); ++} ++EXPORT_SYMBOL(video_output_register); ++ ++void video_output_unregister(struct output_device *dev) ++{ ++ if (!dev) ++ return; ++ device_unregister(&dev->dev); ++} ++EXPORT_SYMBOL(video_output_unregister); ++ ++static void __exit video_output_class_exit(void) ++{ ++ class_unregister(&video_output_class); ++} ++ ++static int __init video_output_class_init(void) ++{ ++ return class_register(&video_output_class); ++} ++ ++postcore_initcall(video_output_class_init); ++module_exit(video_output_class_exit); +diff --git a/include/linux/sm501.h b/include/linux/sm501.h +index 02fde50..a8677f0 100644 +--- a/include/linux/sm501.h ++++ b/include/linux/sm501.h +@@ -27,6 +27,9 @@ extern unsigned long sm501_set_clock(struct device *dev, + extern unsigned long sm501_find_clock(struct device *dev, + int clksrc, unsigned long req_freq); + ++extern void sm501_configure_gpio(struct device *dev, ++ unsigned int gpio, unsigned char mode); ++ + /* sm501_misc_control + * + * Modify the SM501's MISC_CONTROL register +@@ -122,6 +125,7 @@ struct sm501_reg_init { + #define SM501_USE_AC97 (1<<7) + #define SM501_USE_I2S (1<<8) + #define SM501_USE_GPIO (1<<9) ++#define SM501_USE_PWM (1<<10) + + #define SM501_USE_ALL (0xffffffff) + +diff --git a/include/linux/video_output.h b/include/linux/video_output.h +new file mode 100644 +index 0000000..ed5cdeb +--- /dev/null ++++ b/include/linux/video_output.h +@@ -0,0 +1,57 @@ ++/* ++ * ++ * Copyright (C) 2006 Luming Yu ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++#ifndef _LINUX_VIDEO_OUTPUT_H ++#define _LINUX_VIDEO_OUTPUT_H ++#include ++#include ++struct output_device; ++struct output_properties { ++ int (*set_state)(struct output_device *); ++ int (*get_status)(struct output_device *); ++}; ++struct output_device { ++ int request_state; ++ struct output_properties *props; ++ struct device dev; ++}; ++#define to_output_device(obj) container_of(obj, struct output_device, dev) ++#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE) ++struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op); ++void video_output_unregister(struct output_device *dev); ++#else ++static struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op) ++{ ++ return ERR_PTR(-ENODEV); ++} ++static void video_output_unregister(struct output_device *dev) ++{ ++ return; ++} ++#endif ++#endif +diff --git a/init/calibrate.c b/init/calibrate.c +index ce635dc..10e775d 100644 +--- a/init/calibrate.c ++++ b/init/calibrate.c +@@ -21,6 +21,7 @@ static int __init lpj_setup(char *str) + + __setup("lpj=", lpj_setup); + ++#ifndef ARCH_HAS_PREPARED_LPJ + #ifdef ARCH_HAS_READ_CURRENT_TIMER + + /* This routine uses the read_current_timer() routine and gets the +@@ -171,6 +172,7 @@ static unsigned long calibrate_delay_direct(void) + return 0; + } + #endif ++#endif /* ARCH_HAS_PREPARED_LPJ */ + + /* + * This is the number of bits of precision for the loops_per_jiffy. Each +@@ -291,6 +293,7 @@ void calibrate_delay(void) + lpj = lpj_fine; + pr_info("Calibrating delay loop (skipped), " + "value calculated using timer frequency.. "); ++#ifndef ARCH_HAS_PREPARED_LPJ + } else if ((lpj = calibrate_delay_is_known())) { + ; + } else if ((lpj = calibrate_delay_direct()) != 0) { +@@ -301,6 +304,7 @@ void calibrate_delay(void) + if (!printed) + pr_info("Calibrating delay loop... "); + lpj = calibrate_delay_converge(); ++#endif /* ARCH_HAS_PREPARED_LPJ */ + } + per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj; + if (!printed) +diff --git a/net/rfkill/core.c b/net/rfkill/core.c +index fa7cd79..616abb5 100644 +--- a/net/rfkill/core.c ++++ b/net/rfkill/core.c +@@ -111,7 +111,7 @@ static LIST_HEAD(rfkill_list); /* list of registered rf switches */ + static DEFINE_MUTEX(rfkill_global_mutex); + static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ + +-static unsigned int rfkill_default_state = 1; ++static unsigned int rfkill_default_state; /* default: 0 = radio off */ + module_param_named(default_state, rfkill_default_state, uint, 0444); + MODULE_PARM_DESC(default_state, + "Default initial state for all radio types, 0 = radio off"); +diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl +index 826470d..9e6dc30 100755 +--- a/scripts/recordmcount.pl ++++ b/scripts/recordmcount.pl +@@ -309,14 +309,33 @@ if ($arch eq "x86_64") { + $cc .= " -m64"; + $objcopy .= " -O elf64-sparc"; + } elsif ($arch eq "mips") { +- # To enable module support, we need to enable the -mlong-calls option +- # of gcc for module, after using this option, we can not get the real +- # offset of the calling to _mcount, but the offset of the lui +- # instruction or the addiu one. herein, we record the address of the +- # first one, and then we can replace this instruction by a branch +- # instruction to jump over the profiling function to filter the +- # indicated functions, or swith back to the lui instruction to trace +- # them, which means dynamic tracing. ++ # ++ # To disable tracing, just replace "jal _mcount" with nop; ++ # to enable tracing, replace back. so, the offset 14 is ++ # needed to be recorded. ++ # ++ # 10: 03e0082d move at,ra ++ # 14: 0c000000 jal 0 ++ # 14: R_MIPS_26 _mcount ++ # 14: R_MIPS_NONE *ABS* ++ # 14: R_MIPS_NONE *ABS* ++ # 18: 00020021 nop ++ # ++ # ++ # ++ # If no long call(-mlong-calls), the same to kernel. ++ # ++ # If the module space differs from the kernel space, long ++ # call is needed, as a result, the address of _mcount is ++ # needed to be recorded in a register and then jump from ++ # module space to kernel space via "jalr ". To ++ # disable tracing, "jalr " can be replaced by ++ # nop; to enable tracing, replace it back. Since the ++ # offset of "jalr " is not easy to be matched, ++ # the offset of the 1st _mcount below is recorded and to ++ # disable tracing, "lui v1, 0x0" is substituted with "b ++ # label", which jumps over "jalr "; to enable ++ # tracing, replace it back. + # + # c: 3c030000 lui v1,0x0 + # c: R_MIPS_HI16 _mcount +@@ -328,19 +347,12 @@ if ($arch eq "x86_64") { + # 10: R_MIPS_NONE *ABS* + # 14: 03e0082d move at,ra + # 18: 0060f809 jalr v1 ++ # label: + # +- # for the kernel: +- # +- # 10: 03e0082d move at,ra +- # 14: 0c000000 jal 0 +- # 14: R_MIPS_26 _mcount +- # 14: R_MIPS_NONE *ABS* +- # 14: R_MIPS_NONE *ABS* +- # 18: 00020021 nop + if ($is_module eq "0") { + $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$"; + } else { +- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$"; ++ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_(HI16|26)\\s+_mcount\$"; + } + $objdump .= " -Melf-trad".$endian."mips "; + +diff --git a/scripts/sstrip.sh b/scripts/sstrip.sh +new file mode 100755 +index 0000000..49b973a +--- /dev/null ++++ b/scripts/sstrip.sh +@@ -0,0 +1,59 @@ ++#!/bin/bash ++# sstrip.sh -- strip the section table of an elf file ++# ++# Copyright (C) 2010 Wu Zhangjin, wuzhangjin@gmail.com ++# Licensed under the GPLv2 ++# ++# Since the section table is useless for the embedded device, it can be ++# stripped out. ++# ++# Note: Some bootloader may check the section table but most of the time, it ++# may be not really used, If it really need the section table, it may need the ++# decompressed kernel image. ++ ++# Usage ++ ++function usage ++{ ++cat </dev/null` ++[ "xELF" != "x${FILE_TYPE}" ] && echo "$0: ${IMAGE} is not an ELF file" && exit -1 ++ ++[ "x${V}" == "x1" ] && orig_filesz=`wc -c ${IMAGE} | cut -d' ' -f1` ++ ++# Get the offset of the section table, here get the end of the program section ++filesz=$((`${OBJDUMP} -p ${IMAGE} | grep -m1 filesz | tr -s ' ' | cut -d' ' -f3`)) ++ ++# Truncate it via the dd tool ++dd if=/dev/null bs=1 of=${IMAGE} seek=${filesz} 2>/dev/null ++ ++# Clear the section table information in the ELF header ++# The last 6 bytes of the ELF header are the section table information ++echo -ne "\x00\x00\x00\x00\x00\x00" | dd of=${IMAGE} bs=1 seek=46 count=6 conv=notrunc 2>/dev/null ++ ++# Debug ++if [ "x${V}" == "x1" ]; then ++ echo "----------------------------------------------------------------" ++ echo "Strip the section table at ${filesz} of ${IMAGE}" ++ echo "----------------------------------------------------------------" ++ echo " sstrip: $0" ++ echo " objdump: ${OBJDUMP}" ++ echo "original size: ${orig_filesz}" ++ echo "current size: ${filesz}" ++ echo "reduced size: $((${orig_filesz} - ${filesz}))" ++fi diff --git a/kernels/linux-libre-grsec-knock/PKGBUILD b/kernels/linux-libre-grsec-knock/PKGBUILD index 24a513aa3..c9f1cf0e4 100644 --- a/kernels/linux-libre-grsec-knock/PKGBUILD +++ b/kernels/linux-libre-grsec-knock/PKGBUILD @@ -12,9 +12,9 @@ pkgbase=linux-libre-grsec-knock # Build kernel with -grsec-knock localname _pkgbasever=4.0-gnu -_pkgver=4.0.3-gnu +_pkgver=4.0.4-gnu _grsecver=3.1 -_timestamp=201505141746 +_timestamp=201505182014 _knockpatchver=3.18_1 _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname @@ -46,24 +46,24 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li 'change-default-console-loglevel.patch' # loongson-community patch: http://linux-libre.fsfla.org/pub/linux-libre/lemote/gnewsense/pool/debuginfo/ # Note: Makefile patching was removed due which we are using specific flags from grsecurity patch - '4.0-rc7-37af2c8aae-loongson-community.patch') + '4.0.2-ae91f13af5-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - '73e5adbee83c5d5898f03b4f7525876cc0db6eab0e569a4229ee8d8cf9e3ef2e' + 'e447de9a53c5aefd25f0474f3304ab87076b88353badaae20dcbd85712e85e61' 'SKIP' - 'e10e9292b02728a3e2d4157b385298095c29634d00e7ae5f9f2847576d69c570' + '5e098d6ed12ec7926b7a2697fde24ccfabd5ca81de486fc81d257fbf3e003ad0' 'SKIP' '93a1610c203ea4c187ac5b50dce105fac86df914b1406e1d85df5857d36201c9' 'SKIP' - '16760abed3851e97991b09efab107ae27b99668a8a6994ae7d9e9b8fe418c953' - '2e50c28b0dcb8c90780be6bfb5e117403fefb10ecc97a7fae7c90fefdf95c574' - 'de68ea79d9339c4d7ef6706dc573badf4c134c1c730df1a628da2dc88e1bb3a8' + 'df033a9eb5729f61169e3aca092709cf928f820b05fea3efde14d372e2fa607f' + 'fbf48421ebfb46f09457fe601255a7dd3631f24bba28945dcabc5a8772ab3872' + 'ee7da446efd8533761aa4e2e07f8bcdb0e196f06bd067f72f29557caa33cb30b' 'f0d90e756f14533ee67afda280500511a62465b4f76adcc5effa95a40045179c' 'bfd4a7f61febe63c880534dcb7c31c5b932dde6acf991810b41a939a93535494' '6de8a8319271809ffdb072b68d53d155eef12438e6d04ff06a5a4db82c34fa8a' '13bd7a8d9ed6b6bc971e4cd162262c5a20448a83796af39ce394d827b0e5de74' '1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99' - '8a070d193bc54db696b38ac844cfbfd62724f483ad74c9a288ccab462c32f80e') + 'ac7232b38f5a25a79a23c25c8cd5ed4579ca5402466d3370dd093626998092b3') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva 'DE9452CE46F42094907F108B44D1C0F82525FE49' # Bradley Spengler @@ -109,7 +109,7 @@ prepare() { # Adding loongson-community patch if [ "${CARCH}" == "mips64el" ]; then - patch -p1 -i ${srcdir}/4.0-rc7-37af2c8aae-loongson-community.patch + patch -p1 -i ${srcdir}/4.0.2-ae91f13af5-loongson-community.patch fi cat "${srcdir}/config.${CARCH}" > ./.config diff --git a/kernels/linux-libre-grsec-knock/config.i686 b/kernels/linux-libre-grsec-knock/config.i686 index ed73cfead..928e102aa 100644 --- a/kernels/linux-libre-grsec-knock/config.i686 +++ b/kernels/linux-libre-grsec-knock/config.i686 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 4.0.1-gnu-201505031602-1-grsec-knock Kernel Configuration +# Linux/x86 4.0.4-gnu-201505182014-1-grsec-knock Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -151,8 +151,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_HUGETLB is not set # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y @@ -838,7 +838,7 @@ CONFIG_TCP_CONG_DCTCP=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_TCP_STEALTH=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y @@ -3191,6 +3191,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m CONFIG_INPUT_E3X0_BUTTON=m CONFIG_INPUT_PCSPKR=m @@ -3647,7 +3648,7 @@ CONFIG_POWER_RESET_GPIO=y # CONFIG_POWER_RESET_RESTART is not set # CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3805,6 +3806,7 @@ CONFIG_SENSORS_W83627EHF=m CONFIG_SENSORS_ACPI_POWER=m CONFIG_SENSORS_ATK0110=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_OF=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set @@ -4314,6 +4316,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4825,8 +4828,10 @@ CONFIG_SOUND_OSS_CORE=y CONFIG_SND=m CONFIG_SND_TIMER=m CONFIG_SND_PCM=m +CONFIG_SND_DMAENGINE_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -5037,7 +5042,109 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y +# CONFIG_SND_ATMEL_SOC is not set +CONFIG_SND_DESIGNWARE_I2S=m + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +CONFIG_SND_SST_MFLD_PLATFORM=m +CONFIG_SND_SST_IPC=m +CONFIG_SND_SST_IPC_ACPI=m +CONFIG_SND_SOC_INTEL_SST=m +CONFIG_SND_SOC_INTEL_SST_ACPI=m +CONFIG_SND_SOC_INTEL_HASWELL=m +CONFIG_SND_SOC_INTEL_BAYTRAIL=m +CONFIG_SND_SOC_INTEL_HASWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH=m +CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +CONFIG_SND_SOC_MAX98090=m +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +CONFIG_SND_SOC_RL6231=m +CONFIG_SND_SOC_RT286=m +# CONFIG_SND_SOC_RT5631 is not set +CONFIG_SND_SOC_RT5640=m +CONFIG_SND_SOC_RT5645=m +CONFIG_SND_SOC_RT5670=m +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -6234,6 +6341,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set CONFIG_EXTCON_SM5502=m @@ -7308,7 +7416,7 @@ CONFIG_CRYPTO_CRC32_PCLMUL=m CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m diff --git a/kernels/linux-libre-grsec-knock/config.mips64el b/kernels/linux-libre-grsec-knock/config.mips64el index 67209e95d..36c7de4a6 100644 --- a/kernels/linux-libre-grsec-knock/config.mips64el +++ b/kernels/linux-libre-grsec-knock/config.mips64el @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/mips 4.0.1-gnu-201505042053-1-grsec-knock Kernel Configuration +# Linux/mips 4.0.4-gnu-201505182014-1-grsec-knock Kernel Configuration # CONFIG_MIPS=y @@ -271,8 +271,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y CONFIG_FAIR_GROUP_SCHED=y @@ -626,7 +626,7 @@ CONFIG_TCP_CONG_ILLINOIS=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_TCP_STEALTH=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y @@ -2812,6 +2812,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m # CONFIG_INPUT_E3X0_BUTTON is not set CONFIG_INPUT_MC13783_PWRBUTTON=m @@ -3185,7 +3186,7 @@ CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_BRCMSTB is not set # CONFIG_POWER_RESET_RESTART is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3325,6 +3326,7 @@ CONFIG_SENSORS_W83L786NG=m CONFIG_SENSORS_W83627HF=m CONFIG_SENSORS_W83627EHF=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set # CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set @@ -3779,6 +3781,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4232,6 +4235,7 @@ CONFIG_SND_TIMER=m CONFIG_SND_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -4396,7 +4400,87 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +# CONFIG_SND_ATMEL_SOC is not set + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -5381,6 +5465,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set # CONFIG_EXTCON_SM5502 is not set @@ -6366,7 +6451,7 @@ CONFIG_CRYPTO_CRC32=m CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m diff --git a/kernels/linux-libre-grsec-knock/config.x86_64 b/kernels/linux-libre-grsec-knock/config.x86_64 index 1348c9663..481089625 100644 --- a/kernels/linux-libre-grsec-knock/config.x86_64 +++ b/kernels/linux-libre-grsec-knock/config.x86_64 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 4.0.1-gnu-201505031602-1-grsec-knock Kernel Configuration +# Linux/x86 4.0.4-gnu-201505182014-1-grsec-knock Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -159,8 +159,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_HUGETLB is not set # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y @@ -822,7 +822,7 @@ CONFIG_TCP_CONG_DCTCP=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_TCP_STEALTH=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y @@ -3080,6 +3080,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m CONFIG_INPUT_E3X0_BUTTON=m CONFIG_INPUT_PCSPKR=m @@ -3497,7 +3498,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_RESTART is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3654,6 +3655,7 @@ CONFIG_SENSORS_W83627EHF=m CONFIG_SENSORS_ACPI_POWER=m CONFIG_SENSORS_ATK0110=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set # CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set @@ -4143,6 +4145,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4633,8 +4636,10 @@ CONFIG_SOUND_OSS_CORE=y CONFIG_SND=m CONFIG_SND_TIMER=m CONFIG_SND_PCM=m +CONFIG_SND_DMAENGINE_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -4804,7 +4809,109 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y +# CONFIG_SND_ATMEL_SOC is not set +CONFIG_SND_DESIGNWARE_I2S=m + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +CONFIG_SND_SST_MFLD_PLATFORM=m +CONFIG_SND_SST_IPC=m +CONFIG_SND_SST_IPC_ACPI=m +CONFIG_SND_SOC_INTEL_SST=m +CONFIG_SND_SOC_INTEL_SST_ACPI=m +CONFIG_SND_SOC_INTEL_HASWELL=m +CONFIG_SND_SOC_INTEL_BAYTRAIL=m +CONFIG_SND_SOC_INTEL_HASWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH=m +CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +CONFIG_SND_SOC_MAX98090=m +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +CONFIG_SND_SOC_RL6231=m +CONFIG_SND_SOC_RT286=m +# CONFIG_SND_SOC_RT5631 is not set +CONFIG_SND_SOC_RT5640=m +CONFIG_SND_SOC_RT5645=m +CONFIG_SND_SOC_RT5670=m +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -5931,6 +6038,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set CONFIG_EXTCON_SM5502=m @@ -7002,7 +7110,7 @@ CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m diff --git a/libre/linux-libre-grsec/4.0-rc7-37af2c8aae-loongson-community.patch b/libre/linux-libre-grsec/4.0-rc7-37af2c8aae-loongson-community.patch deleted file mode 100644 index 5fb2ec0b7..000000000 --- a/libre/linux-libre-grsec/4.0-rc7-37af2c8aae-loongson-community.patch +++ /dev/null @@ -1,12143 +0,0 @@ -diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig -index c7a1690..0f854f0 100644 ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -333,7 +333,7 @@ config LASAT - - config MACH_LOONGSON - bool "Loongson family of machines" -- select SYS_SUPPORTS_ZBOOT -+ select SYS_SUPPORTS_ZBOOT_UART16550 - help - This enables the support of Loongson family of machines. - -@@ -1640,6 +1640,15 @@ config CPU_LOONGSON2 - bool - select CPU_SUPPORTS_32BIT_KERNEL - select CPU_SUPPORTS_64BIT_KERNEL -+ select CPU_SUPPORTS_HIGHMEM if ! EMBEDDED -+ select ARCH_WANT_OPTIONAL_GPIOLIB -+ -+config CPU_LOONGSON1 -+ bool -+ select CPU_MIPS32 -+ select CPU_MIPSR2 -+ select CPU_HAS_PREFETCH -+ select CPU_SUPPORTS_32BIT_KERNEL - select CPU_SUPPORTS_HIGHMEM - select CPU_SUPPORTS_HUGEPAGES - -@@ -2313,7 +2322,7 @@ config CPU_SUPPORTS_MSA - - config ARCH_FLATMEM_ENABLE - def_bool y -- depends on !NUMA && !CPU_LOONGSON2 -+ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION) - - config ARCH_DISCONTIGMEM_ENABLE - bool -diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile -index 61af6b6..8598044 100644 ---- a/arch/mips/boot/compressed/Makefile -+++ b/arch/mips/boot/compressed/Makefile -@@ -30,9 +30,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ - targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o - - # decompressor objects (linked with vmlinuz) --vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o -+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o - - ifdef CONFIG_DEBUG_ZBOOT -+vmlinuzobjs-y += $(obj)/dbg.o - vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o - vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o - endif -@@ -79,9 +80,18 @@ quiet_cmd_zld = LD $@ - cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ - quiet_cmd_strip = STRIP $@ - cmd_strip = $(STRIP) -s $@ -+ifdef CONFIG_EMBEDDED -+quiet_cmd_sstrip = SSTRIP $@ -+ cmd_sstrip = $(srctree)/scripts/sstrip.sh $@ -+endif - vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr - $(call cmd,zld) - $(call cmd,strip) -+ $(call cmd,sstrip) -+ -+vmlinuz.unsstrip: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr -+ $(call cmd,zld) -+ $(call cmd,strip) - - # - # Some DECstations need all possible sections of an ECOFF executable -@@ -94,14 +104,14 @@ endif - hostprogs-y += ../elf2ecoff - - ifdef CONFIG_32BIT -- VMLINUZ = vmlinuz -+ VMLINUZ = vmlinuz.unsstrip - else - VMLINUZ = vmlinuz.32 - endif - - quiet_cmd_32 = OBJCOPY $@ - cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ --vmlinuz.32: vmlinuz -+vmlinuz.32: vmlinuz.unsstrip - $(call cmd,32) - - quiet_cmd_ecoff = ECOFF $@ -@@ -110,11 +120,11 @@ vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ) - $(call cmd,ecoff) - - OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary --vmlinuz.bin: vmlinuz -+vmlinuz.bin: vmlinuz.unsstrip - $(call cmd,objcopy) - - OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec --vmlinuz.srec: vmlinuz -+vmlinuz.srec: vmlinuz.unsstrip - $(call cmd,objcopy) - --clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} -+clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec,unsstrip} -diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c -index 31903cf..14da73c 100644 ---- a/arch/mips/boot/compressed/decompress.c -+++ b/arch/mips/boot/compressed/decompress.c -@@ -28,8 +28,13 @@ unsigned long free_mem_end_ptr; - extern unsigned char __image_begin, __image_end; - - /* debug interfaces */ -+#ifdef CONFIG_DEBUG_ZBOOT - extern void puts(const char *s); - extern void puthex(unsigned long long val); -+#else -+#define puts(s) -+#define puthex(val) -+#endif - - void error(char *x) - { -diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script -index 5a33409..de04ac9 100644 ---- a/arch/mips/boot/compressed/ld.script -+++ b/arch/mips/boot/compressed/ld.script -@@ -49,5 +49,6 @@ SECTIONS - *(.reginfo) - *(.comment) - *(.note) -+ *(.gnu.attributes) - } - } -diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -index a0ee0cb..4e18add 100644 ---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h -@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo); - /* GPIO : I/O SPACE; REG : 32BITS */ - #define GPIOL_OUT_VAL 0x00 - #define GPIOL_OUT_EN 0x04 -+#define GPIOL_OUT_AUX1_SEL 0x10 -+/* SMB : I/O SPACE, REG : 8BITS WIDTH */ -+#define SMB_SDA 0x00 -+#define SMB_STS 0x01 -+#define SMB_STS_SLVSTP (1 << 7) -+#define SMB_STS_SDAST (1 << 6) -+#define SMB_STS_BER (1 << 5) -+#define SMB_STS_NEGACK (1 << 4) -+#define SMB_STS_STASTR (1 << 3) -+#define SMB_STS_NMATCH (1 << 2) -+#define SMB_STS_MASTER (1 << 1) -+#define SMB_STS_XMIT (1 << 0) -+#define SMB_CTRL_STS 0x02 -+#define SMB_CSTS_TGSTL (1 << 5) -+#define SMB_CSTS_TSDA (1 << 4) -+#define SMB_CSTS_GCMTCH (1 << 3) -+#define SMB_CSTS_MATCH (1 << 2) -+#define SMB_CSTS_BB (1 << 1) -+#define SMB_CSTS_BUSY (1 << 0) -+#define SMB_CTRL1 0x03 -+#define SMB_CTRL1_STASTRE (1 << 7) -+#define SMB_CTRL1_NMINTE (1 << 6) -+#define SMB_CTRL1_GCMEN (1 << 5) -+#define SMB_CTRL1_ACK (1 << 4) -+#define SMB_CTRL1_RSVD (1 << 3) -+#define SMB_CTRL1_INTEN (1 << 2) -+#define SMB_CTRL1_STOP (1 << 1) -+#define SMB_CTRL1_START (1 << 0) -+#define SMB_ADDR 0x04 -+#define SMB_ADDR_SAEN (1 << 7) -+#define SMB_CONTROLLER_ADDR (0xef << 0) -+#define SMB_CTRL2 0x05 -+#define SMB_FREQ (0x20 << 1) -+#define SMB_ENABLE (0x01 << 0) -+#define SMB_CTRL3 0x06 - - #endif /* _CS5536_H */ -diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -index 021d017..50aafca 100644 ---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h -@@ -28,8 +28,19 @@ static inline void __maybe_unused enable_mfgpt0_counter(void) - #define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ) - - #define MFGPT_BASE mfgpt_base -+#define MFGPT0_CMP1 (MFGPT_BASE + 0) - #define MFGPT0_CMP2 (MFGPT_BASE + 2) - #define MFGPT0_CNT (MFGPT_BASE + 4) - #define MFGPT0_SETUP (MFGPT_BASE + 6) - -+#define MFGPT1_CMP1 (MFGPT_BASE + 0x08) -+#define MFGPT1_CMP2 (MFGPT_BASE + 0x0A) -+#define MFGPT1_CNT (MFGPT_BASE + 0x0C) -+#define MFGPT1_SETUP (MFGPT_BASE + 0x0E) -+ -+#define MFGPT2_CMP1 (MFGPT_BASE + 0x10) -+#define MFGPT2_CMP2 (MFGPT_BASE + 0x12) -+#define MFGPT2_CNT (MFGPT_BASE + 0x14) -+#define MFGPT2_SETUP (MFGPT_BASE + 0x16) -+ - #endif /*!_CS5536_MFGPT_H */ -diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h -index 5459ac0..14e82d9 100644 ---- a/arch/mips/include/asm/mach-loongson/loongson.h -+++ b/arch/mips/include/asm/mach-loongson/loongson.h -@@ -46,6 +46,12 @@ static inline void prom_init_uart_base(void) - #endif - } - -+/* -+ * Copy kernel command line from arcs_cmdline -+ */ -+#include -+extern char loongson_cmdline[COMMAND_LINE_SIZE]; -+ - /* irq operation functions */ - extern void bonito_irqdispatch(void); - extern void __init bonito_irq_init(void); -diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h -index cb2b602..78fcd38 100644 ---- a/arch/mips/include/asm/mach-loongson/machine.h -+++ b/arch/mips/include/asm/mach-loongson/machine.h -@@ -24,6 +24,12 @@ - - #endif - -+#ifdef CONFIG_DEXXON_GDIUM -+ -+#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10 -+ -+#endif -+ - #ifdef CONFIG_LOONGSON_MACH3X - - #define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC -diff --git a/arch/mips/include/asm/mach-loongson1/clock.h b/arch/mips/include/asm/mach-loongson1/clock.h -new file mode 100644 -index 0000000..dd1afdb ---- /dev/null -+++ b/arch/mips/include/asm/mach-loongson1/clock.h -@@ -0,0 +1,53 @@ -+#ifndef __ASM_MACH_LOONGSON1_CLOCK_H -+#define __ASM_MACH_LOONGSON1_CLOCK_H -+ -+#include -+#include -+#include -+#include -+ -+extern void (*cpu_wait) (void); -+ -+struct clk; -+ -+struct clk_ops { -+ void (*init) (struct clk *clk); -+ void (*enable) (struct clk *clk); -+ void (*disable) (struct clk *clk); -+ void (*recalc) (struct clk *clk); -+ int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id); -+ long (*round_rate) (struct clk *clk, unsigned long rate); -+}; -+ -+struct clk { -+ struct list_head node; -+ const char *name; -+ int id; -+ struct module *owner; -+ -+ struct clk *parent; -+ struct clk_ops *ops; -+ -+ struct kref kref; -+ -+ unsigned long rate; -+ unsigned long flags; -+}; -+ -+#define CLK_ALWAYS_ENABLED (1 << 0) -+#define CLK_RATE_PROPAGATES (1 << 1) -+ -+/* Should be defined by processor-specific code */ -+void arch_init_clk_ops(struct clk_ops **, int type); -+ -+int clk_init(void); -+ -+int __clk_enable(struct clk *); -+void __clk_disable(struct clk *); -+ -+void clk_recalc_rate(struct clk *); -+ -+int clk_register(struct clk *); -+void clk_unregister(struct clk *); -+ -+#endif /* __ASM_MIPS_CLOCK_H */ -diff --git a/arch/mips/include/asm/mach-loongson1/regs-intc.h b/arch/mips/include/asm/mach-loongson1/regs-intc.h -new file mode 100644 -index 0000000..6d5db23 ---- /dev/null -+++ b/arch/mips/include/asm/mach-loongson1/regs-intc.h -@@ -0,0 +1,25 @@ -+/* -+ * Copyright (c) 2011 Zhang, Keguang -+ * -+ * Loongson1 Interrupt register definitions. -+ * -+ * 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. -+ */ -+ -+#ifndef __ASM_MACH_LOONGSON1_REGS_INTC_H -+#define __ASM_MACH_LOONGSON1_REGS_INTC_H -+ -+#define LS1X_INTC_REG(n, x) \ -+ (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4)) -+ -+#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) -+#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) -+#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) -+#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) -+#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) -+#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) -+ -+#endif /* __ASM_MACH_LOONGSON1_REGS_INTC_H */ -diff --git a/arch/mips/include/asm/sparsemem.h b/arch/mips/include/asm/sparsemem.h -index b1071c1..8b8e551 100644 ---- a/arch/mips/include/asm/sparsemem.h -+++ b/arch/mips/include/asm/sparsemem.h -@@ -11,7 +11,11 @@ - #else - # define SECTION_SIZE_BITS 28 - #endif --#define MAX_PHYSMEM_BITS 48 -+#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit c461731836 broke Loongson2. */ -+# define MAX_PHYSMEM_BITS 48 -+#else -+# define MAX_PHYSMEM_BITS 35 -+#endif - - #endif /* CONFIG_SPARSEMEM */ - #endif /* _MIPS_SPARSEMEM_H */ -diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h -index b05bb70..44c9a69 100644 ---- a/arch/mips/include/asm/timex.h -+++ b/arch/mips/include/asm/timex.h -@@ -11,6 +11,10 @@ - - #ifdef __KERNEL__ - -+#ifdef CONFIG_CSRC_R4K -+#define ARCH_HAS_PREPARED_LPJ -+#endif -+ - #include - - #include -diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h -index fc0cf5a..99e6430 100644 ---- a/arch/mips/include/uapi/asm/inst.h -+++ b/arch/mips/include/uapi/asm/inst.h -@@ -65,6 +65,8 @@ enum spec_op { - enum spec2_op { - madd_op, maddu_op, mul_op, spec2_3_unused_op, - msub_op, msubu_op, /* more unused ops */ -+ loongson_madd_op = 0x18, loongson_msub_op, -+ loongson_nmadd_op, loongson_nmsub_op, - clz_op = 0x20, clo_op, - dclz_op = 0x24, dclo_op, - sdbpp_op = 0x3f -@@ -151,7 +153,7 @@ enum cop0_com_func { - */ - enum cop1_fmt { - s_fmt, d_fmt, e_fmt, q_fmt, -- w_fmt, l_fmt -+ w_fmt, l_fmt, ps_fmt - }; - - /* -@@ -180,7 +182,8 @@ enum cop1_sdw_func { - enum cop1x_func { - lwxc1_op = 0x00, ldxc1_op = 0x01, - swxc1_op = 0x08, sdxc1_op = 0x09, -- pfetch_op = 0x0f, madd_s_op = 0x20, -+ pfetch_op = 0x0f, -+ prefx_op = 0x17, madd_s_op = 0x20, - madd_d_op = 0x21, madd_e_op = 0x22, - msub_s_op = 0x28, msub_d_op = 0x29, - msub_e_op = 0x2a, nmadd_s_op = 0x30, -diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S -index d07b210..69996f2 100644 ---- a/arch/mips/kernel/scall64-o32.S -+++ b/arch/mips/kernel/scall64-o32.S -@@ -26,6 +26,18 @@ - - .align 5 - NESTED(handle_sys, PT_SIZE, sp) -+#ifdef CONFIG_MIPS_USER_RDTSC -+ MFC0 k0, CP0_EPC -+ lw k1, 0(k0) -+ sltiu k1, k1, 0x1c -+ bne k1, zero, 1f # Normal syscall code: 0x0c < 0x1c -+ nop -+ mfc0 v0, CP0_COUNT # Get TSC -+ PTR_ADDIU k0, 4 # ret from syscall -+ MTC0 k0, CP0_EPC -+ eret -+1: -+#endif /* CONFIG_MIPS_USER_RDTSC */ - .set noat - SAVE_SOME - TRACE_IRQS_ON_RELOAD -diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c -index 8d01709..9cd25da 100644 ---- a/arch/mips/kernel/time.c -+++ b/arch/mips/kernel/time.c -@@ -119,6 +119,11 @@ static __init int cpu_has_mfc0_count_bug(void) - - void __init time_init(void) - { -+#ifdef CONFIG_HR_SCHED_CLOCK -+ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) -+ write_c0_count(0); -+#endif -+ - plat_time_init(); - - /* -diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile -index 1e9e900..36fcccc 100644 ---- a/arch/mips/lib/Makefile -+++ b/arch/mips/lib/Makefile -@@ -2,10 +2,14 @@ - # Makefile for MIPS-specific library files.. - # - --lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ -+lib-y += bitops.o csum_partial.o memcpy.o memset.o \ - mips-atomic.o strlen_user.o strncpy_user.o \ - strnlen_user.o uncached.o - -+ifndef CONFIG_CSRC_R4K -+lib-y += delay.o -+endif -+ - obj-y += iomap.o - obj-$(CONFIG_PCI) += iomap-pci.o - lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y)) -diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig -index 156de85..0a433e6 100644 ---- a/arch/mips/loongson/Kconfig -+++ b/arch/mips/loongson/Kconfig -@@ -32,12 +32,12 @@ config LEMOTE_FULOONG2E - - config LEMOTE_MACH2F - bool "Lemote Loongson 2F family machines" -- select ARCH_SPARSEMEM_ENABLE -+ select ARCH_SPARSEMEM_ENABLE if HIBERNATION - select BOARD_SCACHE - select BOOT_ELF32 - select CEVT_R4K if ! MIPS_EXTERNAL_TIMER - select CPU_HAS_WB -- select CS5536 -+ select CS5536 if PCI - select CSRC_R4K if ! MIPS_EXTERNAL_TIMER - select DMA_NONCOHERENT - select GENERIC_ISA_DMA_SUPPORT_BROKEN -@@ -45,14 +45,13 @@ config LEMOTE_MACH2F - select HW_HAS_PCI - select I8259 - select IRQ_CPU -- select ISA - select SYS_HAS_CPU_LOONGSON2F - select SYS_HAS_EARLY_PRINTK - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL -- select SYS_SUPPORTS_HIGHMEM -+ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED - select SYS_SUPPORTS_LITTLE_ENDIAN -- select LOONGSON_MC146818 -+ select LOONGSON_MC146818 if RTC_DRV_CMOS - help - Lemote Loongson 2F family machines utilize the 2F revision of - Loongson processor and the AMD CS5536 south bridge. -@@ -60,6 +59,31 @@ config LEMOTE_MACH2F - These family machines include fuloong2f mini PC, yeeloong2f notebook, - LingLoong allinone PC and so forth. - -+config DEXXON_GDIUM -+ bool "Dexxon Gdium Netbook" -+ select ARCH_SPARSEMEM_ENABLE -+ select BOARD_SCACHE -+ select BOOT_ELF32 -+ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER -+ select CPU_HAS_WB -+ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER -+ select DMA_NONCOHERENT -+ select GENERIC_ISA_DMA_SUPPORT_BROKEN -+ select HW_HAS_PCI -+ select I8259 -+ select IRQ_CPU -+ select ISA -+ select SYS_HAS_CPU_LOONGSON2F -+ select SYS_HAS_EARLY_PRINTK -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_64BIT_KERNEL -+ select SYS_SUPPORTS_HIGHMEM -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select ARCH_REQUIRE_GPIOLIB -+ select HAVE_PWM if MFD_SM501 -+ help -+ Dexxon gdium netbook based on Loongson 2F and SM502. -+ - config LOONGSON_MACH3X - bool "Generic Loongson 3 family machines" - select ARCH_SPARSEMEM_ENABLE -@@ -152,6 +176,24 @@ config LOONGSON_MC146818 - bool - default n - -+config GDIUM_PWM_CLOCK -+ tristate "Gdium PWM Timer" -+ default n -+ depends on HAVE_PWM && EXPERIMENTAL && BROKEN -+ select MIPS_EXTERNAL_TIMER -+ help -+ This options enables the experimental sm501-pwm based clock. With it, -+ you may be possible to use the loongson2f cpufreq driver. -+ -+config GDIUM_VERSION -+ int "Configure Gdium Version" -+ depends on DEXXON_GDIUM -+ default "3" -+ help -+ I have no information about how to determine which version your board -+ is, If the default config doesn't work for it, please change it to -+ smaller ones. -+ - config LEFI_FIRMWARE_INTERFACE - bool - -diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile -index 7429994..63214c8 100644 ---- a/arch/mips/loongson/Makefile -+++ b/arch/mips/loongson/Makefile -@@ -17,6 +17,12 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ - obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ - - # -+# Dexxon gdium netbook, based on loongson 2F and SM502 -+# -+ -+obj-$(CONFIG_DEXXON_GDIUM) += gdium/ -+ -+# - # All Loongson-3 family machines - # - -diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform -index 0ac20eb..cd957dd 100644 ---- a/arch/mips/loongson/Platform -+++ b/arch/mips/loongson/Platform -@@ -30,4 +30,5 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/ - cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely - load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 - load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 -+load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000 - load-$(CONFIG_LOONGSON_MACH3X) += 0xffffffff80200000 -diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c -index 72fed00..96d5919 100644 ---- a/arch/mips/loongson/common/cmdline.c -+++ b/arch/mips/loongson/common/cmdline.c -@@ -17,10 +17,15 @@ - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -+#include - #include - - #include - -+/* the kernel command line copied from arcs_cmdline */ -+char loongson_cmdline[COMMAND_LINE_SIZE]; -+EXPORT_SYMBOL(loongson_cmdline); -+ - void __init prom_init_cmdline(void) - { - int prom_argc; -@@ -45,4 +50,31 @@ void __init prom_init_cmdline(void) - } - - prom_init_machtype(); -+ -+ /* append machine specific command line */ -+ switch (mips_machtype) { -+ case MACH_LEMOTE_LL2F: -+ if ((strstr(arcs_cmdline, "video=")) == NULL) -+ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60"); -+ break; -+ case MACH_LEMOTE_FL2F: -+ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL) -+ strcat(arcs_cmdline, " ide_core.ignore_cable=0"); -+ break; -+ case MACH_LEMOTE_ML2F7: -+ /* Mengloong-2F has a 800x480 screen */ -+ if ((strstr(arcs_cmdline, "vga=")) == NULL) -+ strcat(arcs_cmdline, " vga=0x313"); -+ break; -+ case MACH_DEXXON_GDIUM2F10: -+ /* gdium has a 1024x600 screen */ -+ if ((strstr(arcs_cmdline, "video=")) == NULL) -+ strcat(arcs_cmdline, " video=sm501fb:1024x600@60"); -+ break; -+ default: -+ break; -+ } -+ -+ /* copy arcs_cmdline into loongson_cmdline */ -+ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE); - } -diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c -index 045ea3d..1d1db80 100644 ---- a/arch/mips/loongson/common/env.c -+++ b/arch/mips/loongson/common/env.c -@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap; - struct loongson_system_configuration loongson_sysconf; - - u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; -+EXPORT_SYMBOL_GPL(loongson_chipcfg); - u64 loongson_freqctrl[MAX_PACKAGES]; - - unsigned long long smp_group[4]; -diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile -new file mode 100644 -index 0000000..f3f4f51 ---- /dev/null -+++ b/arch/mips/loongson/gdium/Makefile -@@ -0,0 +1,6 @@ -+# Makefile for gdium -+ -+obj-y += irq.o reset.o platform.o -+ -+obj-$(CONFIG_MFD_SM501) += sm501-pwm.o -+obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o -diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c -new file mode 100644 -index 0000000..fdbf42a ---- /dev/null -+++ b/arch/mips/loongson/gdium/gdium-clock.c -@@ -0,0 +1,234 @@ -+/* -+ * Doesn't work really well. When used, the clocksource is producing -+ * bad timings and the clockevent can't be used (don't have one shot feature -+ * thus can't switch on the fly and the pwm is initialised too late to be able -+ * to use it at boot time). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define CLOCK_PWM 1 -+#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */ -+#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ) -+#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */ -+#define CLOCK_PWM_DUTY 50 -+#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4) -+ -+static const char drv_name[] = "gdium-clock"; -+ -+static struct pwm_device *clock_pwm; -+ -+static DEFINE_SPINLOCK(clock_pwm_lock); -+static uint64_t clock_tick; -+ -+static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id) -+{ -+ struct clock_event_device *cd = dev_id; -+ unsigned long flag; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ clock_tick++; -+ /* wait intn2 to finish */ -+ do { -+ LOONGSON_INTENCLR = (1 << 13); -+ } while (LOONGSON_INTISR & (1 << 13)); -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ -+ if (cd && cd->event_handler) -+ cd->event_handler(cd); -+ -+ return IRQ_HANDLED; -+} -+ -+static cycle_t gdium_pwm_clock_read(struct clocksource *cs) -+{ -+ unsigned long flag; -+ uint32_t jifs; -+ uint64_t ticks; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ jifs = jiffies; -+ ticks = clock_tick; -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ /* return (cycle_t)ticks; */ -+ return (cycle_t)(CLOCK_LATCH * jifs); -+} -+ -+static struct clocksource gdium_pwm_clock_clocksource = { -+ .name = "gdium_csrc", -+ .read = gdium_pwm_clock_read, -+ .mask = CLOCKSOURCE_MASK(64), -+ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, -+ .shift = 20, -+}; -+ -+/* Debug fs */ -+static int gdium_pwm_clock_show(struct seq_file *s, void *p) -+{ -+ unsigned long flag; -+ uint64_t ticks; -+ -+ spin_lock_irqsave(&clock_pwm_lock, flag); -+ ticks = clock_tick; -+ spin_unlock_irqrestore(&clock_pwm_lock, flag); -+ seq_printf(s, "%lld\n", ticks); -+ return 0; -+} -+ -+static int gdium_pwm_clock_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, gdium_pwm_clock_show, inode->i_private); -+} -+ -+static const struct file_operations gdium_pwm_clock_fops = { -+ .open = gdium_pwm_clock_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+static struct dentry *debugfs_file; -+ -+static void gdium_pwm_clock_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *evt) -+{ -+ /* Nothing to do ... */ -+} -+ -+static struct clock_event_device gdium_pwm_clock_cevt = { -+ .name = "gdium_cevt", -+ .features = CLOCK_EVT_FEAT_PERIODIC, -+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ -+ .rating = 299, -+ .irq = CLOCK_PWM_IRQ, -+ .set_mode = gdium_pwm_clock_set_mode, -+}; -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "gdium-pwmclk", -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver gdium_pwm_clock_driver = { -+ .driver = { -+ .name = drv_name, -+ .owner = THIS_MODULE, -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int gdium_pwm_clock_drvinit(void) -+{ -+ int ret; -+ struct clocksource *cs = &gdium_pwm_clock_clocksource; -+ struct clock_event_device *cd = &gdium_pwm_clock_cevt; -+ unsigned int cpu = smp_processor_id(); -+ -+ clock_tick = 0; -+ -+ clock_pwm = pwm_request(CLOCK_PWM, drv_name); -+ if (clock_pwm == NULL) { -+ pr_err("unable to request PWM for Gdium clock\n"); -+ return -EBUSY; -+ } -+ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD); -+ if (ret) { -+ pr_err("unable to configure PWM for Gdium clock\n"); -+ goto err_pwm_request; -+ } -+ ret = pwm_enable(clock_pwm); -+ if (ret) { -+ pr_err("unable to enable PWM for Gdium clock\n"); -+ goto err_pwm_request; -+ } -+ -+ cd->cpumask = cpumask_of(cpu); -+ -+ cd->shift = 22; -+ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift); -+ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd); -+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd); -+ clockevents_register_device(&gdium_pwm_clock_cevt); -+ -+ /* SM501 PWM1 connected to intn2 <->ip4 */ -+ LOONGSON_INTPOL = (1 << 13); -+ LOONGSON_INTEDGE &= ~(1 << 13); -+ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt); -+ if (ret) { -+ pr_err("Can't claim irq\n"); -+ goto err_pwm_disable; -+ } -+ -+ cs->rating = 200; -+ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift); -+ ret = clocksource_register(&gdium_pwm_clock_clocksource); -+ if (ret) { -+ pr_err("Can't register clocksource\n"); -+ goto err_irq; -+ } -+ pr_info("Clocksource registered with shift %d and mult %d\n", -+ cs->shift, cs->mult); -+ -+ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO, -+ NULL, NULL, &gdium_pwm_clock_fops); -+ -+ return 0; -+ -+err_irq: -+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); -+err_pwm_disable: -+ pwm_disable(clock_pwm); -+err_pwm_request: -+ pwm_free(clock_pwm); -+ return ret; -+} -+ -+static void gdium_pwm_clock_drvexit(void) -+{ -+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); -+ pwm_disable(clock_pwm); -+ pwm_free(clock_pwm); -+} -+ -+ -+static int __devinit gdium_pwm_clock_init(void) -+{ -+ int ret = gdium_pwm_clock_drvinit(); -+ -+ if (ret) { -+ pr_err("Fail to register gdium clock driver\n"); -+ return ret; -+ } -+ -+ return platform_driver_register(&gdium_pwm_clock_driver); -+} -+ -+static void __exit gdium_pwm_clock_cleanup(void) -+{ -+ gdium_pwm_clock_drvexit(); -+ platform_driver_unregister(&gdium_pwm_clock_driver); -+} -+ -+module_init(gdium_pwm_clock_init); -+module_exit(gdium_pwm_clock_cleanup); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("Gdium PWM clock driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:gdium-pwmclk"); -diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c -new file mode 100644 -index 0000000..2415d20 ---- /dev/null -+++ b/arch/mips/loongson/gdium/irq.c -@@ -0,0 +1,55 @@ -+/* -+ * Copyright (C) 2007 Lemote Inc. -+ * Author: Fuxin Zhang, zhangfx@lemote.com -+ * -+ * Copyright (c) 2010 yajin -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+ -+#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */ -+#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */ -+#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */ -+ -+void mach_irq_dispatch(unsigned int pending) -+{ -+ if (pending & CAUSEF_IP7) -+ do_IRQ(LOONGSON_TIMER_IRQ); -+ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ -+ do_perfcnt_IRQ(); -+ bonito_irqdispatch(); -+ } else if (pending & CAUSEF_IP3) /* CPU UART */ -+ do_IRQ(LOONGSON_UART_IRQ); -+#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE) -+ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */ -+ do_IRQ(MIPS_CPU_IRQ_BASE + 4); -+#endif -+ else -+ spurious_interrupt(); -+} -+ -+static irqreturn_t ip6_action(int cpl, void *dev_id) -+{ -+ return IRQ_HANDLED; -+} -+ -+struct irqaction ip6_irqaction = { -+ .handler = ip6_action, -+ .name = "cascade", -+ .flags = IRQF_SHARED, -+}; -+ -+void __init mach_init_irq(void) -+{ -+ /* setup north bridge irq (bonito) */ -+ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction); -+} -diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c -new file mode 100644 -index 0000000..ffafba4 ---- /dev/null -+++ b/arch/mips/loongson/gdium/platform.c -@@ -0,0 +1,135 @@ -+/* -+ * Copyright (c) 2009 Philippe Vachon -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define GDIUM_GPIO_BASE 224 -+ -+static struct i2c_board_info __initdata sm502dev_i2c_devices[] = { -+ { -+ I2C_BOARD_INFO("lm75", 0x48), -+ }, -+ { -+ I2C_BOARD_INFO("m41t83", 0x68), -+ }, -+ { -+ I2C_BOARD_INFO("gdium-laptop", 0x40), -+ }, -+}; -+ -+static int sm502dev_backlight_init(struct device *dev) -+{ -+ /* Add gpio request stuff here */ -+ return 0; -+} -+ -+static void sm502dev_backlight_exit(struct device *dev) -+{ -+ /* Add gpio free stuff here */ -+} -+ -+static struct platform_pwm_backlight_data backlight_data = { -+ .pwm_id = 0, -+ .max_brightness = 15, -+ .dft_brightness = 8, -+ .pwm_period_ns = 50000, /* 20 kHz */ -+ .init = sm502dev_backlight_init, -+ .exit = sm502dev_backlight_exit, -+}; -+ -+static struct platform_device backlight = { -+ .name = "pwm-backlight", -+ .dev = { -+ .platform_data = &backlight_data, -+ }, -+ .id = -1, -+}; -+ -+/* -+ * Warning this stunt is very dangerous -+ * as the sm501 gpio have dynamic numbers... -+ */ -+/* bus 0 is the one for the ST7, DS75 etc... */ -+static struct i2c_gpio_platform_data i2c_gpio0_data = { -+#if CONFIG_GDIUM_VERSION > 2 -+ .sda_pin = GDIUM_GPIO_BASE + 13, -+ .scl_pin = GDIUM_GPIO_BASE + 6, -+#else -+ .sda_pin = 192+15, -+ .scl_pin = 192+14, -+#endif -+ .udelay = 5, -+ .timeout = HZ / 10, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+}; -+ -+static struct platform_device i2c_gpio0_device = { -+ .name = "i2c-gpio", -+ .id = 0, -+ .dev = { .platform_data = &i2c_gpio0_data, }, -+}; -+ -+/* bus 1 is for the CRT/VGA external screen */ -+static struct i2c_gpio_platform_data i2c_gpio1_data = { -+ .sda_pin = GDIUM_GPIO_BASE + 10, -+ .scl_pin = GDIUM_GPIO_BASE + 9, -+ .udelay = 5, -+ .timeout = HZ / 10, -+ .sda_is_open_drain = 0, -+ .scl_is_open_drain = 0, -+}; -+ -+static struct platform_device i2c_gpio1_device = { -+ .name = "i2c-gpio", -+ .id = 1, -+ .dev = { .platform_data = &i2c_gpio1_data, }, -+}; -+ -+static struct platform_device gdium_clock = { -+ .name = "gdium-pwmclk", -+ .id = -1, -+}; -+ -+static struct platform_device *devices[] __initdata = { -+ &i2c_gpio0_device, -+ &i2c_gpio1_device, -+ &backlight, -+ &gdium_clock, -+}; -+ -+static int __init gdium_platform_devices_setup(void) -+{ -+ int ret; -+ -+ pr_info("Registering gdium platform devices\n"); -+ -+ ret = i2c_register_board_info(0, sm502dev_i2c_devices, -+ ARRAY_SIZE(sm502dev_i2c_devices)); -+ -+ if (ret != 0) { -+ pr_info("Error while registering platform devices: %d\n", ret); -+ return ret; -+ } -+ -+ platform_add_devices(devices, ARRAY_SIZE(devices)); -+ -+ return 0; -+} -+ -+/* -+ * some devices are on the pwm stuff which is behind the mfd which is -+ * behind the pci bus so arch_initcall can't work because too early -+ */ -+late_initcall(gdium_platform_devices_setup); -diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c -new file mode 100644 -index 0000000..8289f95 ---- /dev/null -+++ b/arch/mips/loongson/gdium/reset.c -@@ -0,0 +1,22 @@ -+/* Board-specific reboot/shutdown routines -+ * -+ * Copyright (C) 2010 yajin -+ * -+ * 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. -+ */ -+#include -+ -+void mach_prepare_shutdown(void) -+{ -+ LOONGSON_GPIOIE &= ~(1<<1); -+ LOONGSON_GPIODATA |= (1<<1); -+} -+ -+void mach_prepare_reboot(void) -+{ -+ LOONGSON_GPIOIE &= ~(1<<2); -+ LOONGSON_GPIODATA &= ~(1<<2); -+} -diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c -new file mode 100644 -index 0000000..5af3b23 ---- /dev/null -+++ b/arch/mips/loongson/gdium/sm501-pwm.c -@@ -0,0 +1,465 @@ -+/* -+ * SM501 PWM clock -+ * Copyright (C) 2009-2010 Arnaud Patard -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static const char drv_name[] = "sm501-pwm"; -+ -+#define INPUT_CLOCK 96 /* MHz */ -+#define PWM_COUNT 3 -+ -+#define SM501PWM_HIGH_COUNTER (1<<20) -+#define SM501PWM_LOW_COUNTER (1<<8) -+#define SM501PWM_CLOCK_DIVIDE (1>>4) -+#define SM501PWM_IP (1<<3) -+#define SM501PWM_I (1<<2) -+#define SM501PWM_E (1<<0) -+ -+struct pwm_device { -+ struct list_head node; -+ struct device *dev; -+ void __iomem *regs; -+ int duty_ns; -+ int period_ns; -+ char enabled; -+ void (*handler)(struct pwm_device *pwm); -+ -+ const char *label; -+ unsigned int use_count; -+ unsigned int pwm_id; -+}; -+ -+struct sm501pwm_info { -+ void __iomem *regs; -+ int irq; -+ struct resource *res; -+ struct device *dev; -+ struct dentry *debugfs; -+ -+ struct pwm_device pwm[3]; -+}; -+ -+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -+{ -+ unsigned int high, low, divider; -+ int divider1, divider2; -+ unsigned long long delay; -+ -+ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns) -+ return -EINVAL; -+ -+ /* Get delay -+ * We're loosing some precision but multiplying then dividing -+ * will overflow -+ */ -+ if (period_ns > 1000) { -+ delay = period_ns / 1000; -+ delay *= INPUT_CLOCK; -+ } else { -+ delay = period_ns * 96; -+ delay /= 1000; -+ } -+ -+ /* Get the number of clock low and high */ -+ high = delay * duty_ns / period_ns; -+ low = delay - high; -+ -+ /* Get divider to make 'low' and 'high' fit into 12 bits */ -+ /* No need to say that the divider must be >= 0 */ -+ divider1 = fls(low)-12; -+ divider2 = fls(high)-12; -+ -+ if (divider1 < 0) -+ divider1 = 0; -+ if (divider2 < 0) -+ divider2 = 0; -+ -+ divider = max(divider1, divider2); -+ -+ low >>= divider; -+ high >>= divider; -+ -+ pwm->duty_ns = duty_ns; -+ pwm->period_ns = period_ns; -+ -+ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_config); -+ -+int pwm_enable(struct pwm_device *pwm) -+{ -+ u32 reg; -+ -+ if (!pwm) -+ return -EINVAL; -+ -+ switch (pwm->pwm_id) { -+ case 0: -+ sm501_configure_gpio(pwm->dev->parent, 29, 1); -+ break; -+ case 1: -+ sm501_configure_gpio(pwm->dev->parent, 30, 1); -+ break; -+ case 2: -+ sm501_configure_gpio(pwm->dev->parent, 31, 1); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ reg = readl(pwm->regs); -+ reg |= (SM501PWM_IP | SM501PWM_E); -+ writel(reg, pwm->regs); -+ pwm->enabled = 1; -+ -+ return 0; -+} -+EXPORT_SYMBOL(pwm_enable); -+ -+void pwm_disable(struct pwm_device *pwm) -+{ -+ u32 reg; -+ -+ if (!pwm) -+ return; -+ -+ reg = readl(pwm->regs); -+ reg &= ~(SM501PWM_IP | SM501PWM_E); -+ writel(reg, pwm->regs); -+ -+ switch (pwm->pwm_id) { -+ case 0: -+ sm501_configure_gpio(pwm->dev->parent, 29, 0); -+ break; -+ case 1: -+ sm501_configure_gpio(pwm->dev->parent, 30, 0); -+ break; -+ case 2: -+ sm501_configure_gpio(pwm->dev->parent, 31, 0); -+ break; -+ default: -+ break; -+ } -+ pwm->enabled = 0; -+} -+EXPORT_SYMBOL(pwm_disable); -+ -+static DEFINE_MUTEX(pwm_lock); -+static LIST_HEAD(pwm_list); -+ -+struct pwm_device *pwm_request(int pwm_id, const char *label) -+{ -+ struct pwm_device *pwm; -+ int found = 0; -+ -+ mutex_lock(&pwm_lock); -+ -+ list_for_each_entry(pwm, &pwm_list, node) { -+ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) { -+ pwm->use_count++; -+ pwm->label = label; -+ found = 1; -+ break; -+ } -+ } -+ -+ mutex_unlock(&pwm_lock); -+ -+ return (found) ? pwm : NULL; -+} -+EXPORT_SYMBOL(pwm_request); -+ -+void pwm_free(struct pwm_device *pwm) -+{ -+ mutex_lock(&pwm_lock); -+ -+ if (pwm->use_count) { -+ pwm->use_count--; -+ pwm->label = NULL; -+ } else -+ dev_warn(pwm->dev, "PWM device already freed\n"); -+ -+ mutex_unlock(&pwm_lock); -+} -+EXPORT_SYMBOL(pwm_free); -+ -+int pwm_int_enable(struct pwm_device *pwm) -+{ -+ unsigned long conf; -+ -+ if (!pwm || !pwm->regs || !pwm->handler) -+ return -EINVAL; -+ -+ conf = readl(pwm->regs); -+ conf |= SM501PWM_I; -+ writel(conf, pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_int_enable); -+ -+int pwm_int_disable(struct pwm_device *pwm) -+{ -+ unsigned long conf; -+ -+ if (!pwm || !pwm->regs || !pwm->handler) -+ return -EINVAL; -+ -+ conf = readl(pwm->regs); -+ conf &= ~SM501PWM_I; -+ writel(conf, pwm->regs); -+ return 0; -+} -+EXPORT_SYMBOL(pwm_int_disable); -+ -+int pwm_set_handler(struct pwm_device *pwm, -+ void (*handler)(struct pwm_device *pwm)) -+{ -+ if (!pwm || !handler) -+ return -EINVAL; -+ pwm->handler = handler; -+ return 0; -+} -+EXPORT_SYMBOL(pwm_set_handler); -+ -+static irqreturn_t sm501pwm_irq(int irq, void *dev_id) -+{ -+ unsigned long value; -+ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id; -+ struct pwm_device *pwm; -+ int i; -+ -+ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0); -+ -+ /* Check is the interrupt is for us */ -+ if (value & (1<<22)) { -+ for (i = 0 ; i < PWM_COUNT ; i++) { -+ /* -+ * Find which pwm triggered the interrupt -+ * and ack -+ */ -+ value = readl(info->regs + i*4); -+ if (value & SM501PWM_IP) -+ writel(value | SM501PWM_IP, info->regs + i*4); -+ -+ pwm = &info->pwm[i]; -+ if (pwm->handler) -+ pwm->handler(pwm); -+ } -+ return IRQ_HANDLED; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static void add_pwm(int id, struct sm501pwm_info *info) -+{ -+ struct pwm_device *pwm = &info->pwm[id]; -+ -+ pwm->use_count = 0; -+ pwm->pwm_id = id; -+ pwm->dev = info->dev; -+ pwm->regs = info->regs + id * 4; -+ -+ mutex_lock(&pwm_lock); -+ list_add_tail(&pwm->node, &pwm_list); -+ mutex_unlock(&pwm_lock); -+} -+ -+static void del_pwm(int id, struct sm501pwm_info *info) -+{ -+ struct pwm_device *pwm = &info->pwm[id]; -+ -+ pwm->use_count = 0; -+ pwm->pwm_id = -1; -+ mutex_lock(&pwm_lock); -+ list_del(&pwm->node); -+ mutex_unlock(&pwm_lock); -+} -+ -+/* Debug fs */ -+static int sm501pwm_show(struct seq_file *s, void *p) -+{ -+ struct pwm_device *pwm; -+ -+ mutex_lock(&pwm_lock); -+ list_for_each_entry(pwm, &pwm_list, node) { -+ if (pwm->use_count) { -+ seq_printf(s, "pwm-%d (%12s) %d %d %s\n", -+ pwm->pwm_id, pwm->label, -+ pwm->duty_ns, pwm->period_ns, -+ pwm->enabled ? "on" : "off"); -+ seq_printf(s, " %08x\n", readl(pwm->regs)); -+ } -+ } -+ mutex_unlock(&pwm_lock); -+ -+ return 0; -+} -+ -+static int sm501pwm_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, sm501pwm_show, inode->i_private); -+} -+ -+static const struct file_operations sm501pwm_fops = { -+ .open = sm501pwm_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init sm501pwm_probe(struct platform_device *pdev) -+{ -+ struct sm501pwm_info *info; -+ struct device *dev = &pdev->dev; -+ struct resource *res; -+ int ret = 0; -+ int res_len; -+ int i; -+ -+ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL); -+ if (!info) { -+ dev_err(dev, "Allocation failure\n"); -+ ret = -ENOMEM; -+ goto err; -+ } -+ info->dev = dev; -+ platform_set_drvdata(pdev, info); -+ -+ /* Get irq number */ -+ info->irq = platform_get_irq(pdev, 0); -+ if (!info->irq) { -+ dev_err(dev, "no irq found\n"); -+ ret = -ENODEV; -+ goto err_alloc; -+ } -+ -+ /* Get regs address */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res == NULL) { -+ dev_err(dev, "No memory resource found\n"); -+ ret = -ENODEV; -+ goto err_alloc; -+ } -+ info->res = res; -+ res_len = (res->end - res->start)+1; -+ -+ if (!request_mem_region(res->start, res_len, drv_name)) { -+ dev_err(dev, "Can't request iomem resource\n"); -+ ret = -EBUSY; -+ goto err_alloc; -+ } -+ -+ info->regs = ioremap(res->start, res_len); -+ if (!info->regs) { -+ dev_err(dev, "ioremap failed\n"); -+ ret = -ENOMEM; -+ goto err_mem; -+ } -+ -+ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info); -+ if (ret != 0) { -+ dev_err(dev, "can't get irq\n"); -+ goto err_map; -+ } -+ -+ -+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1); -+ -+ for (i = 0; i < 3; i++) -+ add_pwm(i, info); -+ -+ dev_info(dev, "SM501 PWM Found at %lx irq %d\n", -+ (unsigned long)info->res->start, info->irq); -+ -+ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO, -+ NULL, info, &sm501pwm_fops); -+ -+ -+ return 0; -+ -+err_map: -+ iounmap(info->regs); -+ -+err_mem: -+ release_mem_region(res->start, res_len); -+ -+err_alloc: -+ kfree(info); -+ platform_set_drvdata(pdev, NULL); -+err: -+ return ret; -+} -+ -+static int sm501pwm_remove(struct platform_device *pdev) -+{ -+ struct sm501pwm_info *info = platform_get_drvdata(pdev); -+ int i; -+ -+ if (info->debugfs) -+ debugfs_remove(info->debugfs); -+ -+ for (i = 0; i < 3; i++) { -+ pwm_disable(&info->pwm[i]); -+ del_pwm(i, info); -+ } -+ -+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0); -+ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22); -+ -+ free_irq(info->irq, info); -+ iounmap(info->regs); -+ release_mem_region(info->res->start, -+ (info->res->end - info->res->start)+1); -+ kfree(info); -+ platform_set_drvdata(pdev, NULL); -+ -+ return 0; -+} -+ -+static struct platform_driver sm501pwm_driver = { -+ .probe = sm501pwm_probe, -+ .remove = sm501pwm_remove, -+ .driver = { -+ .name = drv_name, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __devinit sm501pwm_init(void) -+{ -+ return platform_driver_register(&sm501pwm_driver); -+} -+ -+static void __exit sm501pwm_cleanup(void) -+{ -+ platform_driver_unregister(&sm501pwm_driver); -+} -+ -+module_init(sm501pwm_init); -+module_exit(sm501pwm_cleanup); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("SM501 PWM driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:sm501-pwm"); -diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile -index 4f9eaa3..f945bd7a 100644 ---- a/arch/mips/loongson/lemote-2f/Makefile -+++ b/arch/mips/loongson/lemote-2f/Makefile -@@ -2,7 +2,7 @@ - # Makefile for lemote loongson2f family machines - # - --obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o -+obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o platform.o - - # - # Suspend Support -diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c -new file mode 100644 -index 0000000..5316360 ---- /dev/null -+++ b/arch/mips/loongson/lemote-2f/platform.c -@@ -0,0 +1,48 @@ -+/* -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+ -+static struct platform_device yeeloong_pdev = { -+ .name = "yeeloong_laptop", -+ .id = -1, -+}; -+ -+static struct platform_device lynloong_pdev = { -+ .name = "lynloong_pc", -+ .id = -1, -+}; -+ -+static int __init lemote2f_platform_init(void) -+{ -+ struct platform_device *pdev = NULL; -+ -+ switch (mips_machtype) { -+ case MACH_LEMOTE_YL2F89: -+ pdev = &yeeloong_pdev; -+ break; -+ case MACH_LEMOTE_LL2F: -+ pdev = &lynloong_pdev; -+ break; -+ default: -+ break; -+ -+ } -+ -+ if (pdev != NULL) -+ return platform_device_register(pdev); -+ -+ return -ENODEV; -+} -+ -+arch_initcall(lemote2f_platform_init); -diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c -index b30bf65..c0177cb 100644 ---- a/arch/mips/math-emu/cp1emu.c -+++ b/arch/mips/math-emu/cp1emu.c -@@ -7,6 +7,9 @@ - * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. - * -+ * Loongson instruction support -+ * Copyright (C) 2011 Mark H Weaver -+ * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. -@@ -60,6 +63,11 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, - static int fpux_emu(struct pt_regs *, - struct mips_fpu_struct *, mips_instruction, void *__user *); - -+#ifdef CONFIG_MACH_LOONGSON -+static int loongson_spec2_emu(struct pt_regs *, -+ struct mips_fpu_struct *, mips_instruction, void *__user *); -+#endif -+ - /* Control registers */ - - #define FPCREG_RID 0 /* $0 = revision id */ -@@ -842,6 +850,14 @@ do { \ - #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) - #define DPTOREG(dp, x) DITOREG((dp).bits, x) - -+/* Support for Loongson paired single floating-point format */ -+#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \ -+ (si1) = (u32)di; (si2) = (u32)(di >> 32); }) -+#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x) -+ -+#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x) -+#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x) -+ - /* - * Emulate the single floating point instruction pointed at by EPC. - * Two instructions if the instruction is in a branch delay slot. -@@ -1235,6 +1251,16 @@ emul: - xcp->regs[MIPSInst_RD(ir)] = - xcp->regs[MIPSInst_RS(ir)]; - break; -+ -+#ifdef CONFIG_MACH_LOONGSON -+ case spec2_op:{ -+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr); -+ if (sig) -+ return sig; -+ break; -+ } -+#endif -+ - default: - sigill: - return SIGILL; -@@ -1312,6 +1338,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); - DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); - DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); - -+#ifdef CONFIG_MACH_LOONGSON -+static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, -+ mips_instruction ir, void *__user *fault_addr) -+{ -+ int rfmt; /* resulting format */ -+ unsigned rcsr = 0; /* resulting csr */ -+ union { -+ union ieee754dp d; -+ struct { -+ union ieee754sp s; -+ union ieee754sp s2; -+ }; -+ } rv; /* resulting value */ -+ -+ /* XXX maybe add a counter for loongson spec2 fp instructions? */ -+ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */ -+ -+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { -+ case s_fmt:{ -+ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); -+ union ieee754sp fd, fs, ft; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_sp_madd; -+ goto scoptop; -+ case loongson_msub_op: -+ handler = fpemu_sp_msub; -+ goto scoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_sp_nmadd; -+ goto scoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_sp_nmsub; -+ goto scoptop; -+ -+ scoptop: -+ SPFROMREG(fd, MIPSInst_FD(ir)); -+ SPFROMREG(fs, MIPSInst_FS(ir)); -+ SPFROMREG(ft, MIPSInst_FT(ir)); -+ rv.s = (*handler) (fd, fs, ft); -+ -+ copcsr: -+ if (ieee754_cxtest(IEEE754_INEXACT)) -+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; -+ if (ieee754_cxtest(IEEE754_UNDERFLOW)) -+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; -+ if (ieee754_cxtest(IEEE754_OVERFLOW)) -+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; -+ if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) -+ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; -+ -+ break; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ case d_fmt:{ -+ union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); -+ union ieee754dp fd, fs, ft; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_dp_madd; -+ goto dcoptop; -+ case loongson_msub_op: -+ handler = fpemu_dp_msub; -+ goto dcoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_dp_nmadd; -+ goto dcoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_dp_nmsub; -+ goto dcoptop; -+ -+ dcoptop: -+ DPFROMREG(fd, MIPSInst_FD(ir)); -+ DPFROMREG(fs, MIPSInst_FS(ir)); -+ DPFROMREG(ft, MIPSInst_FT(ir)); -+ rv.d = (*handler) (fd, fs, ft); -+ goto copcsr; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ case ps_fmt:{ -+ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fd1, fs1, ft1; -+ union ieee754sp fd2, fs2, ft2; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ case loongson_madd_op: -+ handler = fpemu_sp_madd; -+ goto pscoptop; -+ case loongson_msub_op: -+ handler = fpemu_sp_msub; -+ goto pscoptop; -+ case loongson_nmadd_op: -+ handler = fpemu_sp_nmadd; -+ goto pscoptop; -+ case loongson_nmsub_op: -+ handler = fpemu_sp_nmsub; -+ goto pscoptop; -+ -+ pscoptop: -+ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir)); -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); -+ rv.s = (*handler) (fd1, fs1, ft1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler) (fd2, fs2, ft2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ -+ default: -+ return SIGILL; -+ } -+ break; -+ } -+ -+ default: -+ return SIGILL; -+ } -+ -+ /* -+ * Update the fpu CSR register for this operation. -+ * If an exception is required, generate a tidy SIGFPE exception, -+ * without updating the result register. -+ * Note: cause exception bits do not accumulate, they are rewritten -+ * for each op; only the flag/sticky bits accumulate. -+ */ -+ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; -+ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { -+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ -+ return SIGFPE; -+ } -+ -+ /* -+ * Now we can safely write the result back to the register file. -+ */ -+ switch (rfmt) { -+ case d_fmt: -+ DPTOREG(rv.d, MIPSInst_FD(ir)); -+ break; -+ case s_fmt: -+ SPTOREG(rv.s, MIPSInst_FD(ir)); -+ break; -+ case ps_fmt: -+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); -+ break; -+ default: -+ return SIGILL; -+ } -+ -+ return 0; -+} -+#endif -+ - static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - mips_instruction ir, void *__user *fault_addr) - { -@@ -1413,7 +1605,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - break; - - default: -- return SIGILL; -+ goto SIGILL_unless_prefx_op; - } - break; - } -@@ -1483,7 +1675,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - goto copcsr; - - default: -- return SIGILL; -+ goto SIGILL_unless_prefx_op; - } - break; - } -@@ -1496,6 +1688,11 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - break; - - default: -+ SIGILL_unless_prefx_op: -+ if (MIPSInst_FUNC(ir) == prefx_op) { -+ /* ignore prefx operation */ -+ break; -+ } - return SIGILL; - } - -@@ -1517,7 +1714,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - unsigned cond; - union { - union ieee754dp d; -- union ieee754sp s; -+ struct { -+ union ieee754sp s; -+#ifdef CONFIG_MACH_LOONGSON -+ union ieee754sp s2; /* for Loongson paired singles */ -+#endif -+ }; - int w; - s64 l; - } rv; /* resulting value */ -@@ -1614,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - case fmov_op: - /* an easy one */ - SPFROMREG(rv.s, MIPSInst_FS(ir)); -- goto copcsr; -+ break; - - /* binary op on handler */ - scopbop: -@@ -1811,7 +2013,7 @@ copcsr: - case fmov_op: - /* an easy one */ - DPFROMREG(rv.d, MIPSInst_FS(ir)); -- goto copcsr; -+ break; - - /* binary op on handler */ - dcopbop: -@@ -1928,6 +2130,83 @@ dcopuop: - break; - } - -+#ifdef CONFIG_MACH_LOONGSON -+ case ps_fmt:{ /* 6 */ -+ /* Support for Loongson paired single fp instructions */ -+ union { -+ union ieee754sp(*b) (union ieee754sp, union ieee754sp); -+ union ieee754sp(*u) (union ieee754sp); -+ } handler; -+ -+ switch (MIPSInst_FUNC(ir)) { -+ /* binary ops */ -+ case fadd_op: -+ handler.b = ieee754sp_add; -+ goto pscopbop; -+ case fsub_op: -+ handler.b = ieee754sp_sub; -+ goto pscopbop; -+ case fmul_op: -+ handler.b = ieee754sp_mul; -+ goto pscopbop; -+ -+ /* unary ops */ -+ case fabs_op: -+ handler.u = ieee754sp_abs; -+ goto pscopuop; -+ case fneg_op: -+ handler.u = ieee754sp_neg; -+ goto pscopuop; -+ case fmov_op: -+ /* an easy one */ -+ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir)); -+ break; -+ -+ pscopbop: /* paired binary op handler */ -+ { -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fs1, ft1; -+ union ieee754sp fs2, ft2; -+ -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); -+ rv.s = (*handler.b) (fs1, ft1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler.b) (fs2, ft2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ } -+ pscopuop: /* paired unary op handler */ -+ { -+ struct _ieee754_csr ieee754_csr_save; -+ union ieee754sp fs1; -+ union ieee754sp fs2; -+ -+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); -+ rv.s = (*handler.u) (fs1); -+ ieee754_csr_save = ieee754_csr; -+ rv.s2 = (*handler.u) (fs2); -+ ieee754_csr.cx |= ieee754_csr_save.cx; -+ ieee754_csr.sx |= ieee754_csr_save.sx; -+ goto copcsr; -+ } -+ break; -+ -+ default: -+ if (MIPSInst_FUNC(ir) >= fcmp_op) { -+ /* Loongson fp hardware handles all -+ cases of fp compare insns, so we -+ shouldn't have to */ -+ printk ("Loongson paired-single fp compare" -+ " unimplemented in cp1emu.c\n"); -+ } -+ return SIGILL; -+ } -+ break; -+ } -+#endif -+ - case l_fmt: - - if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) -@@ -1999,6 +2278,11 @@ dcopuop: - - DITOREG(rv.l, MIPSInst_FD(ir)); - break; -+#ifdef CONFIG_MACH_LOONGSON -+ case ps_fmt: -+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); -+ break; -+#endif - default: - return SIGILL; - } -diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile -index 300591c..ed272e2 100644 ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -30,6 +30,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o - obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o - obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o - obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o -+obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o - obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3.o - obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o - obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o -diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c -new file mode 100644 -index 0000000..b296220 ---- /dev/null -+++ b/arch/mips/pci/fixup-gdium.c -@@ -0,0 +1,90 @@ -+/* -+ * Copyright (C) 2010 yajin -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+#include -+/* -+ * http://www.pcidatabase.com -+ * GDIUM has different PCI mapping -+ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI -+ * slog 14 (0x126f/0x0501) -> sm501 -+ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers -+ * plus Single EHCI controller -+ * slot 16 (0x10ec/0x8139) -> Realtek 8139c -+ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller -+ */ -+ -+#undef INT_IRQA -+#undef INT_IRQB -+#undef INT_IRQC -+#undef INT_IRQD -+#define INT_IRQA 36 -+#define INT_IRQB 37 -+#define INT_IRQC 38 -+#define INT_IRQD 39 -+ -+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ int irq = 0; -+ -+ switch (slot) { -+ case 13: -+ irq = INT_IRQC + ((pin - 1) & 3); -+ break; -+ case 14: -+ irq = INT_IRQA; -+ break; -+ case 15: -+#if CONFIG_GDIUM_VERSION > 2 -+ irq = INT_IRQB; -+#else -+ irq = INT_IRQA + ((pin - 1) & 3); -+#endif -+ break; -+ case 16: -+ irq = INT_IRQD; -+ break; -+#if CONFIG_GDIUM_VERSION > 2 -+ case 17: -+ irq = INT_IRQC; -+ break; -+#endif -+ default: -+ pr_info(" strange pci slot number %d on gdium.\n", slot); -+ break; -+ } -+ return irq; -+} -+ -+/* Do platform specific device initialization at pci_enable_device() time */ -+int pcibios_plat_dev_init(struct pci_dev *dev) -+{ -+ return 0; -+} -+ -+/* Fixups for the USB host controllers */ -+static void __init gdium_usb_host_fixup(struct pci_dev *dev) -+{ -+ unsigned int val; -+ pci_read_config_dword(dev, 0xe0, &val); -+#if CONFIG_GDIUM_VERSION > 2 -+ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3); -+#else -+ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5); -+ pci_write_config_dword(dev, 0xe4, 1<<5); -+#endif -+} -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, -+ gdium_usb_host_fixup); -+#if CONFIG_GDIUM_VERSION > 2 -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550, -+ gdium_usb_host_fixup); -+#endif -diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S -index 32a7c82..3a89502 100644 ---- a/arch/mips/power/hibernate.S -+++ b/arch/mips/power/hibernate.S -@@ -43,7 +43,9 @@ LEAF(swsusp_arch_resume) - bne t1, t3, 1b - PTR_L t0, PBE_NEXT(t0) - bnez t0, 0b -+#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit 771004298d broke Loongson2. */ - jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */ -+#endif - PTR_LA t0, saved_regs - PTR_L ra, PT_R31(t0) - PTR_L sp, PT_R29(t0) -diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c -index fc897ba..ac60f6b 100644 ---- a/drivers/cpufreq/loongson2_cpufreq.c -+++ b/drivers/cpufreq/loongson2_cpufreq.c -@@ -161,20 +161,32 @@ static int __init cpufreq_init(void) - /* Register platform stuff */ - ret = platform_driver_register(&platform_driver); - if (ret) -- return ret; -+ goto err_return; - - pr_info("cpufreq: Loongson-2F CPU frequency driver.\n"); - -- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, -- CPUFREQ_TRANSITION_NOTIFIER); -+ ret = cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, -+ CPUFREQ_TRANSITION_NOTIFIER); -+ if (ret) -+ goto err_platform_driver_unregister; - - ret = cpufreq_register_driver(&loongson2_cpufreq_driver); -+ if (ret) -+ goto err_cpufreq_unregister_notifier; - -- if (!ret && !nowait) { -+ if (!nowait) { - saved_cpu_wait = cpu_wait; - cpu_wait = loongson2_cpu_wait; - } - -+ return 0; -+ -+ err_cpufreq_unregister_notifier: -+ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block, -+ CPUFREQ_TRANSITION_NOTIFIER); -+ err_platform_driver_unregister: -+ platform_driver_unregister(&platform_driver); -+ err_return: - return ret; - } - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 152b006..767d8de 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -871,6 +871,13 @@ config HID_ZYDACRON - ---help--- - Support for Zydacron remote control. - -+config HID_GDIUM -+ bool "Gdium Fn keys support" if EMBEDDED -+ depends on USB_HID && DEXXON_GDIUM -+ default !EMBEDDED -+ ---help--- -+ Support for Functions keys available on Gdiums. -+ - config HID_SENSOR_HUB - tristate "HID Sensors framework support" - depends on HID && HAS_IOMEM -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 6f19958..2740ff0 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -99,6 +99,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o - wacom-objs := wacom_wac.o wacom_sys.o - obj-$(CONFIG_HID_WACOM) += wacom.o - obj-$(CONFIG_HID_WALTOP) += hid-waltop.o -+obj-$(CONFIG_HID_GDIUM) += hid-gdium.o - obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o - obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o - -diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c -new file mode 100644 -index 0000000..67cc095 ---- /dev/null -+++ b/drivers/hid/hid-gdium.c -@@ -0,0 +1,210 @@ -+/* -+ * hid-gdium -- Gdium laptop function keys -+ * -+ * Arnaud Patard -+ * -+ * Based on hid-apple.c -+ * -+ * 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. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+ -+#include "hid-ids.h" -+ -+#define GDIUM_FN_ON 1 -+ -+static int fnmode = GDIUM_FN_ON; -+module_param(fnmode, int, 0644); -+MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)"); -+ -+struct gdium_data { -+ unsigned int fn_on; -+}; -+ -+ -+struct gdium_key_translation { -+ u16 from; -+ u16 to; -+}; -+ -+static struct gdium_key_translation gdium_fn_keys[] = { -+ { KEY_F1, KEY_CAMERA }, -+ { KEY_F2, KEY_CONNECT }, -+ { KEY_F3, KEY_MUTE }, -+ { KEY_F4, KEY_VOLUMEUP}, -+ { KEY_F5, KEY_VOLUMEDOWN }, -+ { KEY_F6, KEY_SWITCHVIDEOMODE }, -+ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */ -+ { KEY_F8, KEY_BRIGHTNESSUP }, -+ { KEY_F9, KEY_BRIGHTNESSDOWN }, -+ { KEY_F10, KEY_SLEEP }, -+ { KEY_F11, KEY_PROG1 }, -+ { KEY_F12, KEY_PROG2 }, -+ { KEY_UP, KEY_PAGEUP }, -+ { KEY_DOWN, KEY_PAGEDOWN }, -+ { KEY_INSERT, KEY_NUMLOCK }, -+ { KEY_DELETE, KEY_SCROLLLOCK }, -+ { KEY_T, KEY_STOPCD }, -+ { KEY_F, KEY_PREVIOUSSONG }, -+ { KEY_H, KEY_NEXTSONG }, -+ { KEY_G, KEY_PLAYPAUSE }, -+ { } -+}; -+ -+static struct gdium_key_translation *gdium_find_translation( -+ struct gdium_key_translation *table, u16 from) -+{ -+ struct gdium_key_translation *trans; -+ -+ /* Look for the translation */ -+ for (trans = table; trans->from; trans++) -+ if (trans->from == from) -+ return trans; -+ return NULL; -+} -+ -+static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input, -+ struct hid_usage *usage, __s32 value) -+{ -+ struct gdium_data *data = hid_get_drvdata(hid); -+ struct gdium_key_translation *trans; -+ int do_translate; -+ -+ if (usage->type != EV_KEY) -+ return 0; -+ -+ if ((usage->code == KEY_FN)) { -+ data->fn_on = !!value; -+ input_event(input, usage->type, usage->code, value); -+ return 1; -+ } -+ -+ if (fnmode) { -+ trans = gdium_find_translation(gdium_fn_keys, usage->code); -+ if (trans) { -+ do_translate = data->fn_on; -+ if (do_translate) { -+ input_event(input, usage->type, trans->to, value); -+ return 1; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int gdium_input_event(struct hid_device *hdev, struct hid_field *field, -+ struct hid_usage *usage, __s32 value) -+{ -+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type) -+ return 0; -+ -+ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value)) -+ return 1; -+ -+ return 0; -+} -+ -+ -+static void gdium_input_setup(struct input_dev *input) -+{ -+ struct gdium_key_translation *trans; -+ -+ set_bit(KEY_NUMLOCK, input->keybit); -+ -+ /* Enable all needed keys */ -+ for (trans = gdium_fn_keys; trans->from; trans++) -+ set_bit(trans->to, input->keybit); -+} -+ -+static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi, -+ struct hid_field *field, struct hid_usage *usage, -+ unsigned long **bit, int *max) -+{ -+ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) -+ && ((usage->hid & HID_USAGE) == 0x82)) { -+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); -+ gdium_input_setup(hi->input); -+ return 1; -+ } -+ return 0; -+} -+ -+static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id) -+{ -+ struct gdium_data *data; -+ int ret; -+ -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) { -+ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n"); -+ return -ENOMEM; -+ } -+ -+ hid_set_drvdata(hdev, data); -+ -+ ret = hid_parse(hdev); -+ if (ret) { -+ dev_err(&hdev->dev, "parse failed\n"); -+ goto err_free; -+ } -+ -+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); -+ if (ret) { -+ dev_err(&hdev->dev, "hw start failed\n"); -+ goto err_free; -+ } -+ -+ return 0; -+err_free: -+ kfree(data); -+ return ret; -+} -+static void gdium_input_remove(struct hid_device *hdev) -+{ -+ hid_hw_stop(hdev); -+ kfree(hid_get_drvdata(hdev)); -+} -+ -+static const struct hid_device_id gdium_input_devices[] = { -+ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) }, -+ {} -+}; -+MODULE_DEVICE_TABLE(hid, gdium_input_devices); -+ -+static struct hid_driver gdium_input_driver = { -+ .name = "gdium-fnkeys", -+ .id_table = gdium_input_devices, -+ .probe = gdium_input_probe, -+ .remove = gdium_input_remove, -+ .event = gdium_input_event, -+ .input_mapping = gdium_input_mapping, -+}; -+ -+static int gdium_input_init(void) -+{ -+ int ret; -+ -+ ret = hid_register_driver(&gdium_input_driver); -+ if (ret) -+ pr_err("can't register gdium keyboard driver\n"); -+ -+ return ret; -+} -+static void gdium_input_exit(void) -+{ -+ hid_unregister_driver(&gdium_input_driver); -+} -+ -+module_init(gdium_input_init); -+module_exit(gdium_input_exit); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 9c47867..a3e1258 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -1021,6 +1021,9 @@ - #define USB_VENDOR_ID_ZYTRONIC 0x14c8 - #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 - -+#define USB_VENDOR_ID_GDIUM 0x04B4 -+#define USB_DEVICE_ID_GDIUM 0xe001 -+ - #define USB_VENDOR_ID_PRIMAX 0x0461 - #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 - -diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c -index 376f2dc..b576801 100644 ---- a/drivers/ide/ide-iops.c -+++ b/drivers/ide/ide-iops.c -@@ -27,6 +27,10 @@ - #include - #include - -+#ifdef CONFIG_LEMOTE_MACH2F -+#include -+#endif -+ - void SELECT_MASK(ide_drive_t *drive, int mask) - { - const struct ide_port_ops *port_ops = drive->hwif->port_ops; -@@ -300,6 +304,11 @@ void ide_check_nien_quirk_list(ide_drive_t *drive) - { - const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; - -+#ifdef CONFIG_LEMOTE_MACH2F -+ if (mips_machtype != MACH_LEMOTE_YL2F89) -+ return; -+#endif -+ - for (list = nien_quirk_list; *list != NULL; list++) - if (strstr(m, *list) != NULL) { - drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; -diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c -index 91077ef..2cfd9ff 100644 ---- a/drivers/mfd/sm501.c -+++ b/drivers/mfd/sm501.c -@@ -58,7 +58,7 @@ struct sm501_gpio { - struct sm501_gpio { - /* no gpio support, empty definition for sm501_devdata. */ - }; --#endif -+#endif /* CONFIG_MFD_SM501_GPIO */ - - struct sm501_devdata { - spinlock_t reg_lock; -@@ -1124,6 +1124,22 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) - { - return sm->gpio.registered; - } -+ -+void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned -+ char mode) -+{ -+ unsigned long set, reg, offset = gpio; -+ -+ if (offset >= 32) { -+ reg = SM501_GPIO63_32_CONTROL; -+ offset = gpio - 32; -+ } else -+ reg = SM501_GPIO31_0_CONTROL; -+ -+ set = mode ? 1 << offset : 0; -+ -+ sm501_modify_reg(dev, reg, set, 0); -+} - #else - static inline int sm501_register_gpio(struct sm501_devdata *sm) - { -@@ -1143,7 +1159,13 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) - { - return 0; - } --#endif -+ -+void sm501_configure_gpio(struct device *dev, unsigned int gpio, -+ unsigned char mode) -+{ -+} -+#endif /* CONFIG_MFD_SM501_GPIO */ -+EXPORT_SYMBOL_GPL(sm501_configure_gpio); - - static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, - struct sm501_platdata_gpio_i2c *iic) -@@ -1198,6 +1220,20 @@ static int sm501_register_gpio_i2c(struct sm501_devdata *sm, - return 0; - } - -+/* register sm501 PWM device */ -+static int sm501_register_pwm(struct sm501_devdata *sm) -+{ -+ struct platform_device *pdev; -+ -+ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0); -+ if (!pdev) -+ return -ENOMEM; -+ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC); -+ sm501_create_irq(sm, &pdev->resource[1]); -+ -+ return sm501_register_device(sm, pdev); -+} -+ - /* sm501_dbg_regs - * - * Debug attribute to attach to parent device to show core registers -@@ -1356,6 +1392,8 @@ static int sm501_init_dev(struct sm501_devdata *sm) - sm501_register_uart(sm, idata->devices); - if (idata->devices & SM501_USE_GPIO) - sm501_register_gpio(sm); -+ if (idata->devices & SM501_USE_PWM) -+ sm501_register_pwm(sm); - } - - if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { -@@ -1542,10 +1580,15 @@ static struct sm501_initdata sm501_pci_initdata = { - .devices = SM501_USE_ALL, - - /* Errata AB-3 says that 72MHz is the fastest available -- * for 33MHZ PCI with proper bus-mastering operation */ -- -+ * for 33MHZ PCI with proper bus-mastering operation -+ * For gdium, it works under 84&112M clock freq.*/ -+#ifdef CONFIG_DEXXON_GDIUM -+ .mclk = 84 * MHZ, -+ .m1xclk = 112 * MHZ, -+#else - .mclk = 72 * MHZ, - .m1xclk = 144 * MHZ, -+#endif - }; - - static struct sm501_platdata_fbsub sm501_pdata_fbsub = { -diff --git a/drivers/net/titan_ge.c b/drivers/net/titan_ge.c -new file mode 100644 -index 0000000..dc137bf8 ---- /dev/null -+++ b/drivers/net/titan_ge.c -@@ -0,0 +1,2069 @@ -+/* -+ * drivers/net/titan_ge.c - Driver for Titan ethernet ports -+ * -+ * Copyright (C) 2003 PMC-Sierra Inc. -+ * Author : Manish Lachwani (lachwani@pmc-sierra.com) -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+/* -+ * The MAC unit of the Titan consists of the following: -+ * -+ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO -+ * -> FIFO is where the incoming and outgoing data is placed -+ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes -+ * the data into the FIFO for Rx -+ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. -+ * -> AFX is the address filtering block -+ * -> GMII block to communicate with the PHY -+ * -+ * Rx will look like the following: -+ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory -+ * -+ * Tx will look like the following: -+ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII -+ * -+ * The Titan driver has support for the following performance features: -+ * -> Rx side checksumming -+ * -> Jumbo Frames -+ * -> Interrupt Coalscing -+ * -> Rx NAPI -+ * -> SKB Recycling -+ * -> Transmit/Receive descriptors in SRAM -+ * -> Fast routing for IP forwarding -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* For MII specifc registers, titan_mdio.h should be included */ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "titan_ge.h" -+#include "titan_mdio.h" -+ -+/* Static Function Declarations */ -+static int titan_ge_eth_open(struct net_device *); -+static void titan_ge_eth_stop(struct net_device *); -+static struct net_device_stats *titan_ge_get_stats(struct net_device *); -+static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int, -+ unsigned long, unsigned long, -+ unsigned long); -+static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int, -+ unsigned long, unsigned long); -+ -+static int titan_ge_open(struct net_device *); -+static int titan_ge_start_xmit(struct sk_buff *, struct net_device *); -+static int titan_ge_stop(struct net_device *); -+ -+static unsigned long titan_ge_tx_coal(unsigned long, int); -+ -+static void titan_ge_port_reset(unsigned int); -+static int titan_ge_free_tx_queue(titan_ge_port_info *); -+static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *); -+static int titan_ge_port_start(struct net_device *, titan_ge_port_info *); -+ -+static int titan_ge_return_tx_desc(titan_ge_port_info *, int); -+ -+/* -+ * Some configuration for the FIFO and the XDMA channel needs -+ * to be done only once for all the ports. This flag controls -+ * that -+ */ -+static unsigned long config_done; -+ -+/* -+ * One time out of memory flag -+ */ -+static unsigned int oom_flag; -+ -+static int titan_ge_poll(struct net_device *netdev, int *budget); -+ -+static int titan_ge_receive_queue(struct net_device *, unsigned int); -+ -+static struct platform_device *titan_ge_device[3]; -+ -+/* MAC Address */ -+extern unsigned char titan_ge_mac_addr_base[6]; -+ -+unsigned long titan_ge_base; -+static unsigned long titan_ge_sram; -+ -+static char titan_string[] = "titan"; -+ -+/* -+ * The Titan GE has two alignment requirements: -+ * -> skb->data to be cacheline aligned (32 byte) -+ * -> IP header alignment to 16 bytes -+ * -+ * The latter is not implemented. So, that results in an extra copy on -+ * the Rx. This is a big performance hog. For the former case, the -+ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size -+ * requested is calculated: -+ * -+ * Ethernet Frame Size : 1518 -+ * Ethernet Header : 14 -+ * Future Titan change for IP header alignment : 2 -+ * -+ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header -+ * alignment, we use skb_reserve(). -+ */ -+ -+#define ALIGNED_RX_SKB_ADDR(addr) \ -+ ((((unsigned long)(addr) + (64UL - 1UL)) \ -+ & ~(64UL - 1UL)) - (unsigned long)(addr)) -+ -+#define titan_ge_alloc_skb(__length, __gfp_flags) \ -+({ struct sk_buff *__skb; \ -+ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \ -+ if(__skb) { \ -+ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \ -+ if(__offset) \ -+ skb_reserve(__skb, __offset); \ -+ } \ -+ __skb; \ -+}) -+ -+/* -+ * Configure the GMII block of the Titan based on what the PHY tells us -+ */ -+static void titan_ge_gmii_config(int port_num) -+{ -+ unsigned int reg_data = 0, phy_reg; -+ int err; -+ -+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); -+ -+ if (err == TITAN_GE_MDIO_ERROR) { -+ printk(KERN_ERR -+ "Could not read PHY control register 0x11 \n"); -+ printk(KERN_ERR -+ "Setting speed to 1000 Mbps and Duplex to Full \n"); -+ -+ return; -+ } -+ -+ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0); -+ -+ if (phy_reg & 0x8000) { -+ if (phy_reg & 0x2000) { -+ /* Full Duplex and 1000 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x201); -+ } else { -+ /* Half Duplex and 1000 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x2201); -+ } -+ } -+ if (phy_reg & 0x4000) { -+ if (phy_reg & 0x2000) { -+ /* Full Duplex and 100 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x100); -+ } else { -+ /* Half Duplex and 100 Mbps */ -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + -+ (port_num << 12)), 0x2100); -+ } -+ } -+ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL + -+ (port_num << 12)); -+ reg_data |= 0x3; -+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL + -+ (port_num << 12)), reg_data); -+} -+ -+/* -+ * Enable the TMAC if it is not -+ */ -+static void titan_ge_enable_tx(unsigned int port_num) -+{ -+ unsigned long reg_data; -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); -+ if (!(reg_data & 0x8000)) { -+ printk("TMAC disabled for port %d!! \n", port_num); -+ -+ reg_data |= 0x0001; /* Enable TMAC */ -+ reg_data |= 0x4000; /* CRC Check Enable */ -+ reg_data |= 0x2000; /* Padding enable */ -+ reg_data |= 0x0800; /* CRC Add enable */ -+ reg_data |= 0x0080; /* PAUSE frame */ -+ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ } -+} -+ -+/* -+ * Tx Timeout function -+ */ -+static void titan_ge_tx_timeout(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ printk(KERN_INFO "%s: TX timeout ", netdev->name); -+ printk(KERN_INFO "Resetting card \n"); -+ -+ /* Do the reset outside of interrupt context */ -+ schedule_work(&titan_ge_eth->tx_timeout_task); -+} -+ -+/* -+ * Update the AFX tables for UC and MC for slice 0 only -+ */ -+static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth) -+{ -+ int port = titan_ge_eth->port_num; -+ unsigned int i; -+ volatile unsigned long reg_data = 0; -+ u8 p_addr[6]; -+ -+ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6); -+ -+ /* Set the MAC address here for TMAC and RMAC */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1); -+ /* Configure the eight address filters */ -+ for (i = 0; i < 8; i++) { -+ /* Select each of the eight filters */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 + -+ (port << 12)), i); -+ -+ /* Configure the match */ -+ reg_data = 0x9; /* Forward Enable Bit */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 + -+ (port << 12)), reg_data); -+ -+ /* Finally, AFX Exact Match Address Registers */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ -+ /* VLAN id set to 0 */ -+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + -+ (port << 12)), 0); -+ } -+} -+ -+/* -+ * Actual Routine to reset the adapter when the timeout occurred -+ */ -+static void titan_ge_tx_timeout_task(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ int port = titan_ge_eth->port_num; -+ -+ printk("Titan GE: Transmit timed out. Resetting ... \n"); -+ -+ /* Dump debug info */ -+ printk(KERN_ERR "TRTG cause : %x \n", -+ TITAN_GE_READ(0x100c + (port << 12))); -+ -+ /* Fix this for the other ports */ -+ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c)); -+ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040)); -+ printk(KERN_ERR "XDMA GDI ERROR : %x \n", -+ TITAN_GE_READ(0x5008 + (port << 8))); -+ printk(KERN_ERR "CHANNEL ERROR: %x \n", -+ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT -+ + (port << 8))); -+ -+ netif_device_detach(netdev); -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ titan_ge_port_start(netdev, titan_ge_eth); -+ netif_device_attach(netdev); -+} -+ -+/* -+ * Change the MTU of the Ethernet Device -+ */ -+static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned long flags; -+ -+ if ((new_mtu > 9500) || (new_mtu < 64)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ netdev->mtu = new_mtu; -+ -+ /* Now we have to reopen the interface so that SKBs with the new -+ * size will be allocated */ -+ -+ if (netif_running(netdev)) { -+ titan_ge_eth_stop(netdev); -+ -+ if (titan_ge_eth_open(netdev) != TITAN_OK) { -+ printk(KERN_ERR -+ "%s: Fatal error on opening device\n", -+ netdev->name); -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ return -1; -+ } -+ } -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ return 0; -+} -+ -+/* -+ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line -+ * only. Once an interrupt is triggered, figure out the port and then check -+ * the channel. -+ */ -+static irqreturn_t titan_ge_int_handler(int irq, void *dev_id) -+{ -+ struct net_device *netdev = (struct net_device *) dev_id; -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int reg_data; -+ unsigned int eth_int_cause_error = 0, is; -+ unsigned long eth_int_cause1; -+ int err = 0; -+#ifdef CONFIG_SMP -+ unsigned long eth_int_cause2; -+#endif -+ -+ /* Ack the CPU interrupt */ -+ switch (port_num) { -+ case 0: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is); -+#endif -+ break; -+ -+ case 1: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is); -+#endif -+ break; -+ -+ case 2: -+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4); -+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is); -+ -+#ifdef CONFIG_SMP -+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4); -+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is); -+#endif -+ } -+ -+ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); -+#ifdef CONFIG_SMP -+ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B); -+#endif -+ -+ /* Spurious interrupt */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) { -+#else -+ if (eth_int_cause1 == 0) { -+#endif -+ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT + -+ (port_num << 8)); -+ -+ if (eth_int_cause_error == 0) -+ return IRQ_NONE; -+ } -+ -+ /* Handle Tx first. No need to ack interrupts */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 & 0x20202) || -+ (eth_int_cause2 & 0x20202) ) -+#else -+ if (eth_int_cause1 & 0x20202) -+#endif -+ titan_ge_free_tx_queue(titan_ge_eth); -+ -+ /* Handle the Rx next */ -+#ifdef CONFIG_SMP -+ if ( (eth_int_cause1 & 0x10101) || -+ (eth_int_cause2 & 0x10101)) { -+#else -+ if (eth_int_cause1 & 0x10101) { -+#endif -+ if (netif_rx_schedule_prep(netdev)) { -+ unsigned int ack; -+ -+ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ /* Disable Tx and Rx both */ -+ if (port_num == 0) -+ ack &= ~(0x3); -+ if (port_num == 1) -+ ack &= ~(0x300); -+ -+ if (port_num == 2) -+ ack &= ~(0x30000); -+ -+ /* Interrupts have been disabled */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack); -+ -+ __netif_rx_schedule(netdev); -+ } -+ } -+ -+ /* Handle error interrupts */ -+ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) { -+ printk(KERN_ERR -+ "XDMA Channel Error : %x on port %d\n", -+ eth_int_cause_error, port_num); -+ -+ printk(KERN_ERR -+ "XDMA GDI Hardware error : %x on port %d\n", -+ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num); -+ -+ printk(KERN_ERR -+ "XDMA currently has %d Rx descriptors \n", -+ TITAN_GE_READ(0x5048 + (port_num << 8))); -+ -+ printk(KERN_ERR -+ "XDMA currently has prefetcted %d Rx descriptors \n", -+ TITAN_GE_READ(0x505c + (port_num << 8))); -+ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + -+ (port_num << 8)), eth_int_cause_error); -+ } -+ -+ /* -+ * PHY interrupt to inform abt the changes. Reading the -+ * PHY Status register will clear the interrupt -+ */ -+ if ((!(eth_int_cause1 & 0x30303)) && -+ (eth_int_cause_error == 0)) { -+ err = -+ titan_ge_mdio_read(port_num, -+ TITAN_GE_MDIO_PHY_IS, ®_data); -+ -+ if (reg_data & 0x0400) { -+ /* Link status change */ -+ titan_ge_mdio_read(port_num, -+ TITAN_GE_MDIO_PHY_STATUS, ®_data); -+ if (!(reg_data & 0x0400)) { -+ /* Link is down */ -+ netif_carrier_off(netdev); -+ netif_stop_queue(netdev); -+ } else { -+ /* Link is up */ -+ netif_carrier_on(netdev); -+ netif_wake_queue(netdev); -+ -+ /* Enable the queue */ -+ titan_ge_enable_tx(port_num); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Multicast and Promiscuous mode set. The -+ * set_multi entry point is called whenever the -+ * multicast address list or the network interface -+ * flags are updated. -+ */ -+static void titan_ge_set_multi(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned long reg_data; -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + -+ (port_num << 12)); -+ -+ if (netdev->flags & IFF_PROMISC) { -+ reg_data |= 0x2; -+ } -+ else if (netdev->flags & IFF_ALLMULTI) { -+ reg_data |= 0x01; -+ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */ -+ } -+ else { -+ reg_data = 0x2; -+ } -+ -+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + -+ (port_num << 12)), reg_data); -+ if (reg_data & 0x01) { -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI + -+ (port_num << 12)), 0xffff); -+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI + -+ (port_num << 12)), 0xffff); -+ } -+} -+ -+/* -+ * Open the network device -+ */ -+static int titan_ge_open(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num; -+ int retval; -+ -+ retval = request_irq(irq, titan_ge_int_handler, -+ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev); -+ -+ if (retval != 0) { -+ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n"); -+ return -1; -+ } -+ -+ netdev->irq = irq; -+ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num); -+ -+ spin_lock_irq(&(titan_ge_eth->lock)); -+ -+ if (titan_ge_eth_open(netdev) != TITAN_OK) { -+ spin_unlock_irq(&(titan_ge_eth->lock)); -+ printk("%s: Error opening interface \n", netdev->name); -+ free_irq(netdev->irq, netdev); -+ return -EBUSY; -+ } -+ -+ spin_unlock_irq(&(titan_ge_eth->lock)); -+ -+ return 0; -+} -+ -+/* -+ * Allocate the SKBs for the Rx ring. Also used -+ * for refilling the queue -+ */ -+static int titan_ge_rx_task(struct net_device *netdev, -+ titan_ge_port_info *titan_ge_port) -+{ -+ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev; -+ volatile titan_ge_rx_desc *rx_desc; -+ struct sk_buff *skb; -+ int rx_used_desc; -+ int count = 0; -+ -+ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) { -+ -+ /* First try to get the skb from the recycler */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC); -+#else -+ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC); -+#endif -+ if (unlikely(!skb)) { -+ /* OOM, set the flag */ -+ printk("OOM \n"); -+ oom_flag = 1; -+ break; -+ } -+ count++; -+ skb->dev = netdev; -+ -+ titan_ge_port->rx_ring_skbs++; -+ -+ rx_used_desc = titan_ge_port->rx_used_desc_q; -+ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]); -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ rx_desc->buffer_addr = dma_map_single(device, skb->data, -+ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE); -+#else -+ rx_desc->buffer_addr = dma_map_single(device, skb->data, -+ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE); -+#endif -+ -+ titan_ge_port->rx_skb[rx_used_desc] = skb; -+ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED; -+ -+ titan_ge_port->rx_used_desc_q = -+ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE; -+ } -+ -+ return count; -+} -+ -+/* -+ * Actual init of the Tital GE port. There is one register for -+ * the channel configuration -+ */ -+static void titan_port_init(struct net_device *netdev, -+ titan_ge_port_info * titan_ge_eth) -+{ -+ unsigned long reg_data; -+ -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ -+ /* First reset the TMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data |= 0x80000000; -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ udelay(30); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data &= ~(0xc0000000); -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ /* Now reset the RMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data |= 0x00080000; -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+ -+ udelay(30); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); -+ reg_data &= ~(0x000c0000); -+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); -+} -+ -+/* -+ * Start the port. All the hardware specific configuration -+ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX -+ * go here -+ */ -+static int titan_ge_port_start(struct net_device *netdev, -+ titan_ge_port_info * titan_port) -+{ -+ volatile unsigned long reg_data, reg_data1; -+ int port_num = titan_port->port_num; -+ int count = 0; -+ unsigned long reg_data_1; -+ -+ if (config_done == 0) { -+ reg_data = TITAN_GE_READ(0x0004); -+ reg_data |= 0x100; -+ TITAN_GE_WRITE(0x0004, reg_data); -+ -+ reg_data &= ~(0x100); -+ TITAN_GE_WRITE(0x0004, reg_data); -+ -+ /* Turn on GMII/MII mode and turn off TBI mode */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1); -+ reg_data |= 0x00000700; -+ reg_data &= ~(0x00800000); /* Fencing */ -+ -+ TITAN_GE_WRITE(0x000c, 0x00001100); -+ -+ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data); -+ -+ /* Set the CPU Resource Limit register */ -+ TITAN_GE_WRITE(0x00f8, 0x8); -+ -+ /* Be conservative when using the BIU buffers */ -+ TITAN_GE_WRITE(0x0068, 0x4); -+ } -+ -+ titan_port->tx_threshold = 0; -+ titan_port->rx_threshold = 0; -+ -+ /* We need to write the descriptors for Tx and Rx */ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)), -+ (unsigned long) titan_port->tx_dma); -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)), -+ (unsigned long) titan_port->rx_dma); -+ -+ if (config_done == 0) { -+ /* Step 1: XDMA config */ -+ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG); -+ reg_data &= ~(0x80000000); /* clear reset */ -+ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */ -+ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */ -+ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */ -+ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */ -+ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data); -+ } -+ -+ /* IR register for the XDMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)); -+ reg_data |= 0x80068000; /* No Rx_OOD */ -+ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data); -+ -+ /* Start the Tx and Rx XDMA controller */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)); -+ reg_data &= 0x4fffffff; /* Clear tx reset */ -+ reg_data &= 0xfff4ffff; /* Clear rx reset */ -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ reg_data |= 0xa0 | 0x30030000; -+#else -+ reg_data |= 0x40 | 0x20030000; -+#endif -+ -+#ifndef CONFIG_SMP -+ reg_data &= ~(0x10); -+ reg_data |= 0x0f; /* All of the packet */ -+#endif -+ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data); -+ -+ /* Rx desc count */ -+ count = titan_ge_rx_task(netdev, titan_port); -+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count); -+ count = TITAN_GE_READ(0x5048 + (port_num << 8)); -+ -+ udelay(30); -+ -+ /* -+ * Step 2: Configure the SDQPF, i.e. FIFO -+ */ -+ if (config_done == 0) { -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); -+ reg_data = 0x1; -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ reg_data &= ~(0x1); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); -+ reg_data = 0x1; -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ reg_data &= ~(0x1); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); -+ } -+ /* -+ * Enable RX FIFO 0, 4 and 8 -+ */ -+ if (port_num == 0) { -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10); -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4844); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x4844, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); -+ -+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ reg_data |= (0xff << 10); -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4944); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x4944, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); -+ -+ } -+ -+ if (port_num == 1) { -+ reg_data = TITAN_GE_READ(0x4870); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (0xff + 1); -+ -+ TITAN_GE_WRITE(0x4870, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4874); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x4874, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4870, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x494c); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x494c, reg_data); -+ reg_data |= (0xff << 10) | (0xff + 1); -+ TITAN_GE_WRITE(0x494c, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x4950); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x4950, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x494c, reg_data); -+ } -+ -+ /* -+ * Titan 1.2 revision does support port #2 -+ */ -+ if (port_num == 2) { -+ /* -+ * Put the descriptors in the SRAM -+ */ -+ reg_data = TITAN_GE_READ(0x48a0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x48a4); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x48a4, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x4958); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ TITAN_GE_WRITE(0x4958, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x495c); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x495c, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ } -+ -+ if (port_num == 2) { -+ reg_data = TITAN_GE_READ(0x48a0); -+ -+ reg_data |= 0x100000; -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ /* -+ * BAV2,BAV and DAV settings for the Rx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x48a4); -+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); -+ TITAN_GE_WRITE(0x48a4, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x48a0, reg_data); -+ -+ reg_data = TITAN_GE_READ(0x4958); -+ reg_data |= 0x100000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ reg_data |= (0xff << 10) | (2*(0xff + 1)); -+ TITAN_GE_WRITE(0x4958, reg_data); -+ -+ /* -+ * BAV2, BAV and DAV settings for the Tx FIFO -+ */ -+ reg_data1 = TITAN_GE_READ(0x495c); -+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); -+ -+ TITAN_GE_WRITE(0x495c, reg_data1); -+ -+ reg_data &= ~(0x00100000); -+ reg_data |= 0x200000; -+ -+ TITAN_GE_WRITE(0x4958, reg_data); -+ } -+ -+ /* -+ * Step 3: TRTG block enable -+ */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12)); -+ -+ /* -+ * This is the 1.2 revision of the chip. It has fix for the -+ * IP header alignment. Now, the IP header begins at an -+ * aligned address and this wont need an extra copy in the -+ * driver. This performance drawback existed in the previous -+ * versions of the silicon -+ */ -+ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12)); -+ reg_data_1 |= 0x40000000; -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ reg_data_1 |= 0x04000000; -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ mdelay(5); -+ -+ reg_data_1 &= ~(0x04000000); -+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); -+ -+ mdelay(5); -+ -+ reg_data |= 0x0001; -+ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data); -+ -+ /* -+ * Step 4: Start the Tx activity -+ */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197); -+#ifdef TITAN_GE_JUMBO_FRAMES -+ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000); -+#endif -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); -+ reg_data |= 0x0001; /* Enable TMAC */ -+ reg_data |= 0x6c70; /* PAUSE also set */ -+ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ udelay(30); -+ -+ /* Destination Address drop bit */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)); -+ reg_data |= 0x218; /* DA_DROP bit and pause */ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data); -+ -+ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3); -+ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000); -+#endif -+ /* Start the Rx activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); -+ reg_data |= 0x0001; /* RMAC Enable */ -+ reg_data |= 0x0010; /* CRC Check enable */ -+ reg_data |= 0x0040; /* Min Frame check enable */ -+ reg_data |= 0x4400; /* Max Frame check enable */ -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ udelay(30); -+ -+ /* -+ * Enable the Interrupts for Tx and Rx -+ */ -+ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ -+ if (port_num == 0) { -+ reg_data1 |= 0x3; -+#ifdef CONFIG_SMP -+ TITAN_GE_WRITE(0x0038, 0x003); -+#else -+ TITAN_GE_WRITE(0x0038, 0x303); -+#endif -+ } -+ -+ if (port_num == 1) { -+ reg_data1 |= 0x300; -+ } -+ -+ if (port_num == 2) -+ reg_data1 |= 0x30000; -+ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1); -+ TITAN_GE_WRITE(0x003c, 0x300); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */ -+ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */ -+ } -+ -+ /* Priority */ -+ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12)); -+ reg_data &= ~(0x00f00000); -+ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data); -+ -+ /* Step 5: GMII config */ -+ titan_ge_gmii_config(port_num); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(0x1a80, 0); -+ config_done = 1; -+ } -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Function to queue the packet for the Ethernet device -+ */ -+static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth, -+ struct sk_buff * skb) -+{ -+ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev; -+ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q; -+ volatile titan_ge_tx_desc *tx_curr; -+ int port_num = titan_ge_eth->port_num; -+ -+ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]); -+ tx_curr->buffer_addr = -+ dma_map_single(device, skb->data, skb_headlen(skb), -+ DMA_TO_DEVICE); -+ -+ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb; -+ tx_curr->buffer_len = skb_headlen(skb); -+ -+ /* Last descriptor enables interrupt and changes ownership */ -+ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5); -+ -+ /* Kick the XDMA to start the transfer from memory to the FIFO */ -+ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1); -+ -+ /* Current descriptor updated */ -+ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE; -+ -+ /* Prefetch the next descriptor */ -+ prefetch((const void *) -+ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]); -+} -+ -+/* -+ * Actually does the open of the Ethernet device -+ */ -+static int titan_ge_eth_open(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ struct device *device = &titan_ge_device[port_num]->dev; -+ unsigned long reg_data; -+ unsigned int phy_reg; -+ int err = 0; -+ -+ /* Stop the Rx activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); -+ -+ /* Clear the port interrupts */ -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0); -+ -+ if (config_done == 0) { -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0); -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0); -+ } -+ -+ /* Set the MAC Address */ -+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); -+ -+ if (config_done == 0) -+ titan_port_init(netdev, titan_ge_eth); -+ -+ titan_ge_update_afx(titan_ge_eth); -+ -+ /* Allocate the Tx ring now */ -+ titan_ge_eth->tx_ring_skbs = 0; -+ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE; -+ -+ /* Allocate space in the SRAM for the descriptors */ -+ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *) -+ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num); -+ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num; -+ -+ if (!titan_ge_eth->tx_desc_area) { -+ printk(KERN_ERR -+ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n", -+ netdev->name, TITAN_TX_RING_BYTES, port_num); -+ return -ENOMEM; -+ } -+ -+ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size); -+ -+ /* Now initialize the Tx descriptor ring */ -+ titan_ge_init_tx_desc_ring(titan_ge_eth, -+ titan_ge_eth->tx_ring_size, -+ (unsigned long) titan_ge_eth->tx_desc_area, -+ (unsigned long) titan_ge_eth->tx_dma); -+ -+ /* Allocate the Rx ring now */ -+ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE; -+ titan_ge_eth->rx_ring_skbs = 0; -+ -+ titan_ge_eth->rx_desc_area = -+ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num); -+ -+ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num; -+ -+ if (!titan_ge_eth->rx_desc_area) { -+ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", -+ netdev->name, TITAN_RX_RING_BYTES); -+ -+ printk(KERN_ERR "%s: Freeing previously allocated TX queues...", -+ netdev->name); -+ -+ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size, -+ (void *) titan_ge_eth->tx_desc_area, -+ titan_ge_eth->tx_dma); -+ -+ return -ENOMEM; -+ } -+ -+ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size); -+ -+ /* Now initialize the Rx ring */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+ if ((titan_ge_init_rx_desc_ring -+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE, -+ (unsigned long) titan_ge_eth->rx_desc_area, 0, -+ (unsigned long) titan_ge_eth->rx_dma)) == 0) -+#else -+ if ((titan_ge_init_rx_desc_ring -+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE, -+ (unsigned long) titan_ge_eth->rx_desc_area, 0, -+ (unsigned long) titan_ge_eth->rx_dma)) == 0) -+#endif -+ panic("%s: Error initializing RX Ring\n", netdev->name); -+ -+ /* Fill the Rx ring with the SKBs */ -+ titan_ge_port_start(netdev, titan_ge_eth); -+ -+ /* -+ * Check if Interrupt Coalscing needs to be turned on. The -+ * values specified in the register is multiplied by -+ * (8 x 64 nanoseconds) to determine when an interrupt should -+ * be sent to the CPU. -+ */ -+ -+ if (TITAN_GE_TX_COAL) { -+ titan_ge_eth->tx_int_coal = -+ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num); -+ } -+ -+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); -+ if (err == TITAN_GE_MDIO_ERROR) { -+ printk(KERN_ERR -+ "Could not read PHY control register 0x11 \n"); -+ return TITAN_ERROR; -+ } -+ if (!(phy_reg & 0x0400)) { -+ netif_carrier_off(netdev); -+ netif_stop_queue(netdev); -+ return TITAN_ERROR; -+ } else { -+ netif_carrier_on(netdev); -+ netif_start_queue(netdev); -+ } -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Queue the packet for Tx. Currently no support for zero copy, -+ * checksum offload and Scatter Gather. The chip does support -+ * Scatter Gather only. But, that wont help here since zero copy -+ * requires support for Tx checksumming also. -+ */ -+int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned long flags; -+ struct net_device_stats *stats; -+//printk("titan_ge_start_xmit\n"); -+ -+ stats = &titan_ge_eth->stats; -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <= -+ (skb_shinfo(skb)->nr_frags + 1)) { -+ netif_stop_queue(netdev); -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ printk(KERN_ERR "Tx OOD \n"); -+ return 1; -+ } -+ -+ titan_ge_tx_queue(titan_ge_eth, skb); -+ titan_ge_eth->tx_ring_skbs++; -+ -+ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) { -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ titan_ge_free_tx_queue(titan_ge_eth); -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ } -+ -+ stats->tx_bytes += skb->len; -+ stats->tx_packets++; -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ netdev->trans_start = jiffies; -+ -+ return 0; -+} -+ -+/* -+ * Actually does the Rx. Rx side checksumming supported. -+ */ -+static int titan_ge_rx(struct net_device *netdev, int port_num, -+ titan_ge_port_info * titan_ge_port, -+ titan_ge_packet * packet) -+{ -+ int rx_curr_desc, rx_used_desc; -+ volatile titan_ge_rx_desc *rx_desc; -+ -+ rx_curr_desc = titan_ge_port->rx_curr_desc_q; -+ rx_used_desc = titan_ge_port->rx_used_desc_q; -+ -+ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) -+ return TITAN_ERROR; -+ -+ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]); -+ -+ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) -+ return TITAN_ERROR; -+ -+ packet->skb = titan_ge_port->rx_skb[rx_curr_desc]; -+ packet->len = (rx_desc->cmd_sts & 0x7fff); -+ -+ /* -+ * At this point, we dont know if the checksumming -+ * actually helps relieve CPU. So, keep it for -+ * port 0 only -+ */ -+ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16); -+ packet->cmd_sts = rx_desc->cmd_sts; -+ -+ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE; -+ -+ /* Prefetch the next descriptor */ -+ prefetch((const void *) -+ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Free the Tx queue of the used SKBs -+ */ -+static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth) -+{ -+ unsigned long flags; -+ -+ /* Take the lock */ -+ spin_lock_irqsave(&(titan_ge_eth->lock), flags); -+ -+ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) -+ if (titan_ge_eth->tx_ring_skbs != 1) -+ titan_ge_eth->tx_ring_skbs--; -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Threshold beyond which we do the cleaning of -+ * Tx queue and new allocation for the Rx -+ * queue -+ */ -+#define TX_THRESHOLD 4 -+#define RX_THRESHOLD 10 -+ -+/* -+ * Receive the packets and send it to the kernel. -+ */ -+static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ titan_ge_packet packet; -+ struct net_device_stats *stats; -+ struct sk_buff *skb; -+ unsigned long received_packets = 0; -+ unsigned int ack; -+ -+ stats = &titan_ge_eth->stats; -+ -+ while ((--max) -+ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) { -+ skb = (struct sk_buff *) packet.skb; -+ -+ titan_ge_eth->rx_ring_skbs--; -+ -+ if (--titan_ge_eth->rx_work_limit < 0) -+ break; -+ received_packets++; -+ -+ stats->rx_packets++; -+ stats->rx_bytes += packet.len; -+ -+ if ((packet.cmd_sts & TITAN_GE_RX_PERR) || -+ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) || -+ (packet.cmd_sts & TITAN_GE_RX_TRUNC) || -+ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) { -+ stats->rx_dropped++; -+ dev_kfree_skb_any(skb); -+ -+ continue; -+ } -+ /* -+ * Either support fast path or slow path. Decision -+ * making can really slow down the performance. The -+ * idea is to cut down the number of checks and improve -+ * the fastpath. -+ */ -+ -+ skb_put(skb, packet.len - 2); -+ -+ /* -+ * Increment data pointer by two since thats where -+ * the MAC starts -+ */ -+ skb_reserve(skb, 2); -+ skb->protocol = eth_type_trans(skb, netdev); -+ netif_receive_skb(skb); -+ -+ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) { -+ ack = titan_ge_rx_task(netdev, titan_ge_eth); -+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack); -+ titan_ge_eth->rx_threshold = 0; -+ } else -+ titan_ge_eth->rx_threshold++; -+ -+ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) { -+ titan_ge_eth->tx_threshold = 0; -+ titan_ge_free_tx_queue(titan_ge_eth); -+ } -+ else -+ titan_ge_eth->tx_threshold++; -+ -+ } -+ return received_packets; -+} -+ -+ -+/* -+ * Enable the Rx side interrupts -+ */ -+static void titan_ge_enable_int(unsigned int port_num, -+ titan_ge_port_info *titan_ge_eth, -+ struct net_device *netdev) -+{ -+ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); -+ -+ if (port_num == 0) -+ reg_data |= 0x3; -+ if (port_num == 1) -+ reg_data |= 0x300; -+ if (port_num == 2) -+ reg_data |= 0x30000; -+ -+ /* Re-enable interrupts */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data); -+} -+ -+/* -+ * Main function to handle the polling for Rx side NAPI. -+ * Receive interrupts have been disabled at this point. -+ * The poll schedules the transmit followed by receive. -+ */ -+static int titan_ge_poll(struct net_device *netdev, int *budget) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ int port_num = titan_ge_eth->port_num; -+ int work_done = 0; -+ unsigned long flags, status; -+ -+ titan_ge_eth->rx_work_limit = *budget; -+ if (titan_ge_eth->rx_work_limit > netdev->quota) -+ titan_ge_eth->rx_work_limit = netdev->quota; -+ -+ do { -+ /* Do the transmit cleaning work here */ -+ titan_ge_free_tx_queue(titan_ge_eth); -+ -+ /* Ack the Rx interrupts */ -+ if (port_num == 0) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3); -+ if (port_num == 1) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300); -+ if (port_num == 2) -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000); -+ -+ work_done += titan_ge_receive_queue(netdev, 0); -+ -+ /* Out of quota and there is work to be done */ -+ if (titan_ge_eth->rx_work_limit < 0) -+ goto not_done; -+ -+ /* Receive alloc_skb could lead to OOM */ -+ if (oom_flag == 1) { -+ oom_flag = 0; -+ goto oom; -+ } -+ -+ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); -+ } while (status & 0x30300); -+ -+ /* If we are here, then no more interrupts to process */ -+ goto done; -+ -+not_done: -+ *budget -= work_done; -+ netdev->quota -= work_done; -+ return 1; -+ -+oom: -+ printk(KERN_ERR "OOM \n"); -+ netif_rx_complete(netdev); -+ return 0; -+ -+done: -+ /* -+ * No more packets on the poll list. Turn the interrupts -+ * back on and we should be able to catch the new -+ * packets in the interrupt handler -+ */ -+ if (!work_done) -+ work_done = 1; -+ -+ *budget -= work_done; -+ netdev->quota -= work_done; -+ -+ spin_lock_irqsave(&titan_ge_eth->lock, flags); -+ -+ /* Remove us from the poll list */ -+ netif_rx_complete(netdev); -+ -+ /* Re-enable interrupts */ -+ titan_ge_enable_int(port_num, titan_ge_eth, netdev); -+ -+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); -+ -+ return 0; -+} -+ -+/* -+ * Close the network device -+ */ -+int titan_ge_stop(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ spin_lock_irq(&(titan_ge_eth->lock)); -+ titan_ge_eth_stop(netdev); -+ free_irq(netdev->irq, netdev); -+ spin_unlock_irq(&titan_ge_eth->lock); -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Free the Tx ring -+ */ -+static void titan_ge_free_tx_rings(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int curr; -+ unsigned long reg_data; -+ -+ /* Stop the Tx DMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)); -+ reg_data |= 0xc0000000; -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)), reg_data); -+ -+ /* Disable the TMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ for (curr = 0; -+ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE); -+ curr++) { -+ if (titan_ge_eth->tx_skb[curr]) { -+ dev_kfree_skb(titan_ge_eth->tx_skb[curr]); -+ titan_ge_eth->tx_ring_skbs--; -+ } -+ } -+ -+ if (titan_ge_eth->tx_ring_skbs != 0) -+ printk -+ ("%s: Error on Tx descriptor free - could not free %d" -+ " descriptors\n", netdev->name, -+ titan_ge_eth->tx_ring_skbs); -+ -+#ifndef TITAN_RX_RING_IN_SRAM -+ dma_free_coherent(&titan_ge_device[port_num]->dev, -+ titan_ge_eth->tx_desc_area_size, -+ (void *) titan_ge_eth->tx_desc_area, -+ titan_ge_eth->tx_dma); -+#endif -+} -+ -+/* -+ * Free the Rx ring -+ */ -+static void titan_ge_free_rx_rings(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ unsigned int curr; -+ unsigned long reg_data; -+ -+ /* Stop the Rx DMA */ -+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)); -+ reg_data |= 0x000c0000; -+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + -+ (port_num << 8)), reg_data); -+ -+ /* Disable the RMAC */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x00000001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ for (curr = 0; -+ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE); -+ curr++) { -+ if (titan_ge_eth->rx_skb[curr]) { -+ dev_kfree_skb(titan_ge_eth->rx_skb[curr]); -+ titan_ge_eth->rx_ring_skbs--; -+ } -+ } -+ -+ if (titan_ge_eth->rx_ring_skbs != 0) -+ printk(KERN_ERR -+ "%s: Error in freeing Rx Ring. %d skb's still" -+ " stuck in RX Ring - ignoring them\n", netdev->name, -+ titan_ge_eth->rx_ring_skbs); -+ -+#ifndef TITAN_RX_RING_IN_SRAM -+ dma_free_coherent(&titan_ge_device[port_num]->dev, -+ titan_ge_eth->rx_desc_area_size, -+ (void *) titan_ge_eth->rx_desc_area, -+ titan_ge_eth->rx_dma); -+#endif -+} -+ -+/* -+ * Actually does the stop of the Ethernet device -+ */ -+static void titan_ge_eth_stop(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ netif_stop_queue(netdev); -+ -+ titan_ge_port_reset(titan_ge_eth->port_num); -+ -+ titan_ge_free_tx_rings(netdev); -+ titan_ge_free_rx_rings(netdev); -+ -+ /* Disable the Tx and Rx Interrupts for all channels */ -+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0); -+} -+ -+/* -+ * Update the MAC address. Note that we have to write the -+ * address in three station registers, 16 bits each. And this -+ * has to be done for TMAC and RMAC -+ */ -+static void titan_ge_update_mac_address(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ unsigned int port_num = titan_ge_eth->port_num; -+ u8 p_addr[6]; -+ -+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); -+ memcpy(p_addr, netdev->dev_addr, 6); -+ -+ /* Update the Address Filtering Match tables */ -+ titan_ge_update_afx(titan_ge_eth); -+ -+ printk("Station MAC : %d %d %d %d %d %d \n", -+ p_addr[5], p_addr[4], p_addr[3], -+ p_addr[2], p_addr[1], p_addr[0]); -+ -+ /* Set the MAC address here for TMAC and RMAC */ -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+ -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)), -+ ((p_addr[5] << 8) | p_addr[4])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)), -+ ((p_addr[3] << 8) | p_addr[2])); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)), -+ ((p_addr[1] << 8) | p_addr[0])); -+} -+ -+/* -+ * Set the MAC address of the Ethernet device -+ */ -+static int titan_ge_set_mac_address(struct net_device *dev, void *addr) -+{ -+ titan_ge_port_info *tp = netdev_priv(dev); -+ struct sockaddr *sa = addr; -+ -+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); -+ -+ spin_lock_irq(&tp->lock); -+ titan_ge_update_mac_address(dev); -+ spin_unlock_irq(&tp->lock); -+ -+ return 0; -+} -+ -+/* -+ * Get the Ethernet device stats -+ */ -+static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev) -+{ -+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); -+ -+ return &titan_ge_eth->stats; -+} -+ -+/* -+ * Initialize the Rx descriptor ring for the Titan Ge -+ */ -+static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port, -+ int rx_desc_num, -+ int rx_buff_size, -+ unsigned long rx_desc_base_addr, -+ unsigned long rx_buff_base_addr, -+ unsigned long rx_dma) -+{ -+ volatile titan_ge_rx_desc *rx_desc; -+ unsigned long buffer_addr; -+ int index; -+ unsigned long titan_ge_rx_desc_bus = rx_dma; -+ -+ buffer_addr = rx_buff_base_addr; -+ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr; -+ -+ /* Check alignment */ -+ if (rx_buff_base_addr & 0xF) -+ return 0; -+ -+ /* Check Rx buffer size */ -+ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER)) -+ return 0; -+ -+ /* 64-bit alignment -+ if ((rx_buff_base_addr + rx_buff_size) & 0x7) -+ return 0; */ -+ -+ /* Initialize the Rx desc ring */ -+ for (index = 0; index < rx_desc_num; index++) { -+ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc); -+ rx_desc[index].cmd_sts = 0; -+ rx_desc[index].buffer_addr = buffer_addr; -+ titan_eth_port->rx_skb[index] = NULL; -+ buffer_addr += rx_buff_size; -+ } -+ -+ titan_eth_port->rx_curr_desc_q = 0; -+ titan_eth_port->rx_used_desc_q = 0; -+ -+ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr; -+ titan_eth_port->rx_desc_area_size = -+ rx_desc_num * sizeof(titan_ge_rx_desc); -+ -+ titan_eth_port->rx_dma = rx_dma; -+ -+ return TITAN_OK; -+} -+ -+/* -+ * Initialize the Tx descriptor ring. Descriptors in the SRAM -+ */ -+static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port, -+ int tx_desc_num, -+ unsigned long tx_desc_base_addr, -+ unsigned long tx_dma) -+{ -+ titan_ge_tx_desc *tx_desc; -+ int index; -+ unsigned long titan_ge_tx_desc_bus = tx_dma; -+ -+ if (tx_desc_base_addr & 0xF) -+ return 0; -+ -+ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr; -+ -+ for (index = 0; index < tx_desc_num; index++) { -+ titan_ge_port->tx_dma_array[index] = -+ (dma_addr_t) titan_ge_tx_desc_bus; -+ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc); -+ tx_desc[index].cmd_sts = 0x0000; -+ tx_desc[index].buffer_len = 0; -+ tx_desc[index].buffer_addr = 0x00000000; -+ titan_ge_port->tx_skb[index] = NULL; -+ } -+ -+ titan_ge_port->tx_curr_desc_q = 0; -+ titan_ge_port->tx_used_desc_q = 0; -+ -+ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr; -+ titan_ge_port->tx_desc_area_size = -+ tx_desc_num * sizeof(titan_ge_tx_desc); -+ -+ titan_ge_port->tx_dma = tx_dma; -+ return TITAN_OK; -+} -+ -+/* -+ * Initialize the device as an Ethernet device -+ */ -+static int __init titan_ge_probe(struct device *device) -+{ -+ titan_ge_port_info *titan_ge_eth; -+ struct net_device *netdev; -+ int port = to_platform_device(device)->id; -+ int err; -+ -+ netdev = alloc_etherdev(sizeof(titan_ge_port_info)); -+ if (!netdev) { -+ err = -ENODEV; -+ goto out; -+ } -+ -+ netdev->open = titan_ge_open; -+ netdev->stop = titan_ge_stop; -+ netdev->hard_start_xmit = titan_ge_start_xmit; -+ netdev->get_stats = titan_ge_get_stats; -+ netdev->set_multicast_list = titan_ge_set_multi; -+ netdev->set_mac_address = titan_ge_set_mac_address; -+ -+ /* Tx timeout */ -+ netdev->tx_timeout = titan_ge_tx_timeout; -+ netdev->watchdog_timeo = 2 * HZ; -+ -+ /* Set these to very high values */ -+ netdev->poll = titan_ge_poll; -+ netdev->weight = 64; -+ -+ netdev->tx_queue_len = TITAN_GE_TX_QUEUE; -+ netif_carrier_off(netdev); -+ netdev->base_addr = 0; -+ -+ netdev->change_mtu = titan_ge_change_mtu; -+ -+ titan_ge_eth = netdev_priv(netdev); -+ /* Allocation of memory for the driver structures */ -+ -+ titan_ge_eth->port_num = port; -+ -+ /* Configure the Tx timeout handler */ -+ INIT_WORK(&titan_ge_eth->tx_timeout_task, -+ (void (*)(void *)) titan_ge_tx_timeout_task, netdev); -+ -+ spin_lock_init(&titan_ge_eth->lock); -+ -+ /* set MAC addresses */ -+ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6); -+ netdev->dev_addr[5] += port; -+ -+ err = register_netdev(netdev); -+ -+ if (err) -+ goto out_free_netdev; -+ -+ printk(KERN_NOTICE -+ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", -+ netdev->name, port, netdev->dev_addr[0], -+ netdev->dev_addr[1], netdev->dev_addr[2], -+ netdev->dev_addr[3], netdev->dev_addr[4], -+ netdev->dev_addr[5]); -+ -+ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n"); -+ -+ return 0; -+ -+out_free_netdev: -+ kfree(netdev); -+ -+out: -+ return err; -+} -+ -+static void __devexit titan_device_remove(struct device *device) -+{ -+} -+ -+/* -+ * Reset the Ethernet port -+ */ -+static void titan_ge_port_reset(unsigned int port_num) -+{ -+ unsigned int reg_data; -+ -+ /* Stop the Tx port activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x0001); -+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ /* Stop the Rx port activity */ -+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)); -+ reg_data &= ~(0x0001); -+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + -+ (port_num << 12)), reg_data); -+ -+ return; -+} -+ -+/* -+ * Return the Tx desc after use by the XDMA -+ */ -+static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port) -+{ -+ int tx_desc_used; -+ struct sk_buff *skb; -+ -+ tx_desc_used = titan_ge_eth->tx_used_desc_q; -+ -+ /* return right away */ -+ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q) -+ return TITAN_ERROR; -+ -+ /* Now the critical stuff */ -+ skb = titan_ge_eth->tx_skb[tx_desc_used]; -+ -+ dev_kfree_skb_any(skb); -+ -+ titan_ge_eth->tx_skb[tx_desc_used] = NULL; -+ titan_ge_eth->tx_used_desc_q = -+ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE; -+ -+ return 0; -+} -+ -+/* -+ * Coalescing for the Tx path -+ */ -+static unsigned long titan_ge_tx_coal(unsigned long delay, int port) -+{ -+ unsigned long rx_delay; -+ -+ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING); -+ delay = (delay << 16) | rx_delay; -+ -+ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay); -+ TITAN_GE_WRITE(0x5038, delay); -+ -+ return delay; -+} -+ -+static struct device_driver titan_soc_driver = { -+ .name = titan_string, -+ .bus = &platform_bus_type, -+ .probe = titan_ge_probe, -+ .remove = __devexit_p(titan_device_remove), -+}; -+ -+static void titan_platform_release (struct device *device) -+{ -+ struct platform_device *pldev; -+ -+ /* free device */ -+ pldev = to_platform_device (device); -+ kfree (pldev); -+} -+ -+/* -+ * Register the Titan GE with the kernel -+ */ -+static int __init titan_ge_init_module(void) -+{ -+ struct platform_device *pldev; -+ unsigned int version, device; -+ int i; -+ -+ printk(KERN_NOTICE -+ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n"); -+ -+ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE); -+ if (!titan_ge_base) { -+ printk("Mapping Titan GE failed\n"); -+ goto out; -+ } -+ -+ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID); -+ version = (device & 0x000f0000) >> 16; -+ device &= 0x0000ffff; -+ -+ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version); -+ -+#ifdef TITAN_RX_RING_IN_SRAM -+ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE, -+ TITAN_SRAM_SIZE); -+ if (!titan_ge_sram) { -+ printk("Mapping Titan SRAM failed\n"); -+ goto out_unmap_ge; -+ } -+#endif -+ -+ if (driver_register(&titan_soc_driver)) { -+ printk(KERN_ERR "Driver registration failed\n"); -+ goto out_unmap_sram; -+ } -+ -+ for (i = 0; i < 3; i++) { -+ titan_ge_device[i] = NULL; -+ -+ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) -+ continue; -+ -+ memset (pldev, 0, sizeof (*pldev)); -+ pldev->name = titan_string; -+ pldev->id = i; -+ pldev->dev.release = titan_platform_release; -+ titan_ge_device[i] = pldev; -+ -+ if (platform_device_register (pldev)) { -+ kfree (pldev); -+ titan_ge_device[i] = NULL; -+ continue; -+ } -+ -+ if (!pldev->dev.driver) { -+ /* -+ * The driver was not bound to this device, there was -+ * no hardware at this address. Unregister it, as the -+ * release fuction will take care of freeing the -+ * allocated structure -+ */ -+ titan_ge_device[i] = NULL; -+ platform_device_unregister (pldev); -+ } -+ } -+ -+ return 0; -+ -+out_unmap_sram: -+ iounmap((void *)titan_ge_sram); -+ -+out_unmap_ge: -+ iounmap((void *)titan_ge_base); -+ -+out: -+ return -ENOMEM; -+} -+ -+/* -+ * Unregister the Titan GE from the kernel -+ */ -+static void __exit titan_ge_cleanup_module(void) -+{ -+ int i; -+ -+ driver_unregister(&titan_soc_driver); -+ -+ for (i = 0; i < 3; i++) { -+ if (titan_ge_device[i]) { -+ platform_device_unregister (titan_ge_device[i]); -+ titan_ge_device[i] = NULL; -+ } -+ } -+ -+ iounmap((void *)titan_ge_sram); -+ iounmap((void *)titan_ge_base); -+} -+ -+MODULE_AUTHOR("Manish Lachwani "); -+MODULE_DESCRIPTION("Titan GE Ethernet driver"); -+MODULE_LICENSE("GPL"); -+ -+module_init(titan_ge_init_module); -+module_exit(titan_ge_cleanup_module); -diff --git a/drivers/net/titan_ge.h b/drivers/net/titan_ge.h -new file mode 100644 -index 0000000..3719f78 ---- /dev/null -+++ b/drivers/net/titan_ge.h -@@ -0,0 +1,415 @@ -+#ifndef _TITAN_GE_H_ -+#define _TITAN_GE_H_ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * These functions should be later moved to a more generic location since there -+ * will be others accessing it also -+ */ -+ -+/* -+ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in -+ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 -+ * register. -+ */ -+ -+#define TITAN_GE_BASE 0xfe000000UL -+#define TITAN_GE_SIZE 0x10000UL -+ -+extern unsigned long titan_ge_base; -+ -+#define TITAN_GE_WRITE(offset, data) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) = (data) -+ -+#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset)) -+ -+#ifndef msec_delay -+#define msec_delay(x) do { if(in_interrupt()) { \ -+ /* Don't mdelay in interrupt context! */ \ -+ BUG(); \ -+ } else { \ -+ set_current_state(TASK_UNINTERRUPTIBLE); \ -+ schedule_timeout((x * HZ)/1000); \ -+ } } while(0) -+#endif -+ -+#define TITAN_GE_PORT_0 -+ -+#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4) -+#define TITAN_SRAM_SIZE 0x2000UL -+ -+/* -+ * We may need these constants -+ */ -+#define TITAN_BIT0 0x00000001 -+#define TITAN_BIT1 0x00000002 -+#define TITAN_BIT2 0x00000004 -+#define TITAN_BIT3 0x00000008 -+#define TITAN_BIT4 0x00000010 -+#define TITAN_BIT5 0x00000020 -+#define TITAN_BIT6 0x00000040 -+#define TITAN_BIT7 0x00000080 -+#define TITAN_BIT8 0x00000100 -+#define TITAN_BIT9 0x00000200 -+#define TITAN_BIT10 0x00000400 -+#define TITAN_BIT11 0x00000800 -+#define TITAN_BIT12 0x00001000 -+#define TITAN_BIT13 0x00002000 -+#define TITAN_BIT14 0x00004000 -+#define TITAN_BIT15 0x00008000 -+#define TITAN_BIT16 0x00010000 -+#define TITAN_BIT17 0x00020000 -+#define TITAN_BIT18 0x00040000 -+#define TITAN_BIT19 0x00080000 -+#define TITAN_BIT20 0x00100000 -+#define TITAN_BIT21 0x00200000 -+#define TITAN_BIT22 0x00400000 -+#define TITAN_BIT23 0x00800000 -+#define TITAN_BIT24 0x01000000 -+#define TITAN_BIT25 0x02000000 -+#define TITAN_BIT26 0x04000000 -+#define TITAN_BIT27 0x08000000 -+#define TITAN_BIT28 0x10000000 -+#define TITAN_BIT29 0x20000000 -+#define TITAN_BIT30 0x40000000 -+#define TITAN_BIT31 0x80000000 -+ -+/* Flow Control */ -+#define TITAN_GE_FC_NONE 0x0 -+#define TITAN_GE_FC_FULL 0x1 -+#define TITAN_GE_FC_TX_PAUSE 0x2 -+#define TITAN_GE_FC_RX_PAUSE 0x3 -+ -+/* Duplex Settings */ -+#define TITAN_GE_FULL_DUPLEX 0x1 -+#define TITAN_GE_HALF_DUPLEX 0x2 -+ -+/* Speed settings */ -+#define TITAN_GE_SPEED_1000 0x1 -+#define TITAN_GE_SPEED_100 0x2 -+#define TITAN_GE_SPEED_10 0x3 -+ -+/* Debugging info only */ -+#undef TITAN_DEBUG -+ -+/* Keep the rings in the Titan's SSRAM */ -+#define TITAN_RX_RING_IN_SRAM -+ -+#ifdef CONFIG_64BIT -+#define TITAN_GE_IE_MASK 0xfffffffffb001b64 -+#define TITAN_GE_IE_STATUS 0xfffffffffb001b60 -+#else -+#define TITAN_GE_IE_MASK 0xfb001b64 -+#define TITAN_GE_IE_STATUS 0xfb001b60 -+#endif -+ -+/* Support for Jumbo Frames */ -+#undef TITAN_GE_JUMBO_FRAMES -+ -+/* Rx buffer size */ -+#ifdef TITAN_GE_JUMBO_FRAMES -+#define TITAN_GE_JUMBO_BUFSIZE 9080 -+#else -+#define TITAN_GE_STD_BUFSIZE 1580 -+#endif -+ -+/* -+ * Tx and Rx Interrupt Coalescing parameter. These values are -+ * for 1 Ghz processor. Rx coalescing can be taken care of -+ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing -+ * is not adaptive. Hence, these values need to be adjusted -+ * based on load, CPU speed etc. -+ */ -+#define TITAN_GE_RX_COAL 150 -+#define TITAN_GE_TX_COAL 300 -+ -+#if defined(__BIG_ENDIAN) -+ -+/* Define the Rx descriptor */ -+typedef struct eth_rx_desc { -+ u32 reserved; /* Unused */ -+ u32 buffer_addr; /* CPU buffer address */ -+ u32 cmd_sts; /* Command and Status */ -+ u32 buffer; /* XDMA buffer address */ -+} titan_ge_rx_desc; -+ -+/* Define the Tx descriptor */ -+typedef struct eth_tx_desc { -+ u16 cmd_sts; /* Command, Status and Buffer count */ -+ u16 buffer_len; /* Length of the buffer */ -+ u32 buffer_addr; /* Physical address of the buffer */ -+} titan_ge_tx_desc; -+ -+#elif defined(__LITTLE_ENDIAN) -+ -+/* Define the Rx descriptor */ -+typedef struct eth_rx_desc { -+ u32 buffer_addr; /* CPU buffer address */ -+ u32 reserved; /* Unused */ -+ u32 buffer; /* XDMA buffer address */ -+ u32 cmd_sts; /* Command and Status */ -+} titan_ge_rx_desc; -+ -+/* Define the Tx descriptor */ -+typedef struct eth_tx_desc { -+ u32 buffer_addr; /* Physical address of the buffer */ -+ u16 buffer_len; /* Length of the buffer */ -+ u16 cmd_sts; /* Command, Status and Buffer count */ -+} titan_ge_tx_desc; -+#endif -+ -+/* Default Tx Queue Size */ -+#define TITAN_GE_TX_QUEUE 128 -+#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc)) -+ -+/* Default Rx Queue Size */ -+#define TITAN_GE_RX_QUEUE 64 -+#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc)) -+ -+/* Packet Structure */ -+typedef struct _pkt_info { -+ unsigned int len; -+ unsigned int cmd_sts; -+ unsigned int buffer; -+ struct sk_buff *skb; -+ unsigned int checksum; -+} titan_ge_packet; -+ -+ -+#define PHYS_CNT 3 -+ -+/* Titan Port specific data structure */ -+typedef struct _eth_port_ctrl { -+ unsigned int port_num; -+ u8 port_mac_addr[6]; -+ -+ /* Rx descriptor pointers */ -+ int rx_curr_desc_q, rx_used_desc_q; -+ -+ /* Tx descriptor pointers */ -+ int tx_curr_desc_q, tx_used_desc_q; -+ -+ /* Rx descriptor area */ -+ volatile titan_ge_rx_desc *rx_desc_area; -+ unsigned int rx_desc_area_size; -+ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE]; -+ -+ /* Tx Descriptor area */ -+ volatile titan_ge_tx_desc *tx_desc_area; -+ unsigned int tx_desc_area_size; -+ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE]; -+ -+ /* Timeout task */ -+ struct work_struct tx_timeout_task; -+ -+ /* DMA structures and handles */ -+ dma_addr_t tx_dma; -+ dma_addr_t rx_dma; -+ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE]; -+ -+ /* Device lock */ -+ spinlock_t lock; -+ -+ unsigned int tx_ring_skbs; -+ unsigned int rx_ring_size; -+ unsigned int tx_ring_size; -+ unsigned int rx_ring_skbs; -+ -+ struct net_device_stats stats; -+ -+ /* Tx and Rx coalescing */ -+ unsigned long rx_int_coal; -+ unsigned long tx_int_coal; -+ -+ /* Threshold for replenishing the Rx and Tx rings */ -+ unsigned int tx_threshold; -+ unsigned int rx_threshold; -+ -+ /* NAPI work limit */ -+ unsigned int rx_work_limit; -+} titan_ge_port_info; -+ -+/* Titan specific constants */ -+#define TITAN_ETH_PORT_IRQ 3 -+ -+/* Max Rx buffer */ -+#define TITAN_GE_MAX_RX_BUFFER 65536 -+ -+/* Tx and Rx Error */ -+#define TITAN_GE_ERROR -+ -+/* Rx Descriptor Command and Status */ -+ -+#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */ -+#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */ -+#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */ -+#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */ -+#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */ -+#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */ -+#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */ -+#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */ -+#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */ -+#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */ -+ -+/* Tx Descriptor Command */ -+#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */ -+#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */ -+ -+/* Return Status */ -+#define TITAN_OK 0x1 /* Good Status */ -+#define TITAN_ERROR 0x2 /* Error Status */ -+ -+/* MIB specific register offset */ -+#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */ -+#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */ -+#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */ -+#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */ -+#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */ -+ -+/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */ -+#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040 -+#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050 -+#define TITAN_GE_MSTATX_RXFRAMES 0x0060 -+#define TITAN_GE_MSTATX_RXOCTETS 0x0070 -+#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080 -+#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090 -+#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0 -+#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0 -+#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0 -+#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0 -+#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0 -+#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0 -+#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100 -+#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110 -+#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120 -+#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130 -+#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140 -+#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150 -+#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160 -+#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170 -+#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180 -+#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190 -+#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0 -+#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0 -+#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0 -+#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0 -+#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0 -+#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0 -+#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200 -+#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210 -+#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220 -+#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230 -+#define TITAN_GE_MSTATX_HASHFILTERED 0x0240 -+#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250 -+#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260 -+#define TITAN_GE_MSTATX_TXOCTETS 0x0270 -+#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280 -+#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290 -+#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0 -+#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0 -+#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0 -+#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0 -+#define TITAN_GE_MSTATX_TXMACERROR 0x02E0 -+#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0 -+#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300 -+#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310 -+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320 -+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330 -+#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340 -+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350 -+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360 -+#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370 -+#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380 -+#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390 -+#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0 -+#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0 -+#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0 -+#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0 -+#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0 -+#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0 -+#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400 -+#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410 -+#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420 -+#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430 -+#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440 -+ -+/* Interrupt specific defines */ -+#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */ -+#define TITAN_GE_RESET 0x0004 /* Reset reg */ -+#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */ -+#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */ -+#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */ -+#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/ -+#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/ -+#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */ -+#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */ -+#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/ -+#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */ -+#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/ -+#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */ -+#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */ -+#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */ -+#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */ -+#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */ -+#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */ -+#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */ -+#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */ -+ -+/* Rx MAC defines */ -+#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */ -+#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */ -+#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */ -+#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */ -+#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */ -+#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */ -+#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */ -+ -+/* Tx MAC defines */ -+#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */ -+#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */ -+#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */ -+#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */ -+#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */ -+#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */ -+#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */ -+#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */ -+#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */ -+#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */ -+ -+/* GMII register */ -+#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */ -+#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */ -+#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */ -+ -+/* Tx and Rx XDMA defines */ -+#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */ -+#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */ -+#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */ -+#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */ -+#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */ -+#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */ -+#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */ -+#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */ -+ -+/* AFX (Address Filter Exact) register offsets for Slice 0 */ -+#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/ -+#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/ -+#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */ -+#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */ -+#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */ -+#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */ -+#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */ -+#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */ -+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */ -+ -+/* Traffic Groomer block */ -+#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */ -+ -+#endif /* _TITAN_GE_H_ */ -+ -diff --git a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c -new file mode 100644 -index 0000000..8a8785b ---- /dev/null -+++ b/drivers/net/titan_mdio.c -@@ -0,0 +1,217 @@ -+/* -+ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports -+ * -+ * Copyright (C) 2003 PMC-Sierra Inc. -+ * Author : Manish Lachwani (lachwani@pmc-sierra.com) -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY -+ * on the Titan. No support for the TBI as yet. -+ * -+ */ -+ -+#include "titan_mdio.h" -+ -+#define MDIO_DEBUG -+ -+/* -+ * Local constants -+ */ -+#define MAX_CLKA 1023 -+#define MAX_PHY_DEV 31 -+#define MAX_PHY_REG 31 -+#define WRITEADDRS_OPCODE 0x0 -+#define READ_OPCODE 0x2 -+#define WRITE_OPCODE 0x1 -+#define MAX_MDIO_POLL 100 -+ -+/* -+ * Titan MDIO and SCMB registers -+ */ -+#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */ -+#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */ -+#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */ -+#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */ -+#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */ -+#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */ -+ -+/* -+ * Function to poll the MDIO -+ */ -+static int titan_ge_mdio_poll(void) -+{ -+ int i, val; -+ -+ for (i = 0; i < MAX_MDIO_POLL; i++) { -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ -+ if (!(val & 0x8000)) -+ return TITAN_GE_MDIO_GOOD; -+ } -+ -+ return TITAN_GE_MDIO_ERROR; -+} -+ -+ -+/* -+ * Initialize and configure the MDIO -+ */ -+int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio) -+{ -+ unsigned long val; -+ -+ /* Reset the SCMB and program into MDIO mode*/ -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000); -+ -+ /* CLK A */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA); -+ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val); -+ -+ /* Preamble Suppresion */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ /* MDIO mode */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Set the PHY address in indirect mode -+ */ -+int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr) -+{ -+ volatile unsigned long val; -+ -+ /* Setup the PHY device */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ /* Write the new address */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Read the MDIO register. This is what the individual parametes mean: -+ * -+ * dev_addr : PHY ID -+ * reg_addr : register offset -+ * -+ * See the spec for the Titan MAC. We operate in the Direct Mode. -+ */ -+ -+#define MAX_RETRIES 2 -+ -+int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata) -+{ -+ volatile unsigned long val; -+ int retries = 0; -+ -+ /* Setup the PHY device */ -+ -+again: -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ val |= 0x4000; -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ udelay(30); -+ -+ /* Issue the read command */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ udelay(30); -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA); -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); -+ -+ udelay(30); -+ -+ if (val & 0x2) { -+ if (retries == MAX_RETRIES) -+ return TITAN_GE_MDIO_ERROR; -+ else { -+ retries++; -+ goto again; -+ } -+ } -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -+/* -+ * Write to the MDIO register -+ * -+ * dev_addr : PHY ID -+ * reg_addr : register that needs to be written to -+ * -+ */ -+int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data) -+{ -+ volatile unsigned long val; -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ /* Setup the PHY device */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); -+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); -+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); -+ val |= 0x4000; -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); -+ -+ udelay(30); -+ -+ /* Setup the data to write */ -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data); -+ -+ udelay(30); -+ -+ /* Issue the write command */ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); -+ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300)); -+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); -+ -+ udelay(30); -+ -+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) -+ return TITAN_GE_MDIO_ERROR; -+ -+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); -+ if (val & 0x2) -+ return TITAN_GE_MDIO_ERROR; -+ -+ return TITAN_GE_MDIO_GOOD; -+} -+ -diff --git a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h -new file mode 100644 -index 0000000..5d23344 ---- /dev/null -+++ b/drivers/net/titan_mdio.h -@@ -0,0 +1,56 @@ -+/* -+ * MDIO used to interact with the PHY when using GMII/MII -+ */ -+#ifndef _TITAN_MDIO_H -+#define _TITAN_MDIO_H -+ -+#include -+#include -+#include -+#include "titan_ge.h" -+ -+ -+#define TITAN_GE_MDIO_ERROR (-9000) -+#define TITAN_GE_MDIO_GOOD 0 -+ -+#define TITAN_GE_MDIO_BASE titan_ge_base -+ -+#define TITAN_GE_MDIO_READ(offset) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) -+ -+#define TITAN_GE_MDIO_WRITE(offset, data) \ -+ *(volatile u32 *)(titan_ge_base + (offset)) = (data) -+ -+ -+/* GMII specific registers */ -+#define TITAN_GE_MARVEL_PHY_ID 0x00 -+#define TITAN_PHY_AUTONEG_ADV 0x04 -+#define TITAN_PHY_LP_ABILITY 0x05 -+#define TITAN_GE_MDIO_MII_CTRL 0x09 -+#define TITAN_GE_MDIO_MII_EXTENDED 0x0f -+#define TITAN_GE_MDIO_PHY_CTRL 0x10 -+#define TITAN_GE_MDIO_PHY_STATUS 0x11 -+#define TITAN_GE_MDIO_PHY_IE 0x12 -+#define TITAN_GE_MDIO_PHY_IS 0x13 -+#define TITAN_GE_MDIO_PHY_LED 0x18 -+#define TITAN_GE_MDIO_PHY_LED_OVER 0x19 -+#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */ -+ -+/* -+ * MDIO Config Structure -+ */ -+typedef struct { -+ unsigned int clka; -+ int mdio_spre; -+ int mdio_mode; -+} titan_ge_mdio_config; -+ -+/* -+ * Function Prototypes -+ */ -+int titan_ge_mdio_setup(titan_ge_mdio_config *); -+int titan_ge_mdio_inaddrs(int, int); -+int titan_ge_mdio_read(int, int, unsigned int *); -+int titan_ge_mdio_write(int, int, unsigned int); -+ -+#endif /* _TITAN_MDIO_H */ -diff --git a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -index 3411671..4d252c1 100644 ---- a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -+++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c -@@ -22,6 +22,10 @@ - - static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) - { -+#ifdef CONFIG_LEMOTE_MACH2F -+ /* Allow users to activate rfkill through only the /sys interface */ -+ return 1; -+#else - u8 gpio; - - gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); -@@ -29,6 +33,7 @@ static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) - gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); - - return gpio & priv->rfkill_mask; -+#endif - } - - void rtl8187_rfkill_init(struct ieee80211_hw *hw) -diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig -index 09fde58..eacabd1 100644 ---- a/drivers/platform/Kconfig -+++ b/drivers/platform/Kconfig -@@ -4,5 +4,8 @@ endif - if GOLDFISH - source "drivers/platform/goldfish/Kconfig" - endif -+if MIPS -+source "drivers/platform/mips/Kconfig" -+endif - - source "drivers/platform/chrome/Kconfig" -diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile -index 3656b7b..ca26925 100644 ---- a/drivers/platform/Makefile -+++ b/drivers/platform/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_X86) += x86/ -+obj-$(CONFIG_MIPS) += mips/ - obj-$(CONFIG_OLPC) += olpc/ - obj-$(CONFIG_GOLDFISH) += goldfish/ - obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ -diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig -new file mode 100644 -index 0000000..722d690 ---- /dev/null -+++ b/drivers/platform/mips/Kconfig -@@ -0,0 +1,60 @@ -+# -+# MIPS Platform Specific Drivers -+# -+ -+menuconfig MIPS_PLATFORM_DEVICES -+ bool "MIPS Platform Specific Device Drivers" -+ default y -+ help -+ Say Y here to get to see options for device drivers of various -+ MIPS platforms, including vendor-specific netbook/laptop/pc extension -+ drivers. This option alone does not add any kernel code. -+ -+ If you say N, all options in this submenu will be skipped and disabled. -+ -+if MIPS_PLATFORM_DEVICES -+ -+config LEMOTE_YEELOONG2F -+ tristate "Lemote YeeLoong Laptop" -+ depends on LEMOTE_MACH2F -+ select BACKLIGHT_LCD_SUPPORT -+ select LCD_CLASS_DEVICE -+ select BACKLIGHT_CLASS_DEVICE -+ select POWER_SUPPLY -+ select HWMON -+ select VIDEO_OUTPUT_CONTROL -+ select INPUT_SPARSEKMAP -+ select INPUT_EVDEV -+ depends on INPUT -+ default m -+ help -+ YeeLoong netbook is a mini laptop made by Lemote, which is basically -+ compatible to FuLoong2F mini PC, but it has an extra Embedded -+ Controller(kb3310b) for battery, hotkey, backlight, temperature and -+ fan management. -+ -+config LEMOTE_LYNLOONG2F -+ tristate "Lemote LynLoong PC" -+ depends on LEMOTE_MACH2F -+ select BACKLIGHT_LCD_SUPPORT -+ select BACKLIGHT_CLASS_DEVICE -+ select VIDEO_OUTPUT_CONTROL -+ default m -+ help -+ LynLoong PC is an AllINONE machine made by Lemote, which is basically -+ compatible to FuLoong2F Mini PC, the only difference is that it has a -+ size-fixed screen: 1360x768 with sisfb video driver. and also, it has -+ its own specific suspend support. -+ -+config GDIUM_LAPTOP -+ tristate "GDIUM laptop extras" -+ depends on DEXXON_GDIUM -+ select POWER_SUPPLY -+ select I2C -+ select INPUT_POLLDEV -+ default m -+ help -+ This mini-driver drives the ST7 chipset present in the Gdium laptops. -+ This gives battery support, wlan rfkill. -+ -+endif # MIPS_PLATFORM_DEVICES -diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile -new file mode 100644 -index 0000000..f013e78 ---- /dev/null -+++ b/drivers/platform/mips/Makefile -@@ -0,0 +1,9 @@ -+# -+# Makefile for MIPS Platform-Specific Drivers -+# -+ -+obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o # yeeloong_ecrom.o -+CFLAGS_yeeloong_laptop.o = -I$(srctree)/arch/mips/loongson/lemote-2f -+ -+obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o -+obj-$(CONFIG_GDIUM_LAPTOP) += gdium_laptop.o -diff --git a/drivers/platform/mips/gdium_laptop.c b/drivers/platform/mips/gdium_laptop.c -new file mode 100644 -index 0000000..41a65ad ---- /dev/null -+++ b/drivers/platform/mips/gdium_laptop.c -@@ -0,0 +1,927 @@ -+/* -+ * gdium_laptop -- Gdium laptop extras -+ * -+ * Arnaud Patard -+ * -+ * 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. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* For input device */ -+#define SCAN_INTERVAL 150 -+ -+/* For battery status */ -+#define BAT_SCAN_INTERVAL 500 -+ -+#define EC_FIRM_VERSION 0 -+ -+#if CONFIG_GDIUM_VERSION > 2 -+#define EC_REG_BASE 1 -+#else -+#define EC_REG_BASE 0 -+#endif -+ -+#define EC_STATUS (EC_REG_BASE+0) -+#define EC_STATUS_LID (1<<0) -+#define EC_STATUS_PWRBUT (1<<1) -+#define EC_STATUS_BATID (1<<2) /* this bit has no real meaning on v2. */ -+ /* Same as EC_STATUS_ADAPT */ -+ /* but on v3 it's BATID which mean bat present */ -+#define EC_STATUS_SYS_POWER (1<<3) -+#define EC_STATUS_WLAN (1<<4) -+#define EC_STATUS_ADAPT (1<<5) -+ -+#define EC_CTRL (EC_REG_BASE+1) -+#define EC_CTRL_DDR_CLK (1<<0) -+#define EC_CTRL_CHARGE_LED (1<<1) -+#define EC_CTRL_BEEP (1<<2) -+#define EC_CTRL_SUSB (1<<3) /* memory power */ -+#define EC_CTRL_TRICKLE (1<<4) -+#define EC_CTRL_WLAN_EN (1<<5) -+#define EC_CTRL_SUSC (1<<6) /* main power */ -+#define EC_CTRL_CHARGE_EN (1<<7) -+ -+#define EC_BAT_LOW (EC_REG_BASE+2) -+#define EC_BAT_HIGH (EC_REG_BASE+3) -+ -+#define EC_SIGN (EC_REG_BASE+4) -+#define EC_SIGN_OS 0xAE /* write 0xae to control pm stuff */ -+#define EC_SIGN_EC 0x00 /* write 0x00 to let the st7 manage pm stuff */ -+ -+#if 0 -+#define EC_TEST (EC_REG_BASE+5) /* Depending on firmware version this register */ -+ /* may be the programmation register so don't play */ -+ /* with it */ -+#endif -+ -+#define BAT_VOLT_PRESENT 500000 /* Min voltage to consider battery present uV */ -+#define BAT_MIN 7000000 /* Min battery voltage in uV */ -+#define BAT_MIN_MV 7000 /* Min battery voltage in mV */ -+#define BAT_TRICKLE_EN 8000000 /* Charging at 1.4A before 8.0V and then charging at 0.25A */ -+#define BAT_MAX 7950000 /* Max battery voltage ~8V in V */ -+#define BAT_MAX_MV 7950 /* Max battery voltage ~8V in V */ -+#define BAT_READ_ERROR 300000 /* battery read error of 0.3V */ -+#define BAT_READ_ERROR_MV 300 /* battery read error of 0.3V */ -+ -+#define SM502_WLAN_ON (224+16)/* SM502 GPIO16 may be used on gdium v2 (v3?) as wlan_on */ -+ /* when R422 is connected */ -+ -+static unsigned char verbose; -+static unsigned char gpio16; -+static unsigned char ec; -+module_param(verbose, byte, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(verbose, "Add some debugging messages"); -+module_param(gpio16, byte, S_IRUGO); -+MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502"); -+module_param(ec, byte, S_IRUGO); -+MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)"); -+ -+struct gdium_laptop_data { -+ struct i2c_client *client; -+ struct input_polled_dev *input_polldev; -+ struct dentry *debugfs; -+ struct mutex mutex; -+ struct platform_device *bat_pdev; -+ struct power_supply gdium_ac; -+ struct power_supply gdium_battery; -+ struct workqueue_struct *workqueue; -+ struct delayed_work work; -+ char charge_cmd; -+ /* important registers value */ -+ char status; -+ char ctrl; -+ /* mV */ -+ int battery_level; -+ char version; -+}; -+ -+/**********************************************************************/ -+/* Low level I2C functions */ -+/* All are supposed to be called with mutex held */ -+/**********************************************************************/ -+/* -+ * Return battery voltage in mV -+ * >= 0 battery voltage -+ * < 0 error -+ */ -+static s32 ec_read_battery(struct i2c_client *client) -+{ -+ unsigned char bat_low, bat_high; -+ s32 data; -+ unsigned int ret; -+ -+ /* -+ * a = battery high -+ * b = battery low -+ * bat = a << 2 | b & 0x03; -+ * battery voltage = (bat / 1024) * 5 * 2 -+ */ -+ data = i2c_smbus_read_byte_data(client, EC_BAT_LOW); -+ if (data < 0) { -+ dev_err(&client->dev, "ec_read_bat: read bat_low failed\n"); -+ return data; -+ } -+ bat_low = data & 0xff; -+ if (verbose) -+ dev_info(&client->dev, "bat_low %x\n", bat_low); -+ -+ data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH); -+ if (data < 0) { -+ dev_err(&client->dev, "ec_read_bat: read bat_high failed\n"); -+ return data; -+ } -+ bat_high = data & 0xff; -+ if (verbose) -+ dev_info(&client->dev, "bat_high %x\n", bat_high); -+ -+ ret = (bat_high << 2) | (bat_low & 3); -+ /* -+ * mV -+ */ -+ ret = (ret * 5 * 2) * 1000 / 1024; -+ -+ return ret; -+} -+ -+static s32 ec_read_version(struct i2c_client *client) -+{ -+#if CONFIG_GDIUM_VERSION > 2 -+ return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION); -+#else -+ return 0; -+#endif -+} -+ -+static s32 ec_read_status(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_STATUS); -+} -+ -+static s32 ec_read_ctrl(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_CTRL); -+} -+ -+static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue) -+{ -+ return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue); -+} -+ -+static s32 ec_read_sign(struct i2c_client *client) -+{ -+ return i2c_smbus_read_byte_data(client, EC_SIGN); -+} -+ -+static s32 ec_write_sign(struct i2c_client *client, unsigned char sign) -+{ -+ unsigned char value; -+ s32 ret; -+ -+ ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign); -+ if (ret < 0) { -+ dev_err(&client->dev, "ec_set_control: write failed\n"); -+ return ret; -+ } -+ -+ value = ec_read_sign(client); -+ if (value != sign) { -+ dev_err(&client->dev, "Failed to set control to %s\n", -+ sign == EC_SIGN_OS ? "OS" : "EC"); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+#if 0 -+static int ec_power_off(struct i2c_client *client) -+{ -+ char value; -+ int ret; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) { -+ dev_err(&client->dev, "ec_power_off: read failed\n"); -+ return value; -+ } -+ value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC); -+ ret = ec_write_ctrl(client, value); -+ if (ret < 0) { -+ dev_err(&client->dev, "ec_power_off: write failed\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+#endif -+ -+static s32 ec_wlan_status(struct i2c_client *client) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ return (value & EC_CTRL_WLAN_EN) ? 1 : 0; -+} -+ -+static s32 ec_wlan_en(struct i2c_client *client, int on) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ value &= ~EC_CTRL_WLAN_EN; -+ if (on) -+ value |= EC_CTRL_WLAN_EN; -+ -+ return ec_write_ctrl(client, value&0xff); -+} -+ -+#if 0 -+static s32 ec_led_status(struct i2c_client *client) -+{ -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ return (value & EC_CTRL_CHARGE_LED) ? 1 : 0; -+} -+#endif -+ -+/* Changing the charging led status has never worked */ -+static s32 ec_led_en(struct i2c_client *client, int on) -+{ -+#if 0 -+ s32 value; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ value &= ~EC_CTRL_CHARGE_LED; -+ if (on) -+ value |= EC_CTRL_CHARGE_LED; -+ return ec_write_ctrl(client, value&0xff); -+#else -+ return 0; -+#endif -+} -+ -+static s32 ec_charge_en(struct i2c_client *client, int on, int trickle) -+{ -+ s32 value; -+ s32 set = 0; -+ -+ value = ec_read_ctrl(client); -+ if (value < 0) -+ return value; -+ -+ if (on) -+ set |= EC_CTRL_CHARGE_EN; -+ if (trickle) -+ set |= EC_CTRL_TRICKLE; -+ -+ /* Be clever : don't change values if you don't need to */ -+ if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set) -+ return 0; -+ -+ value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE); -+ value |= set; -+ ec_led_en(client, on); -+ return ec_write_ctrl(client, (unsigned char)(value&0xff)); -+ -+} -+ -+/**********************************************************************/ -+/* Input functions */ -+/**********************************************************************/ -+struct gdium_keys { -+ int last_state; -+ int key_code; -+ int mask; -+ int type; -+}; -+ -+static struct gdium_keys gkeys[] = { -+ { -+ .key_code = KEY_WLAN, -+ .mask = EC_STATUS_WLAN, -+ .type = EV_KEY, -+ }, -+ { -+ .key_code = KEY_POWER, -+ .mask = EC_STATUS_PWRBUT, -+ .type = EV_KEY, /*EV_PWR,*/ -+ }, -+ { -+ .key_code = SW_LID, -+ .mask = EC_STATUS_LID, -+ .type = EV_SW, -+ }, -+}; -+ -+static void gdium_laptop_keys_poll(struct input_polled_dev *dev) -+{ -+ int state, i; -+ struct gdium_laptop_data *data = dev->private; -+ struct i2c_client *client = data->client; -+ struct input_dev *input = dev->input; -+ s32 status; -+ -+ mutex_lock(&data->mutex); -+ status = ec_read_status(client); -+ mutex_unlock(&data->mutex); -+ -+ if (status < 0) { -+ /* -+ * Don't know exactly which version of the firmware -+ * has this bug but when the power button is pressed -+ * there are i2c read errors :( -+ */ -+ if ((data->version >= 0x13) && !gkeys[1].last_state) { -+ input_event(input, EV_KEY, KEY_POWER, 1); -+ input_sync(input); -+ gkeys[1].last_state = 1; -+ } -+ return; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(gkeys); i++) { -+ state = status & gkeys[i].mask; -+ if (state != gkeys[i].last_state) { -+ gkeys[i].last_state = state; -+ /* for power key, we want power & key press/release event */ -+ if (gkeys[i].type == EV_PWR) { -+ input_event(input, EV_KEY, gkeys[i].key_code, !!state); -+ input_sync(input); -+ } -+ /* Disable wifi on key press but not key release */ -+ /* -+ * On firmware >= 0x13 the EC_STATUS_WLAN has it's -+ * original meaning of Wifi status and no more the -+ * wifi button status so we have to ignore the event -+ * on theses versions -+ */ -+ if (state && (gkeys[i].key_code == KEY_WLAN) && (data->version < 0x13)) { -+ mutex_lock(&data->mutex); -+ ec_wlan_en(client, !ec_wlan_status(client)); -+ if (gpio16) -+ gpio_set_value(SM502_WLAN_ON, !ec_wlan_status(client)); -+ mutex_unlock(&data->mutex); -+ } -+ -+ input_event(input, gkeys[i].type, gkeys[i].key_code, !!state); -+ input_sync(input); -+ } -+ } -+} -+ -+static int gdium_laptop_input_init(struct gdium_laptop_data *data) -+{ -+ struct i2c_client *client = data->client; -+ struct input_dev *input; -+ int ret, i; -+ -+ data->input_polldev = input_allocate_polled_device(); -+ if (!data->input_polldev) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ input = data->input_polldev->input; -+ input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW); -+ data->input_polldev->poll = gdium_laptop_keys_poll; -+ data->input_polldev->poll_interval = SCAN_INTERVAL; -+ data->input_polldev->private = data; -+ input->name = "gdium-keys"; -+ input->dev.parent = &client->dev; -+ -+ input->id.bustype = BUS_HOST; -+ input->id.vendor = 0x0001; -+ input->id.product = 0x0001; -+ input->id.version = 0x0100; -+ -+ for (i = 0; i < ARRAY_SIZE(gkeys); i++) -+ input_set_capability(input, gkeys[i].type, gkeys[i].key_code); -+ -+ ret = input_register_polled_device(data->input_polldev); -+ if (ret) { -+ dev_err(&client->dev, "Unable to register button device\n"); -+ goto err_poll_dev; -+ } -+ -+ return 0; -+ -+err_poll_dev: -+ input_free_polled_device(data->input_polldev); -+err: -+ return ret; -+} -+ -+static void gdium_laptop_input_exit(struct gdium_laptop_data *data) -+{ -+ input_unregister_polled_device(data->input_polldev); -+ input_free_polled_device(data->input_polldev); -+} -+ -+/**********************************************************************/ -+/* Battery management */ -+/**********************************************************************/ -+static int gdium_ac_get_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ char status; -+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_ac); -+ int ret = 0; -+ -+ if (!data) { -+ pr_err("gdium-ac: gdium_laptop_data not found\n"); -+ return -EINVAL; -+ } -+ -+ status = data->status; -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ val->intval = !!(status & EC_STATUS_ADAPT); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+#undef RET -+#define RET (val->intval) -+ -+static int gdium_battery_get_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ char status, ctrl; -+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_battery); -+ int percentage_capacity = 0, charge_now = 0, time_to_empty = 0; -+ int ret = 0, tmp; -+ -+ if (!data) { -+ pr_err("gdium-battery: gdium_laptop_data not found\n"); -+ return -EINVAL; -+ } -+ -+ status = data->status; -+ ctrl = data->ctrl; -+ switch (psp) { -+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: -+ /* uAh */ -+ RET = 5000000; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: -+ /* This formula is gotten by gnuplot with the statistic data */ -+ time_to_empty = (data->battery_level - BAT_MIN_MV + BAT_READ_ERROR_MV) * 113 - 29870; -+ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) { -+ /* seconds */ -+ RET = time_to_empty / 10; -+ break; -+ } -+ /* fall through */ -+ case POWER_SUPPLY_PROP_CHARGE_NOW: -+ case POWER_SUPPLY_PROP_CAPACITY: { -+ tmp = data->battery_level * 1000; -+ /* > BAT_MIN to avoid negative values */ -+ percentage_capacity = 0; -+ if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN)) -+ percentage_capacity = (tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN); -+ -+ if (percentage_capacity > 100) -+ percentage_capacity = 100; -+ -+ if (psp == POWER_SUPPLY_PROP_CAPACITY) { -+ RET = percentage_capacity; -+ break; -+ } -+ charge_now = 50000 * percentage_capacity; -+ if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) { -+ /* uAh */ -+ RET = charge_now; -+ break; -+ } -+ } /* fall through */ -+ case POWER_SUPPLY_PROP_STATUS: { -+ if (status & EC_STATUS_ADAPT) -+ if (ctrl & EC_CTRL_CHARGE_EN) -+ RET = POWER_SUPPLY_STATUS_CHARGING; -+ else -+ RET = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ else -+ RET = POWER_SUPPLY_STATUS_DISCHARGING; -+ -+ if (psp == POWER_SUPPLY_PROP_STATUS) -+ break; -+ /* mAh -> µA */ -+ switch (RET) { -+ case POWER_SUPPLY_STATUS_CHARGING: -+ RET = -(data->charge_cmd == 2) ? 1400000 : 250000; -+ break; -+ case POWER_SUPPLY_STATUS_DISCHARGING: -+ RET = charge_now / time_to_empty * 36000; -+ break; -+ case POWER_SUPPLY_STATUS_NOT_CHARGING: -+ default: -+ RET = 0; -+ break; -+ } -+ } break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ RET = BAT_MAX+BAT_READ_ERROR; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: -+ RET = BAT_MIN-BAT_READ_ERROR; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ /* mV -> uV */ -+ RET = data->battery_level * 1000; -+ break; -+ case POWER_SUPPLY_PROP_PRESENT: -+#if CONFIG_GDIUM_VERSION > 2 -+ RET = !!(status & EC_STATUS_BATID); -+#else -+ RET = !!(data->battery_level > BAT_VOLT_PRESENT); -+#endif -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: -+ tmp = data->battery_level * 1000; -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ if (status & EC_STATUS_BATID) { -+ if (tmp >= BAT_MAX) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; -+ if (tmp >= BAT_MAX+BAT_READ_ERROR) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; -+ } else if (tmp <= BAT_MIN+BAT_READ_ERROR) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; -+ if (tmp <= BAT_MIN) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; -+ } else -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; -+ } -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_TYPE: -+ if (ctrl & EC_CTRL_TRICKLE) -+ RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; -+ else if (ctrl & EC_CTRL_CHARGE_EN) -+ RET = POWER_SUPPLY_CHARGE_TYPE_FAST; -+ else -+ RET = POWER_SUPPLY_CHARGE_TYPE_NONE; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_MAX: -+ /* 1.4A ? */ -+ RET = 1400000; -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+#undef RET -+ -+static enum power_supply_property gdium_ac_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static enum power_supply_property gdium_battery_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_MAX, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_CAPACITY_LEVEL, -+ POWER_SUPPLY_PROP_CHARGE_TYPE, -+}; -+ -+static void gdium_laptop_battery_work(struct work_struct *work) -+{ -+ struct gdium_laptop_data *data = container_of(work, struct gdium_laptop_data, work.work); -+ struct i2c_client *client; -+ int ret; -+ char old_status, old_charge_cmd; -+ char present; -+ s32 status; -+ -+ mutex_lock(&data->mutex); -+ client = data->client; -+ status = ec_read_status(client); -+ ret = ec_read_battery(client); -+ -+ if ((status < 0) || (ret < 0)) -+ goto i2c_read_error; -+ -+ old_status = data->status; -+ old_charge_cmd = data->charge_cmd; -+ data->status = status; -+ -+ /* -+ * Charge only if : -+ * - battery present -+ * - ac adapter plugged in -+ * - battery not fully charged -+ */ -+#if CONFIG_GDIUM_VERSION > 2 -+ present = !!(data->status & EC_STATUS_BATID); -+#else -+ present = !!(ret > BAT_VOLT_PRESENT); -+#endif -+ data->battery_level = 0; -+ if (present) { -+ data->battery_level = (unsigned int)ret; -+ if (data->status & EC_STATUS_ADAPT) -+ data->battery_level -= BAT_READ_ERROR_MV; -+ } -+ -+ data->charge_cmd = 0; -+ if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level <= BAT_MAX_MV)) -+ data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3; -+ -+ ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1); -+ -+ /* -+ * data->ctrl must be set _after_ calling ec_charge_en as this will change the -+ * control register content -+ */ -+ data->ctrl = ec_read_ctrl(client); -+ -+ if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) { -+ power_supply_changed(&data->gdium_ac); -+ /* Send charging/discharging state change */ -+ power_supply_changed(&data->gdium_battery); -+ } else if ((data->status & EC_STATUS_ADAPT) && -+ ((old_charge_cmd&2) != (data->charge_cmd&2))) -+ power_supply_changed(&data->gdium_battery); -+ -+i2c_read_error: -+ mutex_unlock(&data->mutex); -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+} -+ -+static int gdium_laptop_battery_init(struct gdium_laptop_data *data) -+{ -+ int ret; -+ -+ data->bat_pdev = platform_device_register_simple("gdium-battery", 0, NULL, 0); -+ if (IS_ERR(data->bat_pdev)) -+ return PTR_ERR(data->bat_pdev); -+ -+ data->gdium_battery.name = data->bat_pdev->name; -+ data->gdium_battery.properties = gdium_battery_props; -+ data->gdium_battery.num_properties = ARRAY_SIZE(gdium_battery_props); -+ data->gdium_battery.get_property = gdium_battery_get_props; -+ data->gdium_battery.use_for_apm = 1; -+ -+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery); -+ if (ret) -+ goto err_platform; -+ -+ data->gdium_ac.name = "gdium-ac"; -+ data->gdium_ac.type = POWER_SUPPLY_TYPE_MAINS; -+ data->gdium_ac.properties = gdium_ac_props; -+ data->gdium_ac.num_properties = ARRAY_SIZE(gdium_ac_props); -+ data->gdium_ac.get_property = gdium_ac_get_props; -+/* data->gdium_ac.use_for_apm_ac = 1, */ -+ -+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac); -+ if (ret) -+ goto err_battery; -+ -+ if (!ec) { -+ INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work); -+ data->workqueue = create_singlethread_workqueue("gdium-battery-work"); -+ if (!data->workqueue) { -+ ret = -ESRCH; -+ goto err_work; -+ } -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+ } -+ -+ return 0; -+ -+err_work: -+err_battery: -+ power_supply_unregister(&data->gdium_battery); -+err_platform: -+ platform_device_unregister(data->bat_pdev); -+ -+ return ret; -+} -+static void gdium_laptop_battery_exit(struct gdium_laptop_data *data) -+{ -+ if (!ec) { -+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); -+ destroy_workqueue(data->workqueue); -+ } -+ power_supply_unregister(&data->gdium_battery); -+ power_supply_unregister(&data->gdium_ac); -+ platform_device_unregister(data->bat_pdev); -+} -+ -+/* Debug fs */ -+static int gdium_laptop_regs_show(struct seq_file *s, void *p) -+{ -+ struct gdium_laptop_data *data = s->private; -+ struct i2c_client *client = data->client; -+ -+ mutex_lock(&data->mutex); -+ seq_printf(s, "Version : 0x%02x\n", (unsigned char)ec_read_version(client)); -+ seq_printf(s, "Status : 0x%02x\n", (unsigned char)ec_read_status(client)); -+ seq_printf(s, "Ctrl : 0x%02x\n", (unsigned char)ec_read_ctrl(client)); -+ seq_printf(s, "Sign : 0x%02x\n", (unsigned char)ec_read_sign(client)); -+ seq_printf(s, "Bat Lo : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_LOW)); -+ seq_printf(s, "Bat Hi : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH)); -+ seq_printf(s, "Battery : %d uV\n", (unsigned int)ec_read_battery(client) * 1000); -+ seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", data->charge_cmd & 1 ? "T" : " "); -+ -+ mutex_unlock(&data->mutex); -+ return 0; -+} -+ -+static int gdium_laptop_regs_open(struct inode *inode, -+ struct file *file) -+{ -+ return single_open(file, gdium_laptop_regs_show, inode->i_private); -+} -+ -+static const struct file_operations gdium_laptop_regs_fops = { -+ .open = gdium_laptop_regs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+ .owner = THIS_MODULE, -+}; -+ -+ -+static int gdium_laptop_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct gdium_laptop_data *data; -+ int ret; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -+ dev_err(&client->dev, -+ "%s: no smbus_byte support !\n", __func__); -+ return -ENODEV; -+ } -+ -+ data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(client, data); -+ data->client = client; -+ mutex_init(&data->mutex); -+ -+ ret = ec_read_version(client); -+ if (ret < 0) -+ goto err_alloc; -+ -+ data->version = (unsigned char)ret; -+ -+ ret = gdium_laptop_input_init(data); -+ if (ret) -+ goto err_alloc; -+ -+ ret = gdium_laptop_battery_init(data); -+ if (ret) -+ goto err_input; -+ -+ -+ if (!ec) { -+ ret = ec_write_sign(client, EC_SIGN_OS); -+ if (ret) -+ goto err_sign; -+ } -+ -+ if (gpio16) { -+ ret = gpio_request(SM502_WLAN_ON, "wlan-on"); -+ if (ret < 0) -+ goto err_sign; -+ gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client)); -+ gpio_direction_output(SM502_WLAN_ON, 1); -+ } -+ -+ dev_info(&client->dev, "Found firmware 0x%02x\n", data->version); -+ data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO, -+ NULL, data, &gdium_laptop_regs_fops); -+ -+ return 0; -+ -+err_sign: -+ gdium_laptop_battery_exit(data); -+err_input: -+ gdium_laptop_input_exit(data); -+err_alloc: -+ kfree(data); -+ return ret; -+} -+ -+static int gdium_laptop_remove(struct i2c_client *client) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (gpio16) -+ gpio_free(SM502_WLAN_ON); -+ ec_write_sign(client, EC_SIGN_EC); -+ if (data->debugfs) -+ debugfs_remove(data->debugfs); -+ -+ gdium_laptop_battery_exit(data); -+ gdium_laptop_input_exit(data); -+ -+ kfree(data); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (!ec) -+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); -+ return 0; -+} -+ -+static int gdium_laptop_resume(struct i2c_client *client) -+{ -+ struct gdium_laptop_data *data = i2c_get_clientdata(client); -+ -+ if (!ec) -+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); -+ return 0; -+} -+#else -+#define gdium_laptop_suspend NULL -+#define gdium_laptop_resume NULL -+#endif -+static const struct i2c_device_id gdium_id[] = { -+ { "gdium-laptop" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(i2c, gdium_id); -+ -+static struct i2c_driver gdium_laptop_driver = { -+ .driver = { -+ .name = "gdium-laptop", -+ .owner = THIS_MODULE, -+ }, -+ .probe = gdium_laptop_probe, -+ .remove = gdium_laptop_remove, -+ .shutdown = gdium_laptop_remove, -+ .suspend = gdium_laptop_suspend, -+ .resume = gdium_laptop_resume, -+ .id_table = gdium_id, -+}; -+ -+static int __init gdium_laptop_init(void) -+{ -+ return i2c_add_driver(&gdium_laptop_driver); -+} -+ -+static void __exit gdium_laptop_exit(void) -+{ -+ i2c_del_driver(&gdium_laptop_driver); -+} -+ -+module_init(gdium_laptop_init); -+module_exit(gdium_laptop_exit); -+ -+MODULE_AUTHOR("Arnaud Patard "); -+MODULE_DESCRIPTION("Gdium laptop extras"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/lynloong_pc.c b/drivers/platform/mips/lynloong_pc.c -new file mode 100644 -index 0000000..68f29e4 ---- /dev/null -+++ b/drivers/platform/mips/lynloong_pc.c -@@ -0,0 +1,515 @@ -+/* -+ * Driver for LynLoong PC extras -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin , Xiang Yu -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include /* for backlight subdriver */ -+#include -+#include /* for video output subdriver */ -+#include /* for suspend support */ -+ -+#include -+#include -+ -+#include -+ -+static u32 gpio_base, mfgpt_base; -+ -+static void set_gpio_reg_high(int gpio, int reg) -+{ -+ u32 val; -+ -+ val = inl(gpio_base + reg); -+ val |= (1 << gpio); -+ val &= ~(1 << (16 + gpio)); -+ outl(val, gpio_base + reg); -+ mmiowb(); -+} -+ -+static void set_gpio_reg_low(int gpio, int reg) -+{ -+ u32 val; -+ -+ val = inl(gpio_base + reg); -+ val |= (1 << (16 + gpio)); -+ val &= ~(1 << gpio); -+ outl(val, gpio_base + reg); -+ mmiowb(); -+} -+ -+static void set_gpio_output_low(int gpio) -+{ -+ set_gpio_reg_high(gpio, GPIOL_OUT_EN); -+ set_gpio_reg_low(gpio, GPIOL_OUT_VAL); -+} -+ -+static void set_gpio_output_high(int gpio) -+{ -+ set_gpio_reg_high(gpio, GPIOL_OUT_EN); -+ set_gpio_reg_high(gpio, GPIOL_OUT_VAL); -+} -+ -+/* backlight subdriver */ -+ -+#define MAX_BRIGHTNESS 100 -+#define DEFAULT_BRIGHTNESS 50 -+#define MIN_BRIGHTNESS 0 -+static unsigned int level; -+ -+DEFINE_SPINLOCK(backlight_lock); -+/* Tune the brightness */ -+static void setup_mfgpt2(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&backlight_lock, flags); -+ -+ /* Set MFGPT2 comparator 1,2 */ -+ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1); -+ outw(MAX_BRIGHTNESS, MFGPT2_CMP2); -+ /* Clear MFGPT2 UP COUNTER */ -+ outw(0, MFGPT2_CNT); -+ /* Enable counter, compare mode, 32k */ -+ outw(0x8280, MFGPT2_SETUP); -+ -+ spin_unlock_irqrestore(&backlight_lock, flags); -+} -+ -+static int lynloong_set_brightness(struct backlight_device *bd) -+{ -+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && -+ bd->props.power == FB_BLANK_UNBLANK) ? -+ bd->props.brightness : 0; -+ -+ if (level > MAX_BRIGHTNESS) -+ level = MAX_BRIGHTNESS; -+ else if (level < MIN_BRIGHTNESS) -+ level = MIN_BRIGHTNESS; -+ -+ setup_mfgpt2(); -+ -+ return 0; -+} -+ -+static int lynloong_get_brightness(struct backlight_device *bd) -+{ -+ return level; -+} -+ -+static struct backlight_ops backlight_ops = { -+ .get_brightness = lynloong_get_brightness, -+ .update_status = lynloong_set_brightness, -+}; -+ -+static struct backlight_device *lynloong_backlight_dev; -+ -+static int lynloong_backlight_init(void) -+{ -+ int ret; -+ u32 hi; -+ struct backlight_properties props; -+ -+ /* Get gpio_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); -+ /* Get mfgpt_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base); -+ /* Get gpio_base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); -+ -+ /* Select for mfgpt */ -+ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL); -+ /* Enable brightness controlling */ -+ set_gpio_output_high(7); -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.max_brightness = MAX_BRIGHTNESS; -+ props.type = BACKLIGHT_PLATFORM; -+ lynloong_backlight_dev = backlight_device_register("backlight0", NULL, -+ NULL, &backlight_ops, &props); -+ -+ if (IS_ERR(lynloong_backlight_dev)) { -+ ret = PTR_ERR(lynloong_backlight_dev); -+ return ret; -+ } -+ -+ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS; -+ backlight_update_status(lynloong_backlight_dev); -+ -+ return 0; -+} -+ -+static void lynloong_backlight_exit(void) -+{ -+ if (lynloong_backlight_dev) { -+ backlight_device_unregister(lynloong_backlight_dev); -+ lynloong_backlight_dev = NULL; -+ } -+ /* Disable brightness controlling */ -+ set_gpio_output_low(7); -+} -+ -+/* video output driver */ -+static int vo_status = 1; -+ -+static int lcd_video_output_get(struct output_device *od) -+{ -+ return vo_status; -+} -+ -+static int lcd_video_output_set(struct output_device *od) -+{ -+ int i; -+ unsigned long status; -+ -+ status = !!od->request_state; -+ -+ if (status == 0) { -+ /* Set the current status as off */ -+ vo_status = 0; -+ /* Turn off the backlight */ -+ set_gpio_output_low(11); -+ for (i = 0; i < 0x500; i++) -+ delay(); -+ /* Turn off the LCD */ -+ set_gpio_output_high(8); -+ } else { -+ /* Turn on the LCD */ -+ set_gpio_output_low(8); -+ for (i = 0; i < 0x500; i++) -+ delay(); -+ /* Turn on the backlight */ -+ set_gpio_output_high(11); -+ /* Set the current status as on */ -+ vo_status = 1; -+ } -+ -+ return 0; -+} -+ -+static struct output_properties lcd_output_properties = { -+ .set_state = lcd_video_output_set, -+ .get_status = lcd_video_output_get, -+}; -+ -+static struct output_device *lcd_output_dev; -+ -+static void lynloong_lcd_vo_set(int status) -+{ -+ lcd_output_dev->request_state = status; -+ lcd_video_output_set(lcd_output_dev); -+} -+ -+static int lynloong_vo_init(void) -+{ -+ int ret; -+ -+ /* Register video output device: lcd */ -+ lcd_output_dev = video_output_register("LCD", NULL, NULL, -+ &lcd_output_properties); -+ -+ if (IS_ERR(lcd_output_dev)) { -+ ret = PTR_ERR(lcd_output_dev); -+ lcd_output_dev = NULL; -+ return ret; -+ } -+ /* Ensure LCD is on by default */ -+ lynloong_lcd_vo_set(1); -+ -+ return 0; -+} -+ -+static void lynloong_vo_exit(void) -+{ -+ if (lcd_output_dev) { -+ video_output_unregister(lcd_output_dev); -+ lcd_output_dev = NULL; -+ } -+} -+ -+/* suspend support */ -+ -+#ifdef CONFIG_PM -+ -+static u32 smb_base; -+ -+/* I2C operations */ -+ -+static int i2c_wait(void) -+{ -+ char c; -+ int i; -+ -+ udelay(1000); -+ for (i = 0; i < 20; i++) { -+ c = inb(smb_base | SMB_STS); -+ if (c & (SMB_STS_BER | SMB_STS_NEGACK)) -+ return -1; -+ if (c & SMB_STS_SDAST) -+ return 0; -+ udelay(100); -+ } -+ return -2; -+} -+ -+static void i2c_read_single(int addr, int regNo, char *value) -+{ -+ unsigned char c; -+ -+ /* Start condition */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ -+ /* Send slave address */ -+ outb(addr & 0xfe, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Send register index */ -+ outb(regNo, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Start condition again */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ -+ /* Send salve address again */ -+ outb(1 | addr, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Acknowledge smbus */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); -+ -+ /* Read data */ -+ *value = inb(smb_base | SMB_SDA); -+ -+ /* Stop condition */ -+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); -+ i2c_wait(); -+} -+ -+static void i2c_write_single(int addr, int regNo, char value) -+{ -+ unsigned char c; -+ -+ /* Start condition */ -+ c = inb(smb_base | SMB_CTRL1); -+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); -+ i2c_wait(); -+ /* Send slave address */ -+ outb(addr & 0xfe, smb_base | SMB_SDA); -+ i2c_wait();; -+ -+ /* Send register index */ -+ outb(regNo, smb_base | SMB_SDA); -+ i2c_wait(); -+ -+ /* Write data */ -+ outb(value, smb_base | SMB_SDA); -+ i2c_wait(); -+ /* Stop condition */ -+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); -+ i2c_wait(); -+} -+ -+static void stop_clock(int clk_reg, int clk_sel) -+{ -+ u8 value; -+ -+ i2c_read_single(0xd3, clk_reg, &value); -+ value &= ~(1 << clk_sel); -+ i2c_write_single(0xd2, clk_reg, value); -+} -+ -+static void enable_clock(int clk_reg, int clk_sel) -+{ -+ u8 value; -+ -+ i2c_read_single(0xd3, clk_reg, &value); -+ value |= (1 << clk_sel); -+ i2c_write_single(0xd2, clk_reg, value); -+} -+ -+static char cached_clk_freq; -+static char cached_pci_fixed_freq; -+ -+static void decrease_clk_freq(void) -+{ -+ char value; -+ -+ i2c_read_single(0xd3, 1, &value); -+ cached_clk_freq = value; -+ -+ /* Select frequency by software */ -+ value |= (1 << 1); -+ /* CPU, 3V66, PCI : 100, 66, 33(1) */ -+ value |= (1 << 2); -+ i2c_write_single(0xd2, 1, value); -+ -+ /* Cache the pci frequency */ -+ i2c_read_single(0xd3, 14, &value); -+ cached_pci_fixed_freq = value; -+ -+ /* Enable PCI fix mode */ -+ value |= (1 << 5); -+ /* 3V66, PCI : 64MHz, 32MHz */ -+ value |= (1 << 3); -+ i2c_write_single(0xd2, 14, value); -+ -+} -+ -+static void resume_clk_freq(void) -+{ -+ i2c_write_single(0xd2, 1, cached_clk_freq); -+ i2c_write_single(0xd2, 14, cached_pci_fixed_freq); -+} -+ -+static void stop_clocks(void) -+{ -+ /* CPU Clock Register */ -+ stop_clock(2, 5); /* not used */ -+ stop_clock(2, 6); /* not used */ -+ stop_clock(2, 7); /* not used */ -+ -+ /* PCI Clock Register */ -+ stop_clock(3, 1); /* 8100 */ -+ stop_clock(3, 5); /* SIS */ -+ stop_clock(3, 0); /* not used */ -+ stop_clock(3, 6); /* not used */ -+ -+ /* PCI 48M Clock Register */ -+ stop_clock(4, 6); /* USB grounding */ -+ stop_clock(4, 5); /* REF(5536_14M) */ -+ -+ /* 3V66 Control Register */ -+ stop_clock(5, 0); /* VCH_CLK..., grounding */ -+} -+ -+static void enable_clocks(void) -+{ -+ enable_clock(3, 1); /* 8100 */ -+ enable_clock(3, 5); /* SIS */ -+ -+ enable_clock(4, 6); -+ enable_clock(4, 5); /* REF(5536_14M) */ -+ -+ enable_clock(5, 0); /* VCH_CLOCK, grounding */ -+} -+ -+static int lynloong_suspend(struct device *dev) -+{ -+ /* Disable AMP */ -+ set_gpio_output_high(6); -+ /* Turn off LCD */ -+ lynloong_lcd_vo_set(0); -+ -+ /* Stop the clocks of some devices */ -+ stop_clocks(); -+ -+ /* Decrease the external clock frequency */ -+ decrease_clk_freq(); -+ -+ return 0; -+} -+ -+static int lynloong_resume(struct device *dev) -+{ -+ /* Turn on the LCD */ -+ lynloong_lcd_vo_set(1); -+ -+ /* Resume clock frequency, enable the relative clocks */ -+ resume_clk_freq(); -+ enable_clocks(); -+ -+ /* Enable AMP */ -+ set_gpio_output_low(6); -+ -+ return 0; -+} -+ -+static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend, -+ lynloong_resume); -+#endif /* !CONFIG_PM */ -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "lynloong_pc", -+ }, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver platform_driver = { -+ .driver = { -+ .name = "lynloong_pc", -+ .owner = THIS_MODULE, -+#ifdef CONFIG_PM -+ .pm = &lynloong_pm_ops, -+#endif -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int __init lynloong_init(void) -+{ -+ int ret; -+ -+ pr_info("LynLoong platform specific driver loaded.\n"); -+ -+ /* Register platform stuff */ -+ ret = platform_driver_register(&platform_driver); -+ if (ret) { -+ pr_err("Failed to register LynLoong platform driver.\n"); -+ return ret; -+ } -+ -+ ret = lynloong_backlight_init(); -+ if (ret) { -+ pr_err("Failed to register LynLoong backlight driver.\n"); -+ return ret; -+ } -+ -+ ret = lynloong_vo_init(); -+ if (ret) { -+ pr_err("Failed to register LynLoong backlight driver.\n"); -+ lynloong_vo_exit(); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void __exit lynloong_exit(void) -+{ -+ lynloong_vo_exit(); -+ lynloong_backlight_exit(); -+ platform_driver_unregister(&platform_driver); -+ -+ pr_info("LynLoong platform specific driver unloaded.\n"); -+} -+ -+module_init(lynloong_init); -+module_exit(lynloong_exit); -+ -+MODULE_AUTHOR("Wu Zhangjin ; Xiang Yu "); -+MODULE_DESCRIPTION("LynLoong PC driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/yeeloong_ecrom.c b/drivers/platform/mips/yeeloong_ecrom.c -new file mode 100644 -index 0000000..1bfe4cf ---- /dev/null -+++ b/drivers/platform/mips/yeeloong_ecrom.c -@@ -0,0 +1,944 @@ -+/* -+ * Driver for flushing/dumping ROM of EC on YeeLoong laptop -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: liujl -+ * -+ * NOTE : -+ * The EC resources accessing and programming are supported. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define EC_MISC_DEV "ec_misc" -+#define EC_IOC_MAGIC 'E' -+ -+/* ec registers range */ -+#define EC_MAX_REGADDR 0xFFFF -+#define EC_MIN_REGADDR 0xF000 -+#define EC_RAM_ADDR 0xF800 -+ -+/* version burned address */ -+#define VER_ADDR 0xf7a1 -+#define VER_MAX_SIZE 7 -+#define EC_ROM_MAX_SIZE 0x10000 -+ -+/* ec internal register */ -+#define REG_POWER_MODE 0xF710 -+#define FLAG_NORMAL_MODE 0x00 -+#define FLAG_IDLE_MODE 0x01 -+#define FLAG_RESET_MODE 0x02 -+ -+/* ec update program flag */ -+#define PROGRAM_FLAG_NONE 0x00 -+#define PROGRAM_FLAG_IE 0x01 -+#define PROGRAM_FLAG_ROM 0x02 -+ -+/* XBI relative registers */ -+#define REG_XBISEG0 0xFEA0 -+#define REG_XBISEG1 0xFEA1 -+#define REG_XBIRSV2 0xFEA2 -+#define REG_XBIRSV3 0xFEA3 -+#define REG_XBIRSV4 0xFEA4 -+#define REG_XBICFG 0xFEA5 -+#define REG_XBICS 0xFEA6 -+#define REG_XBIWE 0xFEA7 -+#define REG_XBISPIA0 0xFEA8 -+#define REG_XBISPIA1 0xFEA9 -+#define REG_XBISPIA2 0xFEAA -+#define REG_XBISPIDAT 0xFEAB -+#define REG_XBISPICMD 0xFEAC -+#define REG_XBISPICFG 0xFEAD -+#define REG_XBISPIDATR 0xFEAE -+#define REG_XBISPICFG2 0xFEAF -+ -+/* commands definition for REG_XBISPICMD */ -+#define SPICMD_WRITE_STATUS 0x01 -+#define SPICMD_BYTE_PROGRAM 0x02 -+#define SPICMD_READ_BYTE 0x03 -+#define SPICMD_WRITE_DISABLE 0x04 -+#define SPICMD_READ_STATUS 0x05 -+#define SPICMD_WRITE_ENABLE 0x06 -+#define SPICMD_HIGH_SPEED_READ 0x0B -+#define SPICMD_POWER_DOWN 0xB9 -+#define SPICMD_SST_EWSR 0x50 -+#define SPICMD_SST_SEC_ERASE 0x20 -+#define SPICMD_SST_BLK_ERASE 0x52 -+#define SPICMD_SST_CHIP_ERASE 0x60 -+#define SPICMD_FRDO 0x3B -+#define SPICMD_SEC_ERASE 0xD7 -+#define SPICMD_BLK_ERASE 0xD8 -+#define SPICMD_CHIP_ERASE 0xC7 -+ -+/* bits definition for REG_XBISPICFG */ -+#define SPICFG_AUTO_CHECK 0x01 -+#define SPICFG_SPI_BUSY 0x02 -+#define SPICFG_DUMMY_READ 0x04 -+#define SPICFG_EN_SPICMD 0x08 -+#define SPICFG_LOW_SPICS 0x10 -+#define SPICFG_EN_SHORT_READ 0x20 -+#define SPICFG_EN_OFFSET_READ 0x40 -+#define SPICFG_EN_FAST_READ 0x80 -+ -+/* watchdog timer registers */ -+#define REG_WDTCFG 0xfe80 -+#define REG_WDTPF 0xfe81 -+#define REG_WDT 0xfe82 -+ -+/* lpc configure register */ -+#define REG_LPCCFG 0xfe95 -+ -+/* 8051 reg */ -+#define REG_PXCFG 0xff14 -+ -+/* Fan register in KB3310 */ -+#define REG_ECFAN_SPEED_LEVEL 0xf4e4 -+#define REG_ECFAN_SWITCH 0xf4d2 -+ -+/* the ec flash rom id number */ -+#define EC_ROM_PRODUCT_ID_SPANSION 0x01 -+#define EC_ROM_PRODUCT_ID_MXIC 0xC2 -+#define EC_ROM_PRODUCT_ID_AMIC 0x37 -+#define EC_ROM_PRODUCT_ID_EONIC 0x1C -+ -+/* misc ioctl operations */ -+#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int) -+#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int) -+#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int) -+#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int) -+#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int) -+ -+/* start address for programming of EC content or IE */ -+/* ec running code start address */ -+#define EC_START_ADDR 0x00000000 -+/* ec information element storing address */ -+#define IE_START_ADDR 0x00020000 -+ -+/* EC state */ -+#define EC_STATE_IDLE 0x00 /* ec in idle state */ -+#define EC_STATE_BUSY 0x01 /* ec in busy state */ -+ -+/* timeout value for programming */ -+#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */ -+/* command checkout timeout including cmd to port or state flag check */ -+#define EC_CMD_TIMEOUT 0x1000 -+#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */ -+#define EC_MAX_DELAY_UNIT (10) /* every time for polling */ -+#define SPI_FINISH_WAIT_TIME 10 -+/* EC content max size */ -+#define EC_CONTENT_MAX_SIZE (64 * 1024) -+#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR) -+ -+/* the register operation access struct */ -+struct ec_reg { -+ u32 addr; /* the address of kb3310 registers */ -+ u8 val; /* the register value */ -+}; -+ -+struct ec_info { -+ u32 start_addr; -+ u32 size; -+ u8 *buf; -+}; -+ -+/* open for using rom protection action */ -+#define EC_ROM_PROTECTION -+ -+/* enable the chip reset mode */ -+static int ec_init_reset_mode(void) -+{ -+ int timeout; -+ unsigned char status = 0; -+ int ret = 0; -+ -+ /* make chip goto reset mode */ -+ ret = ec_query_seq(CMD_INIT_RESET_MODE); -+ if (ret < 0) { -+ printk(KERN_ERR "ec init reset mode failed.\n"); -+ goto out; -+ } -+ -+ /* make the action take active */ -+ timeout = EC_CMD_TIMEOUT; -+ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; -+ while (timeout--) { -+ if (status) { -+ udelay(EC_REG_DELAY); -+ break; -+ } -+ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; -+ udelay(EC_REG_DELAY); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR "ec rom fixup : can't check reset status.\n"); -+ ret = -EINVAL; -+ } else -+ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout, -+ EC_CMD_TIMEOUT - timeout, status); -+ -+ /* set MCU to reset mode */ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_PXCFG); -+ status |= (1 << 0); -+ ec_write(REG_PXCFG, status); -+ udelay(EC_REG_DELAY); -+ -+ /* disable FWH/LPC */ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_LPCCFG); -+ status &= ~(1 << 7); -+ ec_write(REG_LPCCFG, status); -+ udelay(EC_REG_DELAY); -+ -+ printk(KERN_INFO "entering reset mode ok..............\n"); -+ -+ out: -+ return ret; -+} -+ -+/* make ec exit from reset mode */ -+static void ec_exit_reset_mode(void) -+{ -+ unsigned char regval; -+ -+ udelay(EC_REG_DELAY); -+ regval = ec_read(REG_LPCCFG); -+ regval |= (1 << 7); -+ ec_write(REG_LPCCFG, regval); -+ regval = ec_read(REG_PXCFG); -+ regval &= ~(1 << 0); -+ ec_write(REG_PXCFG, regval); -+ printk(KERN_INFO "exit reset mode ok..................\n"); -+ -+ return; -+} -+ -+/* make ec disable WDD */ -+static void ec_disable_WDD(void) -+{ -+ unsigned char status; -+ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_WDTCFG); -+ ec_write(REG_WDTPF, 0x03); -+ ec_write(REG_WDTCFG, (status & 0x80) | 0x48); -+ printk(KERN_INFO "Disable WDD ok..................\n"); -+ -+ return; -+} -+ -+/* make ec enable WDD */ -+static void ec_enable_WDD(void) -+{ -+ unsigned char status; -+ -+ udelay(EC_REG_DELAY); -+ status = ec_read(REG_WDTCFG); -+ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */ -+ ec_write(REG_WDTCFG, (status & 0x80) | 0x03); -+ printk(KERN_INFO "Enable WDD ok..................\n"); -+ -+ return; -+} -+ -+/* make ec goto idle mode */ -+static int ec_init_idle_mode(void) -+{ -+ int timeout; -+ unsigned char status = 0; -+ int ret = 0; -+ -+ ec_query_seq(CMD_INIT_IDLE_MODE); -+ -+ /* make the action take active */ -+ timeout = EC_CMD_TIMEOUT; -+ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; -+ while (timeout--) { -+ if (status) { -+ udelay(EC_REG_DELAY); -+ break; -+ } -+ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; -+ udelay(EC_REG_DELAY); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR "ec rom fixup : can't check out the status.\n"); -+ ret = -EINVAL; -+ } else -+ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout, -+ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE)); -+ -+ printk(KERN_INFO "entering idle mode ok...................\n"); -+ -+ return ret; -+} -+ -+/* make ec exit from idle mode */ -+static int ec_exit_idle_mode(void) -+{ -+ -+ ec_query_seq(CMD_EXIT_IDLE_MODE); -+ -+ printk(KERN_INFO "exit idle mode ok...................\n"); -+ -+ return 0; -+} -+ -+static int ec_instruction_cycle(void) -+{ -+ unsigned long timeout; -+ int ret = 0; -+ -+ timeout = EC_FLASH_TIMEOUT; -+ while (timeout-- >= 0) { -+ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY)) -+ break; -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ return ret; -+} -+ -+/* To see if the ec is in busy state or not. */ -+static inline int ec_flash_busy(unsigned long timeout) -+{ -+ /* assurance the first command be going to rom */ -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+#if 1 -+ timeout = timeout / EC_MAX_DELAY_UNIT; -+ while (timeout-- > 0) { -+ /* check the rom's status of busy flag */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) -+ return EC_STATE_IDLE; -+ udelay(EC_MAX_DELAY_UNIT); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_FLASH_BUSY : timeout for check rom flag.\n"); -+ return EC_STATE_BUSY; -+ } -+#else -+ /* check the rom's status of busy flag */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (ec_instruction_cycle() < 0) -+ return EC_STATE_BUSY; -+ -+ timeout = timeout / EC_MAX_DELAY_UNIT; -+ while (timeout-- > 0) { -+ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) -+ return EC_STATE_IDLE; -+ udelay(EC_MAX_DELAY_UNIT); -+ } -+ if (timeout <= 0) { -+ printk(KERN_ERR -+ "EC_FLASH_BUSY : timeout for check rom flag.\n"); -+ return EC_STATE_BUSY; -+ } -+#endif -+ -+ return EC_STATE_IDLE; -+} -+ -+static int rom_instruction_cycle(unsigned char cmd) -+{ -+ unsigned long timeout = 0; -+ -+ switch (cmd) { -+ case SPICMD_READ_STATUS: -+ case SPICMD_WRITE_ENABLE: -+ case SPICMD_WRITE_DISABLE: -+ case SPICMD_READ_BYTE: -+ case SPICMD_HIGH_SPEED_READ: -+ timeout = 0; -+ break; -+ case SPICMD_WRITE_STATUS: -+ timeout = 300 * 1000; -+ break; -+ case SPICMD_BYTE_PROGRAM: -+ timeout = 5 * 1000; -+ break; -+ case SPICMD_SST_SEC_ERASE: -+ case SPICMD_SEC_ERASE: -+ timeout = 1000 * 1000; -+ break; -+ case SPICMD_SST_BLK_ERASE: -+ case SPICMD_BLK_ERASE: -+ timeout = 3 * 1000 * 1000; -+ break; -+ case SPICMD_SST_CHIP_ERASE: -+ case SPICMD_CHIP_ERASE: -+ timeout = 20 * 1000 * 1000; -+ break; -+ default: -+ timeout = EC_SPICMD_STANDARD_TIMEOUT; -+ } -+ if (timeout == 0) -+ return ec_instruction_cycle(); -+ if (timeout < EC_SPICMD_STANDARD_TIMEOUT) -+ timeout = EC_SPICMD_STANDARD_TIMEOUT; -+ -+ return ec_flash_busy(timeout); -+} -+ -+/* delay for start/stop action */ -+static void delay_spi(int n) -+{ -+ while (n--) -+ inb(EC_IO_PORT_HIGH); -+} -+ -+/* start the action to spi rom function */ -+static void ec_start_spi(void) -+{ -+ unsigned char val; -+ -+ delay_spi(SPI_FINISH_WAIT_TIME); -+ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK; -+ ec_write(REG_XBISPICFG, val); -+ delay_spi(SPI_FINISH_WAIT_TIME); -+} -+ -+/* stop the action to spi rom function */ -+static void ec_stop_spi(void) -+{ -+ unsigned char val; -+ -+ delay_spi(SPI_FINISH_WAIT_TIME); -+ val = -+ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK)); -+ ec_write(REG_XBISPICFG, val); -+ delay_spi(SPI_FINISH_WAIT_TIME); -+} -+ -+/* read one byte from xbi interface */ -+static int ec_read_byte(unsigned int addr, unsigned char *byte) -+{ -+ int ret = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* write the address */ -+ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); -+ /* start action */ -+ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ); -+ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ *byte = ec_read(REG_XBISPIDAT); -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* write one byte to ec rom */ -+static int ec_write_byte(unsigned int addr, unsigned char byte) -+{ -+ int ret = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* write the address */ -+ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); -+ ec_write(REG_XBISPIDAT, byte); -+ /* start action */ -+ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM); -+ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* unprotect SPI ROM */ -+/* EC_ROM_unprotect function code */ -+static int EC_ROM_unprotect(void) -+{ -+ unsigned char status; -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); -+ return 1; -+ } -+ -+ /* unprotect the status register of rom */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n"); -+ return 1; -+ } -+ status = ec_read(REG_XBISPIDAT); -+ ec_write(REG_XBISPIDAT, status & 0x02); -+ if (ec_instruction_cycle() < 0) { -+ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n"); -+ return 1; -+ } -+ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); -+ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n"); -+ return 1; -+ } -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/* erase one block or chip or sector as needed */ -+static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr) -+{ -+ unsigned char status; -+ int ret = 0, i = 0; -+ int unprotect_count = 3; -+ int check_flag = 0; -+ -+ /* enable spicmd writing. */ -+ ec_start_spi(); -+ -+#ifdef EC_ROM_PROTECTION -+ /* added for re-check SPICMD_READ_STATUS */ -+ while (unprotect_count-- > 0) { -+ if (EC_ROM_unprotect()) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* first time:500ms --> 5.5sec -->10.5sec */ -+ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++) -+ udelay(50000); -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) -+ == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); -+ } else { -+ status = ec_read(REG_XBISPIDAT); -+ printk(KERN_INFO "Read unprotect status : 0x%x\n", -+ status); -+ if ((status & 0x1C) == 0x00) { -+ printk(KERN_INFO -+ "Read unprotect status OK1 : 0x%x\n", -+ status & 0x1C); -+ check_flag = 1; -+ break; -+ } -+ } -+ } -+ -+ if (!check_flag) { -+ printk(KERN_INFO "SPI ROM unprotect fail.\n"); -+ return 1; -+ } -+#endif -+ -+ /* block address fill */ -+ if (erase_cmd == SPICMD_BLK_ERASE) { -+ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16); -+ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8); -+ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0); -+ } -+ -+ /* erase the whole chip first */ -+ ec_write(REG_XBISPICMD, erase_cmd); -+ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) { -+ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ out: -+ /* disable spicmd writing. */ -+ ec_stop_spi(); -+ -+ return ret; -+} -+ -+/* update the whole rom content with H/W mode -+ * PLEASE USING ec_unit_erase() FIRSTLY -+ */ -+static int ec_program_rom(struct ec_info *info, int flag) -+{ -+ unsigned int addr = 0; -+ unsigned long size = 0; -+ unsigned char *ptr = NULL; -+ unsigned char data; -+ unsigned char val = 0; -+ int ret = 0; -+ int i, j; -+ unsigned char status; -+ -+ /* modify for program serial No. -+ * set IE_START_ADDR & use idle mode, -+ * disable WDD -+ */ -+ if (flag == PROGRAM_FLAG_ROM) { -+ ret = ec_init_reset_mode(); -+ addr = info->start_addr + EC_START_ADDR; -+ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n"); -+ } else if (flag == PROGRAM_FLAG_IE) { -+ ret = ec_init_idle_mode(); -+ ec_disable_WDD(); -+ addr = info->start_addr + IE_START_ADDR; -+ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n"); -+ } else { -+ return 0; -+ } -+ -+ if (ret < 0) { -+ if (flag == PROGRAM_FLAG_IE) -+ ec_enable_WDD(); -+ return ret; -+ } -+ -+ size = info->size; -+ ptr = info->buf; -+ printk(KERN_INFO "starting update ec ROM..............\n"); -+ -+ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr); -+ if (ret) { -+ printk(KERN_ERR "program ec : erase block failed.\n"); -+ goto out; -+ } -+ printk(KERN_ERR "program ec : erase block OK.\n"); -+ -+ i = 0; -+ while (i < size) { -+ data = *(ptr + i); -+ ec_write_byte(addr, data); -+ ec_read_byte(addr, &val); -+ if (val != data) { -+ ec_write_byte(addr, data); -+ ec_read_byte(addr, &val); -+ if (val != data) { -+ printk(KERN_INFO -+ "EC : Second flash program failed at:\t"); -+ printk(KERN_INFO -+ "addr : 0x%x, source : 0x%x, dest: 0x%x\n", -+ addr, data, val); -+ printk(KERN_INFO "This should not happen... STOP\n"); -+ break; -+ } -+ } -+ i++; -+ addr++; -+ } -+ -+#ifdef EC_ROM_PROTECTION -+ /* we should start spi access firstly */ -+ ec_start_spi(); -+ -+ /* enable write spi flash */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n"); -+ goto out1; -+ } -+ -+ /* protect the status register of rom */ -+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); -+ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); -+ goto out1; -+ } -+ status = ec_read(REG_XBISPIDAT); -+ -+ ec_write(REG_XBISPIDAT, status | 0x1C); -+ if (ec_instruction_cycle() < 0) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : write status value failed.\n"); -+ goto out1; -+ } -+ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); -+ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n"); -+ goto out1; -+ } -+#endif -+ -+ /* disable the write action to spi rom */ -+ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE); -+ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) { -+ printk(KERN_ERR -+ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n"); -+ goto out1; -+ } -+ -+ out1: -+ /* we should stop spi access firstly */ -+ ec_stop_spi(); -+ out: -+ /* for security */ -+ for (j = 0; j < 2000; j++) -+ udelay(1000); -+ -+ /* modify for program serial No. -+ * after program No exit idle mode -+ * and enable WDD -+ */ -+ if (flag == PROGRAM_FLAG_ROM) { -+ /* exit from the reset mode */ -+ ec_exit_reset_mode(); -+ } else { -+ /* ec exit from idle mode */ -+ ret = ec_exit_idle_mode(); -+ ec_enable_WDD(); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* ioctl */ -+static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd, -+ u_long arg) -+{ -+ struct ec_info ecinfo; -+ void __user *ptr = (void __user *)arg; -+ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); -+ int ret = 0; -+ -+ switch (cmd) { -+ case IOCTL_RDREG: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg read : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_MAX_REGADDR) -+ || (ecreg->addr < EC_MIN_REGADDR)) { -+ printk(KERN_ERR -+ "reg read : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ecreg->val = ec_read(ecreg->addr); -+ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg read : copy to user error.\n"); -+ return -EFAULT; -+ } -+ break; -+ case IOCTL_WRREG: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "reg write : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_MAX_REGADDR) -+ || (ecreg->addr < EC_MIN_REGADDR)) { -+ printk(KERN_ERR -+ "reg write : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ec_write(ecreg->addr, ecreg->val); -+ break; -+ case IOCTL_READ_EC: -+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "spi read : copy from user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecreg->addr > EC_RAM_ADDR) -+ && (ecreg->addr < EC_MAX_REGADDR)) { -+ printk(KERN_ERR -+ "spi read : out of register address range.\n"); -+ return -EINVAL; -+ } -+ ec_read_byte(ecreg->addr, &(ecreg->val)); -+ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); -+ if (ret) { -+ printk(KERN_ERR "spi read : copy to user error.\n"); -+ return -EFAULT; -+ } -+ break; -+ case IOCTL_PROGRAM_IE: -+ ecinfo.start_addr = EC_START_ADDR; -+ ecinfo.size = EC_CONTENT_MAX_SIZE; -+ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); -+ if (ecinfo.buf == NULL) { -+ printk(KERN_ERR "program ie : kmalloc failed.\n"); -+ return -ENOMEM; -+ } -+ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size); -+ if (ret) { -+ printk(KERN_ERR "program ie : copy from user error.\n"); -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ return -EFAULT; -+ } -+ -+ /* use ec_program_rom to write serial No */ -+ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE); -+ -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ break; -+ case IOCTL_PROGRAM_EC: -+ ecinfo.start_addr = EC_START_ADDR; -+ if (get_user((ecinfo.size), (u32 *) ptr)) { -+ printk(KERN_ERR "program ec : get user error.\n"); -+ return -EFAULT; -+ } -+ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) { -+ printk(KERN_ERR "program ec : size out of limited.\n"); -+ return -EINVAL; -+ } -+ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); -+ if (ecinfo.buf == NULL) { -+ printk(KERN_ERR "program ec : kmalloc failed.\n"); -+ return -ENOMEM; -+ } -+ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size); -+ if (ret) { -+ printk(KERN_ERR "program ec : copy from user error.\n"); -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ return -EFAULT; -+ } -+ -+ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM); -+ -+ kfree(ecinfo.buf); -+ ecinfo.buf = NULL; -+ break; -+ -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static long misc_compat_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg); -+} -+ -+static int misc_open(struct inode *inode, struct file *filp) -+{ -+ struct ec_reg *ecreg = NULL; -+ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL); -+ if (ecreg) -+ filp->private_data = ecreg; -+ -+ return ecreg ? 0 : -ENOMEM; -+} -+ -+static int misc_release(struct inode *inode, struct file *filp) -+{ -+ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); -+ -+ filp->private_data = NULL; -+ kfree(ecreg); -+ -+ return 0; -+} -+ -+static const struct file_operations ecmisc_fops = { -+ .open = misc_open, -+ .release = misc_release, -+ .read = NULL, -+ .write = NULL, -+#ifdef CONFIG_64BIT -+ .compat_ioctl = misc_compat_ioctl, -+#else -+ .ioctl = misc_ioctl, -+#endif -+}; -+ -+static struct miscdevice ecmisc_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = EC_MISC_DEV, -+ .fops = &ecmisc_fops -+}; -+ -+static int __init ecmisc_init(void) -+{ -+ int ret; -+ -+ printk(KERN_INFO "EC misc device init.\n"); -+ ret = misc_register(&ecmisc_device); -+ -+ return ret; -+} -+ -+static void __exit ecmisc_exit(void) -+{ -+ printk(KERN_INFO "EC misc device exit.\n"); -+ misc_deregister(&ecmisc_device); -+} -+ -+module_init(ecmisc_init); -+module_exit(ecmisc_exit); -+ -+MODULE_AUTHOR("liujl "); -+MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c -new file mode 100644 -index 0000000..32a2bdb ---- /dev/null -+++ b/drivers/platform/mips/yeeloong_laptop.c -@@ -0,0 +1,1360 @@ -+/* -+ * Driver for YeeLoong laptop extras -+ * -+ * Copyright (C) 2009 Lemote Inc. -+ * Author: Wu Zhangjin , Liu Junliang -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include /* for backlight subdriver */ -+#include -+#include /* for hwmon subdriver */ -+#include -+#include /* for video output subdriver */ -+#include /* for lcd output subdriver */ -+#include /* for hotkey subdriver */ -+#include -+#include -+#include -+#include /* for AC & Battery subdriver */ -+#include /* for register_reboot_notifier */ -+#include /* for register_pm_notifier */ -+ -+#include -+ -+#include /* for loongson_cmdline */ -+#include -+ -+#define ON 1 -+#define OFF 0 -+#define EVENT_START EVENT_LID -+ -+/* common function */ -+#define EC_VER_LEN 64 -+ -+static int ec_version_before(char *version) -+{ -+ char *p, ec_ver[EC_VER_LEN]; -+ -+ p = strstr(loongson_cmdline, "EC_VER="); -+ if (!p) -+ memset(ec_ver, 0, EC_VER_LEN); -+ else { -+ strncpy(ec_ver, p, EC_VER_LEN); -+ p = strstr(ec_ver, " "); -+ if (p) -+ *p = '\0'; -+ } -+ -+ return (strncasecmp(ec_ver, version, 64) < 0); -+} -+ -+/* backlight subdriver */ -+#define MIN_BRIGHTNESS 1 -+#define MAX_BRIGHTNESS 8 -+ -+static int yeeloong_set_brightness(struct backlight_device *bd) -+{ -+ unsigned char level; -+ static unsigned char old_level; -+ -+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && -+ bd->props.power == FB_BLANK_UNBLANK) ? -+ bd->props.brightness : 0; -+ -+ level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS); -+ -+ /* Avoid to modify the brightness when EC is tuning it */ -+ if (old_level != level) { -+ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level) -+ ec_write(REG_DISPLAY_BRIGHTNESS, level); -+ old_level = level; -+ } -+ -+ return 0; -+} -+ -+static int yeeloong_get_brightness(struct backlight_device *bd) -+{ -+ return ec_read(REG_DISPLAY_BRIGHTNESS); -+} -+ -+static struct backlight_ops backlight_ops = { -+ .get_brightness = yeeloong_get_brightness, -+ .update_status = yeeloong_set_brightness, -+}; -+ -+static struct backlight_device *yeeloong_backlight_dev; -+ -+static int yeeloong_backlight_init(void) -+{ -+ int ret; -+ struct backlight_properties props; -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.max_brightness = MAX_BRIGHTNESS; -+ props.type = BACKLIGHT_PLATFORM; -+ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL, -+ NULL, &backlight_ops, &props); -+ -+ if (IS_ERR(yeeloong_backlight_dev)) { -+ ret = PTR_ERR(yeeloong_backlight_dev); -+ yeeloong_backlight_dev = NULL; -+ return ret; -+ } -+ -+ yeeloong_backlight_dev->props.brightness = -+ yeeloong_get_brightness(yeeloong_backlight_dev); -+ backlight_update_status(yeeloong_backlight_dev); -+ -+ return 0; -+} -+ -+static void yeeloong_backlight_exit(void) -+{ -+ if (yeeloong_backlight_dev) { -+ backlight_device_unregister(yeeloong_backlight_dev); -+ yeeloong_backlight_dev = NULL; -+ } -+} -+ -+/* AC & Battery subdriver */ -+ -+static struct power_supply yeeloong_ac, yeeloong_bat; -+ -+#define RET (val->intval) -+ -+#define BAT_CAP_CRITICAL 5 -+#define BAT_CAP_HIGH 95 -+ -+#define get_bat(type) \ -+ ec_read(REG_BAT_##type) -+ -+#define get_bat_l(type) \ -+ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW)) -+ -+static int yeeloong_get_ac_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ if (psp == POWER_SUPPLY_PROP_ONLINE) -+ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN); -+ -+ return 0; -+} -+ -+static enum power_supply_property yeeloong_ac_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static struct power_supply yeeloong_ac = { -+ .name = "yeeloong-ac", -+ .type = POWER_SUPPLY_TYPE_MAINS, -+ .properties = yeeloong_ac_props, -+ .num_properties = ARRAY_SIZE(yeeloong_ac_props), -+ .get_property = yeeloong_get_ac_props, -+}; -+ -+static inline bool is_bat_in(void) -+{ -+ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN); -+} -+ -+static int get_bat_temp(void) -+{ -+ return get_bat_l(TEMPERATURE) * 10; -+} -+ -+static int get_bat_current(void) -+{ -+ return -(s16)get_bat_l(CURRENT); -+} -+ -+static int get_bat_voltage(void) -+{ -+ return get_bat_l(VOLTAGE); -+} -+ -+static char *get_manufacturer(void) -+{ -+ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO"; -+} -+ -+static int get_relative_cap(void) -+{ -+ /* -+ * When the relative capacity becomes 2, the hardware is observed to -+ * have been turned off forcely. so, we must tune it be suitable to -+ * make the software do related actions. -+ */ -+ int tmp = get_bat_l(RELATIVE_CAP); -+ -+ if (tmp <= (BAT_CAP_CRITICAL * 2)) -+ tmp -= 3; -+ -+ return tmp; -+} -+ -+static int yeeloong_get_bat_props(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ switch (psp) { -+ /* Fixed information */ -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ /* mV -> µV */ -+ RET = get_bat_l(DESIGN_VOL) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: -+ /* mAh->µAh */ -+ RET = get_bat_l(DESIGN_CAP) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL: -+ /* µAh */ -+ RET = get_bat_l(FULLCHG_CAP) * 1000; -+ break; -+ case POWER_SUPPLY_PROP_MANUFACTURER: -+ val->strval = get_manufacturer(); -+ break; -+ /* Dynamic information */ -+ case POWER_SUPPLY_PROP_PRESENT: -+ RET = is_bat_in(); -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ /* mA -> µA */ -+ RET = is_bat_in() ? get_bat_current() * 1000 : 0; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ /* mV -> µV */ -+ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0; -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ /* Celcius */ -+ RET = is_bat_in() ? get_bat_temp() : 0; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ RET = is_bat_in() ? get_relative_cap() : 0; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: { -+ int status; -+ -+ if (!is_bat_in()) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ break; -+ } -+ -+ status = get_bat(STATUS); -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; -+ -+ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; -+ break; -+ } -+ -+ if (status & BIT_BAT_STATUS_FULL) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; -+ else { -+ int curr_cap = get_relative_cap(); -+ -+ if (status & BIT_BAT_STATUS_LOW) { -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; -+ if (curr_cap <= BAT_CAP_CRITICAL) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; -+ } else if (curr_cap >= BAT_CAP_HIGH) -+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; -+ } -+ } break; -+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: -+ /* seconds */ -+ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0; -+ break; -+ case POWER_SUPPLY_PROP_STATUS: { -+ int charge = get_bat(CHARGE); -+ -+ RET = POWER_SUPPLY_STATUS_UNKNOWN; -+ if (charge & FLAG_BAT_CHARGE_DISCHARGE) -+ RET = POWER_SUPPLY_STATUS_DISCHARGING; -+ else if (charge & FLAG_BAT_CHARGE_CHARGE) -+ RET = POWER_SUPPLY_STATUS_CHARGING; -+ } break; -+ case POWER_SUPPLY_PROP_HEALTH: { -+ int status; -+ -+ if (!is_bat_in()) { -+ RET = POWER_SUPPLY_HEALTH_UNKNOWN; -+ break; -+ } -+ -+ status = get_bat(STATUS); -+ RET = POWER_SUPPLY_HEALTH_GOOD; -+ -+ if (status & (BIT_BAT_STATUS_DESTROY | -+ BIT_BAT_STATUS_LOW)) -+ RET = POWER_SUPPLY_HEALTH_DEAD; -+ if (get_bat(CHARGE_STATUS) & -+ BIT_BAT_CHARGE_STATUS_OVERTEMP) -+ RET = POWER_SUPPLY_HEALTH_OVERHEAT; -+ } break; -+ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */ -+ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+#undef RET -+ -+static enum power_supply_property yeeloong_bat_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_FULL, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_CAPACITY_LEVEL, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_MANUFACTURER, -+}; -+ -+static struct power_supply yeeloong_bat = { -+ .name = "yeeloong-bat", -+ .type = POWER_SUPPLY_TYPE_BATTERY, -+ .properties = yeeloong_bat_props, -+ .num_properties = ARRAY_SIZE(yeeloong_bat_props), -+ .get_property = yeeloong_get_bat_props, -+}; -+ -+static int ac_bat_initialized; -+ -+static int yeeloong_bat_init(void) -+{ -+ int ret; -+ -+ ret = power_supply_register(NULL, &yeeloong_ac); -+ if (ret) -+ return ret; -+ ret = power_supply_register(NULL, &yeeloong_bat); -+ if (ret) { -+ power_supply_unregister(&yeeloong_ac); -+ return ret; -+ } -+ ac_bat_initialized = 1; -+ -+ return 0; -+} -+ -+static void yeeloong_bat_exit(void) -+{ -+ ac_bat_initialized = 0; -+ -+ power_supply_unregister(&yeeloong_ac); -+ power_supply_unregister(&yeeloong_bat); -+} -+/* hwmon subdriver */ -+ -+#define MIN_FAN_SPEED 0 -+#define MAX_FAN_SPEED 3 -+ -+#define get_fan(type) \ -+ ec_read(REG_FAN_##type) -+ -+#define set_fan(type, val) \ -+ ec_write(REG_FAN_##type, val) -+ -+static inline int get_fan_speed_level(void) -+{ -+ return get_fan(SPEED_LEVEL); -+} -+static inline void set_fan_speed_level(int speed) -+{ -+ set_fan(SPEED_LEVEL, speed); -+} -+ -+static inline int get_fan_mode(void) -+{ -+ return get_fan(AUTO_MAN_SWITCH); -+} -+static inline void set_fan_mode(int mode) -+{ -+ set_fan(AUTO_MAN_SWITCH, mode); -+} -+ -+/* -+ * 3 different modes: Full speed(0); manual mode(1); auto mode(2) -+ */ -+static int get_fan_pwm_enable(void) -+{ -+ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 : -+ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1; -+} -+ -+static void set_fan_pwm_enable(int mode) -+{ -+ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL); -+ if (mode == 0) -+ set_fan_speed_level(MAX_FAN_SPEED); -+} -+ -+static int get_fan_pwm(void) -+{ -+ return get_fan_speed_level(); -+} -+ -+static void set_fan_pwm(int value) -+{ -+ if (get_fan_mode() != BIT_FAN_MANUAL) -+ return; -+ -+ value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED); -+ -+ /* We must ensure the fan is on */ -+ if (value > 0) -+ set_fan(CONTROL, ON); -+ -+ set_fan_speed_level(value); -+} -+ -+static inline int get_fan_speed(void) -+{ -+ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW); -+} -+ -+static int get_fan_rpm(void) -+{ -+ return FAN_SPEED_DIVIDER / get_fan_speed(); -+} -+ -+static int get_cpu_temp(void) -+{ -+ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000; -+} -+ -+static int get_cpu_temp_max(void) -+{ -+ return 60 * 1000; -+} -+ -+static int get_bat_temp_alarm(void) -+{ -+ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP); -+} -+ -+static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long value; -+ -+ if (!count) -+ return 0; -+ -+ ret = kstrtoul(buf, 10, &value); -+ if (ret) -+ return ret; -+ -+ set(value); -+ -+ return count; -+} -+ -+static ssize_t show_sys_hwmon(int (*get) (void), char *buf) -+{ -+ return sprintf(buf, "%d\n", get()); -+} -+ -+#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ -+ static ssize_t show_##_name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ char *buf) \ -+ { \ -+ return show_sys_hwmon(_set, buf); \ -+ } \ -+ static ssize_t store_##_name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ return store_sys_hwmon(_get, buf, count); \ -+ } \ -+ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); -+ -+CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL); -+CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm); -+CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable, -+ set_fan_pwm_enable); -+CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL); -+CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL); -+CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL); -+CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL); -+CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL); -+CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL); -+ -+static ssize_t -+show_name(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ return sprintf(buf, "yeeloong\n"); -+} -+ -+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); -+ -+static struct attribute *hwmon_attributes[] = { -+ &sensor_dev_attr_pwm1.dev_attr.attr, -+ &sensor_dev_attr_pwm1_enable.dev_attr.attr, -+ &sensor_dev_attr_fan1_input.dev_attr.attr, -+ &sensor_dev_attr_temp1_input.dev_attr.attr, -+ &sensor_dev_attr_temp1_max.dev_attr.attr, -+ &sensor_dev_attr_temp2_input.dev_attr.attr, -+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, -+ &sensor_dev_attr_curr1_input.dev_attr.attr, -+ &sensor_dev_attr_in1_input.dev_attr.attr, -+ &sensor_dev_attr_name.dev_attr.attr, -+ NULL -+}; -+ -+static struct attribute_group hwmon_attribute_group = { -+ .attrs = hwmon_attributes -+}; -+ -+static struct device *yeeloong_hwmon_dev; -+ -+static int yeeloong_hwmon_init(void) -+{ -+ int ret; -+ -+ yeeloong_hwmon_dev = hwmon_device_register(NULL); -+ if (IS_ERR(yeeloong_hwmon_dev)) { -+ yeeloong_hwmon_dev = NULL; -+ return PTR_ERR(yeeloong_hwmon_dev); -+ } -+ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj, -+ &hwmon_attribute_group); -+ if (ret) { -+ hwmon_device_unregister(yeeloong_hwmon_dev); -+ yeeloong_hwmon_dev = NULL; -+ return ret; -+ } -+ /* ensure fan is set to auto mode */ -+ set_fan_pwm_enable(2); -+ -+ return 0; -+} -+ -+static void yeeloong_hwmon_exit(void) -+{ -+ if (yeeloong_hwmon_dev) { -+ sysfs_remove_group(&yeeloong_hwmon_dev->kobj, -+ &hwmon_attribute_group); -+ hwmon_device_unregister(yeeloong_hwmon_dev); -+ yeeloong_hwmon_dev = NULL; -+ } -+} -+ -+/* video output subdriver */ -+ -+#define LCD 0 -+#define CRT 1 -+#define VOD_NUM 2 /* The total number of video output device*/ -+ -+static struct output_device *vod[VOD_NUM]; -+ -+static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT}; -+ -+static int get_vo_dev(struct output_device *od) -+{ -+ int i, dev; -+ -+ dev = -1; -+ for (i = 0; i < VOD_NUM; i++) -+ if (od == vod[i]) -+ dev = i; -+ -+ return dev; -+} -+ -+static int vo_get_status(int dev) -+{ -+ return ec_read(vor[dev]); -+} -+ -+static int yeeloong_vo_get_status(struct output_device *od) -+{ -+ int vd; -+ -+ vd = get_vo_dev(od); -+ if (vd != -1) -+ return vo_get_status(vd); -+ -+ return -ENODEV; -+} -+ -+static void vo_set_state(int dev, int state) -+{ -+ int addr; -+ unsigned long value; -+ -+ switch (dev) { -+ case LCD: -+ addr = 0x31; -+ break; -+ case CRT: -+ addr = 0x21; -+ break; -+ default: -+ /* return directly if the wrong video output device */ -+ return; -+ } -+ -+ outb(addr, 0x3c4); -+ value = inb(0x3c5); -+ -+ switch (dev) { -+ case LCD: -+ value |= (state ? 0x03 : 0x02); -+ break; -+ case CRT: -+ if (state) -+ clear_bit(7, &value); -+ else -+ set_bit(7, &value); -+ break; -+ default: -+ break; -+ } -+ -+ outb(addr, 0x3c4); -+ outb(value, 0x3c5); -+ -+ if (dev == LCD) -+ ec_write(REG_BACKLIGHT_CTRL, state); -+} -+ -+static int yeeloong_vo_set_state(struct output_device *od) -+{ -+ int vd; -+ -+ vd = get_vo_dev(od); -+ if (vd == -1) -+ return -ENODEV; -+ -+ if (vd == CRT && !vo_get_status(vd)) -+ return 0; -+ -+ vo_set_state(vd, !!od->request_state); -+ -+ return 0; -+} -+ -+static struct output_properties vop = { -+ .set_state = yeeloong_vo_set_state, -+ .get_status = yeeloong_vo_get_status, -+}; -+ -+static int yeeloong_vo_init(void) -+{ -+ int ret, i; -+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; -+ -+ /* Register video output device: lcd, crt */ -+ for (i = 0; i < VOD_NUM; i++) { -+ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop); -+ if (IS_ERR(vod[i])) { -+ if (i != 0) -+ video_output_unregister(vod[i-1]); -+ ret = PTR_ERR(vod[i]); -+ vod[i] = NULL; -+ return ret; -+ } -+ } -+ /* Ensure LCD is on by default */ -+ vo_set_state(LCD, ON); -+ -+ /* -+ * Turn off CRT by default, and will be enabled when the CRT -+ * connectting event reported by SCI -+ */ -+ vo_set_state(CRT, OFF); -+ -+ return 0; -+} -+ -+static void yeeloong_vo_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < VOD_NUM; i++) { -+ if (vod[i]) { -+ video_output_unregister(vod[i]); -+ vod[i] = NULL; -+ } -+ } -+} -+ -+/* lcd subdriver */ -+ -+struct lcd_device *lcd[VOD_NUM]; -+ -+static int get_lcd_dev(struct lcd_device *ld) -+{ -+ int i, dev; -+ -+ dev = -1; -+ for (i = 0; i < VOD_NUM; i++) -+ if (ld == lcd[i]) -+ dev = i; -+ -+ return dev; -+} -+ -+static int yeeloong_lcd_set_power(struct lcd_device *ld, int power) -+{ -+ int dev = get_lcd_dev(ld); -+ -+ if (power == FB_BLANK_UNBLANK) -+ vo_set_state(dev, ON); -+ if (power == FB_BLANK_POWERDOWN) -+ vo_set_state(dev, OFF); -+ -+ return 0; -+} -+ -+static int yeeloong_lcd_get_power(struct lcd_device *ld) -+{ -+ return vo_get_status(get_lcd_dev(ld)); -+} -+ -+static struct lcd_ops lcd_ops = { -+ .set_power = yeeloong_lcd_set_power, -+ .get_power = yeeloong_lcd_get_power, -+}; -+ -+static int yeeloong_lcd_init(void) -+{ -+ int ret, i; -+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; -+ -+ /* Register video output device: lcd, crt */ -+ for (i = 0; i < VOD_NUM; i++) { -+ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops); -+ if (IS_ERR(lcd[i])) { -+ if (i != 0) -+ lcd_device_unregister(lcd[i-1]); -+ ret = PTR_ERR(lcd[i]); -+ lcd[i] = NULL; -+ return ret; -+ } -+ } -+#if 0 -+ /* This has been done by the vide output driver */ -+ -+ /* Ensure LCD is on by default */ -+ vo_set_state(LCD, ON); -+ -+ /* -+ * Turn off CRT by default, and will be enabled when the CRT -+ * connectting event reported by SCI -+ */ -+ vo_set_state(CRT, OFF); -+#endif -+ return 0; -+} -+ -+static void yeeloong_lcd_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < VOD_NUM; i++) { -+ if (lcd[i]) { -+ lcd_device_unregister(lcd[i]); -+ lcd[i] = NULL; -+ } -+ } -+} -+ -+/* hotkey subdriver */ -+ -+static struct input_dev *yeeloong_hotkey_dev; -+ -+static atomic_t reboot_flag, sleep_flag; -+#define in_sleep() (&sleep_flag) -+#define in_reboot() (&reboot_flag) -+ -+static const struct key_entry yeeloong_keymap[] = { -+ {KE_SW, EVENT_LID, { SW_LID } }, -+ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */ -+ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */ -+ {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */ -+ {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */ -+ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */ -+ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */ -+ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */ -+ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */ -+ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */ -+ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */ -+ {KE_END, 0} -+}; -+ -+static int is_fake_event(u16 keycode) -+{ -+ switch (keycode) { -+ case KEY_SLEEP: -+ case SW_LID: -+ return atomic_read(in_sleep()) | atomic_read(in_reboot()); -+ break; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static struct key_entry *get_event_key_entry(int event, int status) -+{ -+ struct key_entry *ke; -+ static int old_brightness_status = -1; -+ static int old_volume_status = -1; -+ -+ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event); -+ if (!ke) -+ return NULL; -+ -+ switch (event) { -+ case EVENT_DISPLAY_BRIGHTNESS: -+ /* current status > old one, means up */ -+ if ((status < old_brightness_status) || (0 == status)) -+ ke++; -+ old_brightness_status = status; -+ break; -+ case EVENT_AUDIO_VOLUME: -+ if ((status < old_volume_status) || (0 == status)) -+ ke++; -+ old_volume_status = status; -+ break; -+ default: -+ break; -+ } -+ -+ return ke; -+} -+ -+static int report_lid_switch(int status) -+{ -+ static int old_status; -+ -+ /* -+ * LID is a switch button, so, two continuous same status should be -+ * ignored -+ */ -+ if (old_status != status) { -+ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status); -+ input_sync(yeeloong_hotkey_dev); -+ } -+ old_status = status; -+ -+ return status; -+} -+ -+static int crt_detect_handler(int status) -+{ -+ /* -+ * When CRT is inserted, enable its output and disable the LCD output, -+ * otherwise, do reversely. -+ */ -+ vo_set_state(CRT, status); -+ vo_set_state(LCD, !status); -+ -+ return status; -+} -+ -+static int displaytoggle_handler(int status) -+{ -+ /* EC(>=PQ1D26) does this job for us, we can not do it again, -+ * otherwise, the brightness will not resume to the normal level! */ -+ if (ec_version_before("EC_VER=PQ1D26")) -+ vo_set_state(LCD, status); -+ -+ return status; -+} -+ -+static int mypow(int x, int y) -+{ -+ int i, j = x; -+ -+ for (i = 1; i < y; i++) -+ j *= j; -+ -+ return j; -+} -+ -+static int switchvideomode_handler(int status) -+{ -+ /* Default status: CRT|LCD = 0|1 = 1 */ -+ static int bin_state = 1; -+ int i; -+ -+ /* -+ * Only enable switch video output button -+ * when CRT is connected -+ */ -+ if (!vo_get_status(CRT)) -+ return 0; -+ /* -+ * 2. no CRT connected: LCD on, CRT off -+ * 3. BOTH on -+ * 0. BOTH off -+ * 1. LCD off, CRT on -+ */ -+ -+ bin_state++; -+ if (bin_state > mypow(2, VOD_NUM) - 1) -+ bin_state = 0; -+ -+ for (i = 0; i < VOD_NUM; i++) -+ vo_set_state(i, bin_state & (1 << i)); -+ -+ return bin_state; -+} -+ -+static int camera_handler(int status) -+{ -+ int value; -+ -+ value = ec_read(REG_CAMERA_CONTROL); -+ ec_write(REG_CAMERA_CONTROL, value | (1 << 1)); -+ -+ return status; -+} -+ -+static int usb2_handler(int status) -+{ -+ pr_emerg("USB2 Over Current occurred\n"); -+ -+ return status; -+} -+ -+static int usb0_handler(int status) -+{ -+ pr_emerg("USB0 Over Current occurred\n"); -+ -+ return status; -+} -+ -+static int ac_bat_handler(int status) -+{ -+ if (ac_bat_initialized) { -+ power_supply_changed(&yeeloong_ac); -+ power_supply_changed(&yeeloong_bat); -+ } -+ -+ return status; -+} -+ -+struct sci_event { -+ int reg; -+ sci_handler handler; -+}; -+ -+static const struct sci_event se[] = { -+ [EVENT_AC_BAT] = {0, ac_bat_handler}, -+ [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL}, -+ [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL}, -+ [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler}, -+ [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler}, -+ [EVENT_BLACK_SCREEN] = {REG_DISPLAY_LCD, displaytoggle_handler}, -+ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL}, -+ [EVENT_LID] = {REG_LID_DETECT, NULL}, -+ [EVENT_DISPLAY_TOGGLE] = {0, switchvideomode_handler}, -+ [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler}, -+ [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler}, -+ [EVENT_WLAN] = {REG_WLAN, NULL}, -+}; -+ -+static void do_event_action(int event) -+{ -+ int status = -1; -+ struct key_entry *ke; -+ struct sci_event *sep; -+ -+ sep = (struct sci_event *)&se[event]; -+ -+ if (sep->reg != 0) -+ status = ec_read(sep->reg); -+ -+ if (status == -1) { -+ /* ec_read hasn't been called, status is invalid */ -+ return; -+ } -+ -+ if (sep->handler != NULL) -+ status = sep->handler(status); -+ -+ pr_debug("%s: event: %d status: %d\n", __func__, event, status); -+ -+ /* Report current key to user-space */ -+ ke = get_event_key_entry(event, status); -+ -+ /* -+ * Ignore the LID and SLEEP event when we are already in sleep or -+ * reboot state, this will avoid the recursive pm operations. but note: -+ * the report_lid_switch() called in arch/mips/loongson/lemote-2f/pm.c -+ * is necessary, because it is used to wake the system from sleep -+ * state. In the future, perhaps SW_LID should works like SLEEP, no -+ * need to function as a SWITCH, just report the state when the LID is -+ * closed is enough, this event can tell the software to "SLEEP", no -+ * need to tell the softwares when we are resuming from "SLEEP". -+ */ -+ if (ke && !is_fake_event(ke->keycode)) { -+ if (ke->keycode == SW_LID) -+ report_lid_switch(status); -+ else -+ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1, -+ true); -+ } -+} -+ -+/* -+ * SCI(system control interrupt) main interrupt routine -+ * -+ * We will do the query and get event number together so the interrupt routine -+ * should be longer than 120us now at least 3ms elpase for it. -+ */ -+static irqreturn_t sci_irq_handler(int irq, void *dev_id) -+{ -+ int ret, event; -+ -+ if (SCI_IRQ_NUM != irq) -+ return IRQ_NONE; -+ -+ /* Query the event number */ -+ ret = ec_query_event_num(); -+ if (ret < 0) -+ return IRQ_NONE; -+ -+ event = ec_get_event_num(); -+ if (event < EVENT_START || event > EVENT_END) -+ return IRQ_NONE; -+ -+ /* Execute corresponding actions */ -+ do_event_action(event); -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Config and init some msr and gpio register properly. -+ */ -+static int sci_irq_init(void) -+{ -+ u32 hi, lo; -+ u32 gpio_base; -+ unsigned long flags; -+ int ret; -+ -+ /* Get gpio base */ -+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); -+ gpio_base = lo & 0xff00; -+ -+ /* Filter the former kb3310 interrupt for security */ -+ ret = ec_query_event_num(); -+ if (ret) -+ return ret; -+ -+ /* For filtering next number interrupt */ -+ udelay(10000); -+ -+ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN -+ * gpio : -+ * input, pull-up, no-invert, event-count and value 0, -+ * no-filter, no edge mode -+ * gpio27 map to Virtual gpio0 -+ * msr : -+ * no primary and lpc -+ * Unrestricted Z input to IG10 from Virtual gpio 0. -+ */ -+ local_irq_save(flags); -+ _rdmsr(0x80000024, &hi, &lo); -+ lo &= ~(1 << 10); -+ _wrmsr(0x80000024, hi, lo); -+ _rdmsr(0x80000025, &hi, &lo); -+ lo &= ~(1 << 10); -+ _wrmsr(0x80000025, hi, lo); -+ _rdmsr(0x80000023, &hi, &lo); -+ lo |= (0x0a << 0); -+ _wrmsr(0x80000023, hi, lo); -+ local_irq_restore(flags); -+ -+ /* Set gpio27 as sci interrupt -+ * -+ * input, pull-up, no-fliter, no-negedge, invert -+ * the sci event is just about 120us -+ */ -+ asm(".set noreorder\n"); -+ /* input enable */ -+ outl(0x00000800, (gpio_base | 0xA0)); -+ /* revert the input */ -+ outl(0x00000800, (gpio_base | 0xA4)); -+ /* event-int enable */ -+ outl(0x00000800, (gpio_base | 0xB8)); -+ asm(".set reorder\n"); -+ -+ return 0; -+} -+ -+static int notify_reboot(struct notifier_block *nb, unsigned long event, void *buf) -+{ -+ switch (event) { -+ case SYS_RESTART: -+ case SYS_HALT: -+ case SYS_POWER_OFF: -+ atomic_set(in_reboot(), 1); -+ break; -+ default: -+ return NOTIFY_DONE; -+ } -+ -+ return NOTIFY_OK; -+} -+ -+static int notify_pm(struct notifier_block *nb, unsigned long event, void *buf) -+{ -+ switch (event) { -+ case PM_HIBERNATION_PREPARE: -+ case PM_SUSPEND_PREPARE: -+ atomic_inc(in_sleep()); -+ break; -+ case PM_POST_HIBERNATION: -+ case PM_POST_SUSPEND: -+ case PM_RESTORE_PREPARE: /* do we need this ?? */ -+ atomic_dec(in_sleep()); -+ break; -+ default: -+ return NOTIFY_DONE; -+ } -+ -+ pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event, -+ atomic_read(in_sleep())); -+ -+ return NOTIFY_OK; -+} -+ -+static struct notifier_block reboot_notifier = { -+ .notifier_call = notify_reboot, -+}; -+ -+static struct notifier_block pm_notifier = { -+ .notifier_call = notify_pm, -+}; -+ -+static int yeeloong_hotkey_init(void) -+{ -+ int ret = 0; -+ -+ ret = register_reboot_notifier(&reboot_notifier); -+ if (ret) { -+ pr_err("Can't register reboot notifier\n"); -+ goto end; -+ } -+ -+ ret = register_pm_notifier(&pm_notifier); -+ if (ret) { -+ pr_err("Can't register pm notifier\n"); -+ goto free_reboot_notifier; -+ } -+ -+ ret = sci_irq_init(); -+ if (ret) { -+ pr_err("Can't init SCI interrupt\n"); -+ goto free_pm_notifier; -+ } -+ -+ ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler, -+ IRQF_ONESHOT, "sci", NULL); -+ if (ret) { -+ pr_err("Can't thread SCI interrupt handler\n"); -+ goto free_pm_notifier; -+ } -+ -+ yeeloong_hotkey_dev = input_allocate_device(); -+ -+ if (!yeeloong_hotkey_dev) { -+ ret = -ENOMEM; -+ goto free_irq; -+ } -+ -+ yeeloong_hotkey_dev->name = "HotKeys"; -+ yeeloong_hotkey_dev->phys = "button/input0"; -+ yeeloong_hotkey_dev->id.bustype = BUS_HOST; -+ yeeloong_hotkey_dev->dev.parent = NULL; -+ -+ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL); -+ if (ret) { -+ pr_err("Failed to setup input device keymap\n"); -+ goto free_dev; -+ } -+ -+ ret = input_register_device(yeeloong_hotkey_dev); -+ if (ret) -+ goto free_keymap; -+ -+ /* Update the current status of LID */ -+ report_lid_switch(ON); -+ -+#ifdef CONFIG_LOONGSON_SUSPEND -+ /* Install the real yeeloong_report_lid_status for pm.c */ -+ yeeloong_report_lid_status = report_lid_switch; -+#endif -+ return 0; -+ -+free_keymap: -+ sparse_keymap_free(yeeloong_hotkey_dev); -+free_dev: -+ input_free_device(yeeloong_hotkey_dev); -+free_irq: -+ free_irq(SCI_IRQ_NUM, NULL); -+free_pm_notifier: -+ unregister_pm_notifier(&pm_notifier); -+free_reboot_notifier: -+ unregister_reboot_notifier(&reboot_notifier); -+end: -+ return ret; -+} -+ -+static void yeeloong_hotkey_exit(void) -+{ -+ /* Free irq */ -+ free_irq(SCI_IRQ_NUM, NULL); -+ -+#ifdef CONFIG_LOONGSON_SUSPEND -+ /* Uninstall yeeloong_report_lid_status for pm.c */ -+ if (yeeloong_report_lid_status == report_lid_switch) -+ yeeloong_report_lid_status = NULL; -+#endif -+ -+ if (yeeloong_hotkey_dev) { -+ sparse_keymap_free(yeeloong_hotkey_dev); -+ input_unregister_device(yeeloong_hotkey_dev); -+ yeeloong_hotkey_dev = NULL; -+ } -+} -+ -+#ifdef CONFIG_PM -+static void usb_ports_set(int status) -+{ -+ status = !!status; -+ -+ ec_write(REG_USB0_FLAG, status); -+ ec_write(REG_USB1_FLAG, status); -+ ec_write(REG_USB2_FLAG, status); -+} -+ -+static int yeeloong_suspend(struct device *dev) -+ -+{ -+ if (ec_version_before("EC_VER=PQ1D27")) -+ vo_set_state(LCD, OFF); -+ vo_set_state(CRT, OFF); -+ usb_ports_set(OFF); -+ -+ return 0; -+} -+ -+static int yeeloong_resume(struct device *dev) -+{ -+ int ret; -+ -+ if (ec_version_before("EC_VER=PQ1D27")) -+ vo_set_state(LCD, ON); -+ vo_set_state(CRT, ON); -+ usb_ports_set(ON); -+ -+ ret = sci_irq_init(); -+ if (ret) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend, -+ yeeloong_resume); -+#endif -+ -+static struct platform_device_id platform_device_ids[] = { -+ { -+ .name = "yeeloong_laptop", -+ }, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(platform, platform_device_ids); -+ -+static struct platform_driver platform_driver = { -+ .driver = { -+ .name = "yeeloong_laptop", -+ .owner = THIS_MODULE, -+#ifdef CONFIG_PM -+ .pm = &yeeloong_pm_ops, -+#endif -+ }, -+ .id_table = platform_device_ids, -+}; -+ -+static int __init yeeloong_init(void) -+{ -+ int ret; -+ -+ pr_info("YeeLoong Laptop platform specific driver loaded.\n"); -+ -+ /* Register platform stuff */ -+ ret = platform_driver_register(&platform_driver); -+ if (ret) { -+ pr_err("Failed to register YeeLoong platform driver.\n"); -+ return ret; -+ } -+ -+#define yeeloong_init_drv(drv, alias) do { \ -+ pr_info("Registered YeeLoong " alias " driver.\n"); \ -+ ret = yeeloong_ ## drv ## _init(); \ -+ if (ret) { \ -+ pr_err("Failed to register YeeLoong " alias " driver.\n"); \ -+ yeeloong_ ## drv ## _exit(); \ -+ return ret; \ -+ } \ -+} while (0) -+ -+ yeeloong_init_drv(backlight, "backlight"); -+ yeeloong_init_drv(bat, "battery and AC"); -+ yeeloong_init_drv(hwmon, "hardware monitor"); -+ yeeloong_init_drv(vo, "video output"); -+ yeeloong_init_drv(lcd, "lcd output"); -+ yeeloong_init_drv(hotkey, "hotkey input"); -+ -+ return 0; -+} -+ -+static void __exit yeeloong_exit(void) -+{ -+ yeeloong_hotkey_exit(); -+ yeeloong_lcd_exit(); -+ yeeloong_vo_exit(); -+ yeeloong_hwmon_exit(); -+ yeeloong_bat_exit(); -+ yeeloong_backlight_exit(); -+ platform_driver_unregister(&platform_driver); -+ -+ pr_info("YeeLoong platform specific driver unloaded.\n"); -+} -+ -+module_init(yeeloong_init); -+module_exit(yeeloong_exit); -+ -+MODULE_AUTHOR("Wu Zhangjin ; Liu Junliang "); -+MODULE_DESCRIPTION("YeeLoong laptop driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index b5b5c3d..f908003 100644 ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -727,6 +727,7 @@ comment "Platform RTC drivers" - config RTC_DRV_CMOS - tristate "PC-style 'CMOS'" - depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 -+ depends on !DEXXON_GDIUM - default y if X86 - help - Say "yes" here to get direct support for the real time clock -diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c -index f940056..a9bb1db 100644 ---- a/drivers/usb/host/pci-quirks.c -+++ b/drivers/usb/host/pci-quirks.c -@@ -450,6 +450,26 @@ void usb_amd_dev_put(void) - } - EXPORT_SYMBOL_GPL(usb_amd_dev_put); - -+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) \ -+ || defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) -+static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) -+{ -+ u16 cmd; -+ return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); -+} -+ -+#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) -+#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) -+ -+static int mmio_resource_enabled(struct pci_dev *pdev, int idx) -+{ -+ return pci_resource_start(pdev, idx) && mmio_enabled(pdev); -+} -+#endif -+ -+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) - /* - * Make sure the controller is completely inactive, unable to - * generate interrupts or do DMA. -@@ -531,15 +551,6 @@ reset_needed: - } - EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); - --static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) --{ -- u16 cmd; -- return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); --} -- --#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) --#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) -- - static void quirk_usb_handoff_uhci(struct pci_dev *pdev) - { - unsigned long base = 0; -@@ -557,12 +568,11 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev) - if (base) - uhci_check_and_reset_hc(pdev, base); - } -+#else -+#define quirk_usb_handoff_uhci(x) do { } while (0) -+#endif /* CONFIG_USB_UHCI_HCD* */ - --static int mmio_resource_enabled(struct pci_dev *pdev, int idx) --{ -- return pci_resource_start(pdev, idx) && mmio_enabled(pdev); --} -- -+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) - static void quirk_usb_handoff_ohci(struct pci_dev *pdev) - { - void __iomem *base; -@@ -641,7 +651,11 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) - /* Now the controller is safely in SUSPEND and nothing can wake it up */ - iounmap(base); - } -+#else -+#define quirk_usb_handoff_ohci(x) do { } while(0) -+#endif /* CONFIG_USB_OHCI_HCD* */ - -+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) - static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { - { - /* Pegatron Lucid (ExoPC) */ -@@ -816,6 +830,9 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev) - - iounmap(base); - } -+#else -+#define quirk_usb_disable_ehci(x) do { } while (0) -+#endif /* CONFIG_USB_EHCI_HCD* */ - - /* - * handshake - spin reading a register until handshake completes -@@ -956,6 +973,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) - } - EXPORT_SYMBOL_GPL(usb_disable_xhci_ports); - -+#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) - /** - * PCI Quirks for xHCI. - * -@@ -1064,6 +1082,9 @@ hc_init: - - iounmap(base); - } -+#else -+#define quirk_usb_handoff_xhci(x) do { } while (0) -+#endif /* CONFIG_USB_UHCI_HCD* */ - - static void quirk_usb_early_handoff(struct pci_dev *pdev) - { -diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c -index f0c0c53..84dff90 100644 ---- a/drivers/usb/serial/option.c -+++ b/drivers/usb/serial/option.c -@@ -79,6 +79,9 @@ static void option_instat_callback(struct urb *urb); - #define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 - #define OPTION_PRODUCT_GTM380_MODEM 0x7201 - -+#define HUAWO_VENDOR_ID 0x21F5 -+#define HUAWO_PRODUCT_E1621 0x2008 -+ - #define HUAWEI_VENDOR_ID 0x12D1 - #define HUAWEI_PRODUCT_E173 0x140C - #define HUAWEI_PRODUCT_E1750 0x1406 -@@ -633,6 +636,7 @@ static const struct usb_device_id option_ids[] = { - { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, - { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, -+ { USB_DEVICE(HUAWO_VENDOR_ID, HUAWO_PRODUCT_E1621) }, /* QUANTA 6500 chips, Unicom extensive use of this card */ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, -diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig -index 8bf495f..f6a15b6 100644 ---- a/drivers/video/Kconfig -+++ b/drivers/video/Kconfig -@@ -36,6 +36,12 @@ config VGASTATE - tristate - default n - -+config VIDEO_OUTPUT_CONTROL -+ tristate "Lowlevel video output switch controls" -+ help -+ This framework adds support for low-level control of the video -+ output switch. -+ - config VIDEOMODE_HELPERS - bool - -diff --git a/drivers/video/Makefile b/drivers/video/Makefile -index 9ad3c17..3d869d9 100644 ---- a/drivers/video/Makefile -+++ b/drivers/video/Makefile -@@ -7,6 +7,8 @@ obj-y += backlight/ - - obj-y += fbdev/ - -+#video output switch sysfs driver -+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o - obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o - ifeq ($(CONFIG_OF),y) - obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o -diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig -index b3dd417..452035ad 100644 ---- a/drivers/video/fbdev/Kconfig -+++ b/drivers/video/fbdev/Kconfig -@@ -2450,6 +2450,19 @@ config FB_SIMPLE - Configuration re: surface address, size, and format must be provided - through device tree, or plain old platform data. - -+config FB_SM712 -+ tristate "Silicon Motion SM712 framebuffer support" -+ depends on FB && PCI -+ select FB_CFB_FILLRECT -+ select FB_CFB_COPYAREA -+ select FB_CFB_IMAGEBLIT -+ help -+ Frame buffer driver for the Silicon Motion SM712 chip. -+ -+ This driver is also available as a module. The module will be -+ called sm712fb. If you want to compile it as a module, say M -+ here and read . -+ - source "drivers/video/fbdev/omap/Kconfig" - source "drivers/video/fbdev/omap2/Kconfig" - source "drivers/video/fbdev/exynos/Kconfig" -diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile -index 1979aff..9b694f9 100644 ---- a/drivers/video/fbdev/Makefile -+++ b/drivers/video/fbdev/Makefile -@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o - obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o - obj-$(CONFIG_FB_PS3) += ps3fb.o - obj-$(CONFIG_FB_SM501) += sm501fb.o -+obj-$(CONFIG_FB_SM712) += sm712fb/ - obj-$(CONFIG_FB_UDL) += udlfb.o - obj-$(CONFIG_FB_SMSCUFX) += smscufx.o - obj-$(CONFIG_FB_XILINX) += xilinxfb.o -diff --git a/drivers/video/fbdev/sm712fb/Makefile b/drivers/video/fbdev/sm712fb/Makefile -new file mode 100644 -index 0000000..9bf3519 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_FB_SM712) += sm712fb.o -+ -+sm712fb-objs := sm712fb_drv.o sm712fb_accel.o -diff --git a/drivers/video/fbdev/sm712fb/TODO b/drivers/video/fbdev/sm712fb/TODO -new file mode 100644 -index 0000000..dcfd4e7 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/TODO -@@ -0,0 +1,7 @@ -+TODO: -+- Dual head support -+- refine the code, convert more registers magic numbers to macros -+- Does it really works on Big Endian machines? -+ -+Please send any patches to Greg Kroah-Hartman and -+Tom Li . -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.c b/drivers/video/fbdev/sm712fb/sm712fb_accel.c -new file mode 100644 -index 0000000..12fce1f ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.c -@@ -0,0 +1,246 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#include -+#include -+#include -+ -+#include "sm712fb_drv.h" -+#include "sm712fb_accel.h" -+ -+static inline u32 bytes_to_dword(const u8 *bytes, int length) -+{ -+ u32 dword = 0; -+ -+ switch (length) { -+ case 4: -+#ifdef __BIG_ENDIAN -+ dword += bytes[3]; -+#else -+ dword += bytes[3] << 24; -+#endif -+ case 3: -+#ifdef __BIG_ENDIAN -+ dword += bytes[2] << 8; -+#else -+ dword += bytes[2] << 16; -+#endif -+ case 2: -+#ifdef __BIG_ENDIAN -+ dword += bytes[1] << 16; -+#else -+ dword += bytes[1] << 8; -+#endif -+ case 1: -+#ifdef __BIG_ENDIAN -+ dword += bytes[0] << 24; -+#else -+ dword += bytes[0]; -+#endif -+ } -+ return dword; -+} -+ -+int sm712fb_init_accel(struct sm712fb_info *fb) -+{ -+ u8 reg; -+ -+ /* reset the 2D engine */ -+ sm712_write_seq(fb, 0x21, sm712_read_seq(fb, 0x21) & 0xf8); -+ reg = sm712_read_seq(fb, 0x15); -+ sm712_write_seq(fb, 0x15, reg | 0x30); -+ sm712_write_seq(fb, 0x15, reg); -+ -+ if (sm712fb_wait(fb) != 0) -+ return -1; -+ -+ sm712_write_dpr(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0)); -+ -+ /* same width for DPR_PITCH and DPR_SRC_WINDOW */ -+ sm712_write_dpr(fb, DPR_PITCH, -+ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); -+ sm712_write_dpr(fb, DPR_SRC_WINDOW, -+ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); -+ -+ sm712_write_dpr(fb, DPR_BYTE_BIT_MASK, 0xffffffff); -+ sm712_write_dpr(fb, DPR_COLOR_COMPARE_MASK, 0); -+ sm712_write_dpr(fb, DPR_COLOR_COMPARE, 0); -+ sm712_write_dpr(fb, DPR_SRC_BASE, 0); -+ sm712_write_dpr(fb, DPR_DST_BASE, 0); -+ sm712_read_dpr(fb, DPR_DST_BASE); -+ -+ return 0; -+} -+ -+int sm712fb_wait(struct sm712fb_info *fb) -+{ -+ int i; -+ u8 reg; -+ -+ for (i = 0; i < 10000; i++) { -+ reg = sm712_read_seq(fb, SCR_DE_STATUS); -+ if ((reg & SCR_DE_STATUS_MASK) == SCR_DE_ENGINE_IDLE) -+ return 0; -+ udelay(1); -+ } -+ return -EBUSY; -+} -+ -+void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -+{ -+ u32 width = rect->width, height = rect->height; -+ u32 dx = rect->dx, dy = rect->dy; -+ u32 color; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((rect->dx >= info->var.xres_virtual) || -+ (rect->dy >= info->var.yres_virtual)) -+ return; -+ -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) -+ color = ((u32 *) (info->pseudo_palette))[rect->color]; -+ else -+ color = rect->color; -+ -+ sm712_write_dpr(sfb, DPR_FG_COLOR, color); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | -+ (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -+ -+void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) -+{ -+ u32 sx = area->sx, sy = area->sy; -+ u32 dx = area->dx, dy = area->dy; -+ u32 height = area->height, width = area->width; -+ u32 direction; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((sx >= info->var.xres_virtual) || (sy >= info->var.yres_virtual)) -+ return; -+ -+ if (sy < dy || (sy == dy && sx <= dx)) { -+ sx += width - 1; -+ dx += width - 1; -+ sy += height - 1; -+ dy += height - 1; -+ direction = DE_CTRL_RTOL; -+ } else -+ direction = 0; -+ -+ sm712_write_dpr(sfb, DPR_SRC_COORDS, DPR_COORDS(sx, sy)); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_DE_CTRL, -+ DE_CTRL_START | DE_CTRL_ROP_ENABLE | direction | -+ (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -+ -+void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image) -+{ -+ u32 dx = image->dx, dy = image->dy; -+ u32 width = image->width, height = image->height; -+ u32 fg_color, bg_color; -+ -+ struct sm712fb_info *sfb = info->par; -+ -+ u32 imgidx = 0; -+ u32 line = image->width >> 3; -+ -+ int i, j; -+ u32 total_bytes, total_dwords, remain_bytes; -+ -+ if (unlikely(info->state != FBINFO_STATE_RUNNING)) -+ return; -+ if ((image->dx >= info->var.xres_virtual) || -+ (image->dy >= info->var.yres_virtual)) -+ return; -+ -+ if (unlikely(image->depth != 1)) { -+ /* unsupported depth, fallback to draw Tux */ -+ cfb_imageblit(info, image); -+ return; -+ } -+ -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) { -+ fg_color = ((u32 *) (info->pseudo_palette))[image->fg_color]; -+ bg_color = ((u32 *) (info->pseudo_palette))[image->bg_color]; -+ } else { -+ fg_color = image->fg_color; -+ bg_color = image->bg_color; -+ } -+ -+ /* total bytes we need to write */ -+ total_bytes = (width + 7) / 8; -+ -+ /* split the bytes into dwords and remainder bytes */ -+ total_dwords = (total_bytes & ~3) / 4; -+ remain_bytes = total_bytes & 3; -+ -+ sm712_write_dpr(sfb, DPR_SRC_COORDS, 0); -+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); -+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); -+ sm712_write_dpr(sfb, DPR_FG_COLOR, fg_color); -+ sm712_write_dpr(sfb, DPR_BG_COLOR, bg_color); -+ -+ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | -+ (DE_CTRL_COMMAND_HOST_WRITE << DE_CTRL_COMMAND_SHIFT) | -+ (DE_CTRL_HOST_MONO << DE_CTRL_HOST_SHIFT) | -+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); -+ -+ for (i = 0; i < height; i++) { -+ /* cast bytes data into dwords and write to the dataport */ -+ for (j = 0; j < total_dwords; j++) { -+ sm712_write_dataport(sfb, -+ bytes_to_dword(&image-> -+ data[imgidx] + -+ j * 4, 4)); -+ } -+ -+ if (remain_bytes) { -+ sm712_write_dataport(sfb, -+ bytes_to_dword(&image-> -+ data[imgidx] + -+ (total_dwords * 4), -+ remain_bytes)); -+ } -+ imgidx += line; -+ } -+ sm712_read_dpr(sfb, DPR_DE_CTRL); -+ sm712fb_wait(sfb); -+} -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.h b/drivers/video/fbdev/sm712fb/sm712fb_accel.h -new file mode 100644 -index 0000000..6f79177 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.h -@@ -0,0 +1,33 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#ifndef _SM712FB_ACCEL_H -+#define _SM712FB_ACCEL_H -+ -+int sm712fb_init_accel(struct sm712fb_info *fb); -+int sm712fb_wait(struct sm712fb_info *fb); -+void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -+void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area); -+void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image); -+ -+#endif -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.c b/drivers/video/fbdev/sm712fb/sm712fb_drv.c -new file mode 100644 -index 0000000..7f7cd4f ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.c -@@ -0,0 +1,1022 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_PM -+#include -+#endif -+ -+#include "sm712fb_drv.h" -+#include "sm712fb_accel.h" -+#include "sm712fb_modedb.h" -+ -+static struct fb_var_screeninfo sm712fb_var = { -+ .xres = 1024, -+ .yres = 600, -+ .xres_virtual = 1024, -+ .yres_virtual = 600, -+ .bits_per_pixel = 16, -+ .red = {16, 8, 0}, -+ .green = {8, 8, 0}, -+ .blue = {0, 8, 0}, -+ .activate = FB_ACTIVATE_NOW, -+ .height = -1, -+ .width = -1, -+ .vmode = FB_VMODE_NONINTERLACED, -+ .nonstd = 0, -+ .accel_flags = FB_ACCELF_TEXT, -+}; -+ -+static struct fb_fix_screeninfo sm712fb_fix = { -+ .id = "smXXXfb", -+ .type = FB_TYPE_PACKED_PIXELS, -+ .visual = FB_VISUAL_TRUECOLOR, -+ .line_length = 800 * 3, -+ .accel = FB_ACCEL_SMI_LYNX, -+ .type_aux = 0, -+ .xpanstep = 0, -+ .ypanstep = 0, -+ .ywrapstep = 0, -+}; -+ -+struct vesa_mode { -+ char index[6]; -+ u16 lfb_width; -+ u16 lfb_height; -+ u16 lfb_depth; -+}; -+ -+static bool accel = 1; -+ -+static struct vesa_mode vesa_mode_table[] = { -+ {"0x301", 640, 480, 8}, -+ {"0x303", 800, 600, 8}, -+ {"0x305", 1024, 768, 8}, -+ {"0x307", 1280, 1024, 8}, -+ -+ {"0x311", 640, 480, 16}, -+ {"0x314", 800, 600, 16}, -+ {"0x317", 1024, 768, 16}, -+ {"0x31A", 1280, 1024, 16}, -+ -+ {"0x312", 640, 480, 24}, -+ {"0x315", 800, 600, 24}, -+ {"0x318", 1024, 768, 24}, -+ {"0x31B", 1280, 1024, 24}, -+}; -+ -+struct screen_info sm712_scr_info; -+ -+static int sm712fb_setup(char *options) -+{ -+ char *this_opt; -+ -+ if (!options || !*options) -+ return 0; -+ -+ while ((this_opt = strsep(&options, ",")) != NULL) { -+ if (!*this_opt) -+ continue; -+ -+ if (!strcmp(this_opt, "accel:0")) -+ accel = false; -+ else if (!strcmp(this_opt, "accel:1")) -+ accel = true; -+ } -+ return 0; -+} -+ -+/* process command line options, get vga parameter */ -+static int __init sm712_vga_setup(char *options) -+{ -+ int i; -+ -+ if (!options || !*options) -+ return -EINVAL; -+ -+ sm712_scr_info.lfb_width = 0; -+ sm712_scr_info.lfb_height = 0; -+ sm712_scr_info.lfb_depth = 0; -+ -+ pr_debug("sm712_vga_setup = %s\n", options); -+ -+ for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { -+ if (strstr(options, vesa_mode_table[i].index)) { -+ sm712_scr_info.lfb_width = vesa_mode_table[i].lfb_width; -+ sm712_scr_info.lfb_height = -+ vesa_mode_table[i].lfb_height; -+ sm712_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; -+ return 0; -+ } -+ } -+ -+ return -1; -+} -+ -+__setup("vga=", sm712_vga_setup); -+ -+static void sm712_setpalette(int regno, unsigned red, unsigned green, -+ unsigned blue, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb = info->par; -+ -+ /* set bit 5:4 = 01 (write LCD RAM only) */ -+ sm712_write_seq(sfb, 0x66, (sm712_read_seq(sfb, 0x66) & 0xC3) | 0x10); -+ -+ sm712_writeb(sfb->mmio, DAC_REG, regno); -+ sm712_writeb(sfb->mmio, DAC_VAL, red >> 10); -+ sm712_writeb(sfb->mmio, DAC_VAL, green >> 10); -+ sm712_writeb(sfb->mmio, DAC_VAL, blue >> 10); -+} -+ -+/* chan_to_field -+ * -+ * convert a colour value into a field position -+ * -+ * from pxafb.c -+ */ -+ -+static inline unsigned int chan_to_field(unsigned int chan, -+ struct fb_bitfield *bf) -+{ -+ chan &= 0xffff; -+ chan >>= 16 - bf->length; -+ return chan << bf->offset; -+} -+ -+static int sm712_blank(int blank_mode, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb = info->par; -+ -+ /* clear DPMS setting */ -+ switch (blank_mode) { -+ case FB_BLANK_UNBLANK: -+ /* Screen On: HSync: On, VSync : On */ -+ sm712_write_seq(sfb, 0x01, -+ (sm712_read_seq(sfb, 0x01) & (~0x20))); -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) & 0x77)); -+ sm712_write_seq(sfb, 0x22, -+ (sm712_read_seq(sfb, 0x22) & (~0x30))); -+ sm712_write_seq(sfb, 0x23, -+ (sm712_read_seq(sfb, 0x23) & (~0xc0))); -+ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); -+ sm712_write_seq(sfb, 0x31, (sm712_read_seq(sfb, 0x31) | 0x03)); -+ break; -+ case FB_BLANK_NORMAL: -+ /* Screen Off: HSync: On, VSync : On Soft blank */ -+ sm712_write_seq(sfb, 0x01, -+ (sm712_read_seq(sfb, 0x01) & (~0x20))); -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x22, -+ (sm712_read_seq(sfb, 0x22) & (~0x30))); -+ sm712_write_seq(sfb, 0x23, -+ (sm712_read_seq(sfb, 0x23) & (~0xc0))); -+ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ break; -+ case FB_BLANK_VSYNC_SUSPEND: -+ /* Screen On: HSync: On, VSync : Off */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x0c); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x20)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0x20)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ case FB_BLANK_HSYNC_SUSPEND: -+ /* Screen On: HSync: Off, VSync : On */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x0c); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x10)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ case FB_BLANK_POWERDOWN: -+ /* Screen On: HSync: Off, VSync : Off */ -+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); -+ sm712_write_seq(sfb, 0x20, -+ (sm712_read_seq(sfb, 0x20) & (~0xB0))); -+ sm712_write_seq(sfb, 0x6a, 0x5a); -+ sm712_write_seq(sfb, 0x6b, 0x20); -+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); -+ sm712_write_seq(sfb, 0x22, -+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x30)); -+ sm712_write_seq(sfb, 0x23, -+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); -+ sm712_write_seq(sfb, 0x24, -+ (sm712_read_seq(sfb, 0x24) & (~0x01))); -+ sm712_write_seq(sfb, 0x31, -+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int sm712_setcolreg(unsigned regno, unsigned red, unsigned green, -+ unsigned blue, unsigned trans, struct fb_info *info) -+{ -+ struct sm712fb_info *sfb; -+ u32 val; -+ -+ sfb = info->par; -+ -+ if (regno > 255) -+ return 1; -+ -+ switch (sfb->fb.fix.visual) { -+ case FB_VISUAL_DIRECTCOLOR: -+ case FB_VISUAL_TRUECOLOR: -+ /* -+ * 16/32 bit true-colour, use pseudo-palette for 16 base color -+ */ -+ if (regno < 16) { -+ if (sfb->fb.var.bits_per_pixel == 16) { -+ u32 *pal = sfb->fb.pseudo_palette; -+ -+ val = chan_to_field(red, &sfb->fb.var.red); -+ val |= chan_to_field(green, &sfb->fb.var.green); -+ val |= chan_to_field(blue, &sfb->fb.var.blue); -+#ifdef __BIG_ENDIAN -+ pal[regno] = -+ ((red & 0xf800) >> 8) | -+ ((green & 0xe000) >> 13) | -+ ((green & 0x1c00) << 3) | -+ ((blue & 0xf800) >> 3); -+#else -+ pal[regno] = val; -+#endif -+ } else { -+ u32 *pal = sfb->fb.pseudo_palette; -+ -+ val = chan_to_field(red, &sfb->fb.var.red); -+ val |= chan_to_field(green, &sfb->fb.var.green); -+ val |= chan_to_field(blue, &sfb->fb.var.blue); -+#ifdef __BIG_ENDIAN -+ val = -+ (val & 0xff00ff00 >> 8) | -+ (val & 0x00ff00ff << 8); -+#endif -+ pal[regno] = val; -+ } -+ } -+ break; -+ -+ case FB_VISUAL_PSEUDOCOLOR: -+ /* color depth 8 bit */ -+ sm712_setpalette(regno, red, green, blue, info); -+ break; -+ -+ default: -+ return 1; /* unknown type */ -+ } -+ -+ return 0; -+ -+} -+ -+#ifdef __BIG_ENDIAN -+static ssize_t sm712fb_read(struct fb_info *info, char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ unsigned long p = *ppos; -+ -+ u32 *buffer, *dst; -+ u32 __iomem *src; -+ int c, i, cnt = 0, err = 0; -+ unsigned long total_size; -+ -+ if (!info || !info->screen_base) -+ return -ENODEV; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return -EPERM; -+ -+ total_size = info->screen_size; -+ -+ if (total_size == 0) -+ total_size = info->fix.smem_len; -+ -+ if (p >= total_size) -+ return 0; -+ -+ if (count >= total_size) -+ count = total_size; -+ -+ if (count + p > total_size) -+ count = total_size - p; -+ -+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ src = (u32 __iomem *) (info->screen_base + p); -+ -+ if (info->fbops->fb_sync) -+ info->fbops->fb_sync(info); -+ -+ while (count) { -+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; -+ dst = buffer; -+ for (i = c >> 2; i--;) { -+ *dst = fb_readl(src++); -+ *dst = -+ (*dst & 0xff00ff00 >> 8) | (*dst & 0x00ff00ff << 8); -+ dst++; -+ } -+ if (c & 3) { -+ u8 *dst8 = (u8 *) dst; -+ u8 __iomem *src8 = (u8 __iomem *) src; -+ -+ for (i = c & 3; i--;) { -+ if (i & 1) { -+ *dst8++ = fb_readb(++src8); -+ } else { -+ *dst8++ = fb_readb(--src8); -+ src8 += 2; -+ } -+ } -+ src = (u32 __iomem *) src8; -+ } -+ -+ if (copy_to_user(buf, buffer, c)) { -+ err = -EFAULT; -+ break; -+ } -+ *ppos += c; -+ buf += c; -+ cnt += c; -+ count -= c; -+ } -+ -+ kfree(buffer); -+ -+ return (err) ? err : cnt; -+} -+ -+static ssize_t -+sm712fb_write(struct fb_info *info, const char __user *buf, size_t count, -+ loff_t *ppos) -+{ -+ unsigned long p = *ppos; -+ -+ u32 *buffer, *src; -+ u32 __iomem *dst; -+ int c, i, cnt = 0, err = 0; -+ unsigned long total_size; -+ -+ if (!info || !info->screen_base) -+ return -ENODEV; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return -EPERM; -+ -+ total_size = info->screen_size; -+ -+ if (total_size == 0) -+ total_size = info->fix.smem_len; -+ -+ if (p > total_size) -+ return -EFBIG; -+ -+ if (count > total_size) { -+ err = -EFBIG; -+ count = total_size; -+ } -+ -+ if (count + p > total_size) { -+ if (!err) -+ err = -ENOSPC; -+ -+ count = total_size - p; -+ } -+ -+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ dst = (u32 __iomem *) (info->screen_base + p); -+ -+ if (info->fbops->fb_sync) -+ info->fbops->fb_sync(info); -+ -+ while (count) { -+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; -+ src = buffer; -+ -+ if (copy_from_user(src, buf, c)) { -+ err = -EFAULT; -+ break; -+ } -+ -+ for (i = c >> 2; i--;) { -+ fb_writel((*src & 0xff00ff00 >> 8) | -+ (*src & 0x00ff00ff << 8), dst++); -+ src++; -+ } -+ if (c & 3) { -+ u8 *src8 = (u8 *) src; -+ u8 __iomem *dst8 = (u8 __iomem *) dst; -+ -+ for (i = c & 3; i--;) { -+ if (i & 1) { -+ fb_writeb(*src8++, ++dst8); -+ } else { -+ fb_writeb(*src8++, --dst8); -+ dst8 += 2; -+ } -+ } -+ dst = (u32 __iomem *) dst8; -+ } -+ -+ *ppos += c; -+ buf += c; -+ cnt += c; -+ count -= c; -+ } -+ -+ kfree(buffer); -+ -+ return (cnt) ? cnt : err; -+} -+#endif /* ! __BIG_ENDIAN */ -+ -+static void sm712_set_timing(struct sm712fb_info *sfb) -+{ -+ int i = 0, j = 0; -+ u32 m_nScreenStride; -+ -+ dev_dbg(&sfb->pdev->dev, -+ "sfb->width=%d sfb->height=%d " -+ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n", -+ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz); -+ -+ for (j = 0; j < numVGAModes; j++) { -+ if (VGAMode[j].mmSizeX != sfb->width || -+ VGAMode[j].mmSizeY != sfb->height || -+ VGAMode[j].bpp != sfb->fb.var.bits_per_pixel || -+ VGAMode[j].hz != sfb->hz) { -+ continue; -+ } -+ -+ dev_dbg(&sfb->pdev->dev, -+ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d " -+ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n", -+ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, -+ VGAMode[j].bpp, VGAMode[j].hz); -+ -+ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j); -+ -+ sm712_writeb(sfb->mmio, 0x3c6, 0x0); -+ -+ sm712_write_seq(sfb, 0, 0x1); -+ -+ sm712_writeb(sfb->mmio, 0x3c2, VGAMode[j].Init_MISC); -+ -+ /* init SEQ register SR00 - SR04 */ -+ for (i = 0; i < SR00_SR04_SIZE; i++) -+ sm712_write_seq(sfb, i, VGAMode[j].Init_SR00_SR04[i]); -+ -+ /* init SEQ register SR10 - SR24 */ -+ for (i = 0; i < SR10_SR24_SIZE; i++) -+ sm712_write_seq(sfb, i + 0x10, -+ VGAMode[j].Init_SR10_SR24[i]); -+ -+ /* init SEQ register SR30 - SR75 */ -+ for (i = 0; i < SR30_SR75_SIZE; i++) -+ if ((i + 0x30) != 0x62 && -+ (i + 0x30) != 0x6a && (i + 0x30) != 0x6b) -+ sm712_write_seq(sfb, i + 0x30, -+ VGAMode[j].Init_SR30_SR75[i]); -+ -+ /* init SEQ register SR80 - SR93 */ -+ for (i = 0; i < SR80_SR93_SIZE; i++) -+ sm712_write_seq(sfb, i + 0x80, -+ VGAMode[j].Init_SR80_SR93[i]); -+ -+ /* init SEQ register SRA0 - SRAF */ -+ for (i = 0; i < SRA0_SRAF_SIZE; i++) -+ sm712_write_seq(sfb, i + 0xa0, -+ VGAMode[j].Init_SRA0_SRAF[i]); -+ -+ /* init Graphic register GR00 - GR08 */ -+ for (i = 0; i < GR00_GR08_SIZE; i++) -+ sm712_write_grph(sfb, i, VGAMode[j].Init_GR00_GR08[i]); -+ -+ /* init Attribute register AR00 - AR14 */ -+ for (i = 0; i < AR00_AR14_SIZE; i++) -+ sm712_write_attr(sfb, i, VGAMode[j].Init_AR00_AR14[i]); -+ -+ /* init CRTC register CR00 - CR18 */ -+ for (i = 0; i < CR00_CR18_SIZE; i++) -+ sm712_write_crtc(sfb, i, VGAMode[j].Init_CR00_CR18[i]); -+ -+ /* init CRTC register CR30 - CR4D */ -+ for (i = 0; i < CR30_CR4D_SIZE; i++) -+ sm712_write_crtc(sfb, i + 0x30, -+ VGAMode[j].Init_CR30_CR4D[i]); -+ -+ /* init CRTC register CR90 - CRA7 */ -+ for (i = 0; i < CR90_CRA7_SIZE; i++) -+ sm712_write_crtc(sfb, i + 0x90, -+ VGAMode[j].Init_CR90_CRA7[i]); -+ } -+ sm712_writeb(sfb->mmio, 0x3c2, 0x67); -+ -+ /* set VPR registers */ -+ sm712_writel(sfb->vpr, 0x0C, 0x0); -+ sm712_writel(sfb->vpr, 0x40, 0x0); -+ -+ /* set data width */ -+ m_nScreenStride = (sfb->width * sfb->fb.var.bits_per_pixel) / 64; -+ switch (sfb->fb.var.bits_per_pixel) { -+ case 8: -+ sm712_writel(sfb->vpr, 0x0, 0x0); -+ break; -+ case 16: -+ sm712_writel(sfb->vpr, 0x0, 0x00020000); -+ break; -+ case 24: -+ sm712_writel(sfb->vpr, 0x0, 0x00040000); -+ break; -+ case 32: -+ sm712_writel(sfb->vpr, 0x0, 0x00030000); -+ break; -+ } -+ sm712_writel(sfb->vpr, 0x10, -+ (u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride)); -+} -+ -+static void sm712fb_setmode(struct sm712fb_info *sfb) -+{ -+ switch (sfb->fb.var.bits_per_pixel) { -+ case 32: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 4; -+ sfb->fb.var.red.length = 8; -+ sfb->fb.var.green.length = 8; -+ sfb->fb.var.blue.length = 8; -+ sfb->fb.var.red.offset = 16; -+ sfb->fb.var.green.offset = 8; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 24: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 3; -+ sfb->fb.var.red.length = 8; -+ sfb->fb.var.green.length = 8; -+ sfb->fb.var.blue.length = 8; -+ sfb->fb.var.red.offset = 16; -+ sfb->fb.var.green.offset = 8; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 8: -+ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres; -+ sfb->fb.var.red.length = 3; -+ sfb->fb.var.green.length = 3; -+ sfb->fb.var.blue.length = 2; -+ sfb->fb.var.red.offset = 5; -+ sfb->fb.var.green.offset = 2; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ case 16: -+ default: -+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ sfb->fb.fix.line_length = sfb->fb.var.xres * 2; -+ sfb->fb.var.red.length = 5; -+ sfb->fb.var.green.length = 6; -+ sfb->fb.var.blue.length = 5; -+ sfb->fb.var.red.offset = 11; -+ sfb->fb.var.green.offset = 5; -+ sfb->fb.var.blue.offset = 0; -+ break; -+ } -+ -+ sfb->width = sfb->fb.var.xres; -+ sfb->height = sfb->fb.var.yres; -+ sfb->hz = 60; -+ sm712_set_timing(sfb); -+} -+ -+static int sm712_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ /* sanity checks */ -+ if (var->xres_virtual < var->xres) -+ var->xres_virtual = var->xres; -+ -+ if (var->yres_virtual < var->yres) -+ var->yres_virtual = var->yres; -+ -+ /* set valid default bpp */ -+ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && -+ (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) -+ var->bits_per_pixel = 16; -+ -+ return 0; -+} -+ -+static int sm712_set_par(struct fb_info *info) -+{ -+ sm712fb_setmode(info->par); -+ -+ return 0; -+} -+ -+static struct fb_ops sm712fb_ops = { -+ .owner = THIS_MODULE, -+ .fb_check_var = sm712_check_var, -+ .fb_set_par = sm712_set_par, -+ .fb_setcolreg = sm712_setcolreg, -+ .fb_blank = sm712_blank, -+ .fb_fillrect = cfb_fillrect, -+ .fb_imageblit = cfb_imageblit, -+ .fb_copyarea = cfb_copyarea, -+#ifdef __BIG_ENDIAN -+ .fb_read = sm712fb_read, -+ .fb_write = sm712fb_write, -+#endif -+}; -+ -+/* -+ * alloc struct sm712fb_info and assign default values -+ */ -+static struct sm712fb_info *sm712_fb_info_new(struct pci_dev *pdev) -+{ -+ struct sm712fb_info *sfb; -+ -+ sfb = kzalloc(sizeof(*sfb), GFP_KERNEL); -+ -+ if (!sfb) -+ return NULL; -+ -+ sfb->pdev = pdev; -+ -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT; -+ sfb->fb.fbops = &sm712fb_ops; -+ sfb->fb.fix = sm712fb_fix; -+ sfb->fb.var = sm712fb_var; -+ sfb->fb.pseudo_palette = sfb->colreg; -+ sfb->fb.par = sfb; -+ sfb->accel = accel; -+ -+ return sfb; -+} -+ -+/* -+ * free struct sm712fb_info -+ */ -+static void sm712_fb_info_free(struct sm712fb_info *sfb) -+{ -+ kfree(sfb); -+} -+ -+/* -+ * Map in the screen memory -+ */ -+ -+static int sm712_map_smem(struct sm712fb_info *sfb, -+ struct pci_dev *pdev, u_long smem_len) -+{ -+ -+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); -+ -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 32) -+ sfb->fb.fix.smem_start += 0x800000; -+#endif -+ -+ sfb->fb.fix.smem_len = smem_len; -+ -+ sfb->fb.screen_base = sfb->lfb; -+ -+ if (!sfb->fb.screen_base) { -+ dev_err(&pdev->dev, -+ "%s: unable to map screen memory\n", sfb->fb.fix.id); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Unmap in the screen memory -+ * -+ */ -+static void sm712_unmap_smem(struct sm712fb_info *sfb) -+{ -+ if (sfb && sfb->fb.screen_base) { -+ iounmap(sfb->fb.screen_base); -+ sfb->fb.screen_base = NULL; -+ sfb->lfb = NULL; -+ } -+} -+ -+static inline void sm712_init_hw(struct sm712fb_info *sfb) -+{ -+ /* enable linear memory mode and packed pixel format */ -+ outb_p(0x18, 0x3c4); -+ outb_p(0x11, 0x3c5); -+ -+ /* set MCLK = 14.31818 * (0x16 / 0x2) */ -+ sm712_write_seq(sfb, 0x6a, 0x16); -+ sm712_write_seq(sfb, 0x6b, 0x02); -+ sm712_write_seq(sfb, 0x62, 0x3e); -+ -+ /* enable PCI burst */ -+ sm712_write_seq(sfb, 0x17, 0x20); -+ -+#ifdef __BIG_ENDIAN -+ /* enable word swap */ -+ if (sfb->fb.var.bits_per_pixel == 32) -+ sm712_write_seq(sfb, 0x17, 0x30); -+#endif -+ -+ if (!sfb->accel) { -+ dev_info(&sfb->pdev->dev, "2d acceleration was disabled by user.\n"); -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; -+ return; -+ } -+ -+ if (sm712fb_init_accel(sfb) < 0) { -+ dev_info(&sfb->pdev->dev, "failed to enable 2d accleration.\n"); -+ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; -+ return; -+ } else { -+ sm712fb_ops.fb_fillrect = sm712fb_fillrect; -+ sm712fb_ops.fb_copyarea = sm712fb_copyarea; -+ sm712fb_ops.fb_imageblit = sm712fb_imageblit; -+ sfb->fb.flags |= FBINFO_HWACCEL_COPYAREA | -+ FBINFO_HWACCEL_FILLRECT | -+ FBINFO_HWACCEL_IMAGEBLIT | -+ FBINFO_READS_FAST; -+ dev_info(&sfb->pdev->dev, "sm712fb: enable 2d acceleration.\n"); -+ } -+} -+ -+static int sm712fb_pci_probe(struct pci_dev *pdev, -+ const struct pci_device_id *ent) -+{ -+ struct sm712fb_info *sfb; -+ int err; -+ unsigned long mmio_base; -+ -+#ifndef MODULE -+ char *option = NULL; -+ -+ if (!fb_get_options("sm712fb", &option)) -+ sm712fb_setup(option); -+#endif -+ -+ dev_info(&pdev->dev, "Silicon Motion display driver."); -+ -+ err = pci_enable_device(pdev); /* enable SMTC chip */ -+ if (err) -+ return err; -+ -+ sprintf(sm712fb_fix.id, "sm712fb"); -+ -+ sfb = sm712_fb_info_new(pdev); -+ -+ if (!sfb) { -+ err = -ENOMEM; -+ goto free_fail; -+ } -+ -+ sfb->chip_id = ent->device; -+ -+ pci_set_drvdata(pdev, sfb); -+ -+ /* get mode parameter from sm712_scr_info */ -+ if (sm712_scr_info.lfb_width != 0) { -+ sfb->fb.var.xres = sm712_scr_info.lfb_width; -+ sfb->fb.var.yres = sm712_scr_info.lfb_height; -+ sfb->fb.var.bits_per_pixel = sm712_scr_info.lfb_depth; -+ } else { -+ /* default resolution 1024x600 16bit mode */ -+ sfb->fb.var.xres = SM712_DEFAULT_XRES; -+ sfb->fb.var.yres = SM712_DEFAULT_YRES; -+ sfb->fb.var.bits_per_pixel = SM712_DEFAULT_BPP; -+ } -+ -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 24) -+ sfb->fb.var.bits_per_pixel = (sm712_scr_info.lfb_depth = 32); -+#endif -+ -+ /* Map address and memory detection */ -+ mmio_base = pci_resource_start(pdev, 0); -+ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); -+ -+ if (sfb->chip_id != 0x712) { -+ dev_err(&pdev->dev, -+ "No valid Silicon Motion display chip was detected!"); -+ -+ goto fb_fail; -+ } -+ -+ sfb->fb.fix.mmio_start = mmio_base + SM712_REG_BASE; -+ sfb->fb.fix.mmio_len = SM712_REG_SIZE; -+#ifdef __BIG_ENDIAN -+ sfb->lfb = ioremap(mmio_base, 0x00c00000); -+#else -+ sfb->lfb = ioremap(mmio_base, 0x00800000); -+#endif -+ sfb->mmio = sfb->lfb + SM712_MMIO_BASE; -+ sfb->dpr = sfb->lfb + SM712_DPR_BASE; -+ sfb->vpr = sfb->lfb + SM712_VPR_BASE; -+ sfb->dataport = sfb->lfb + SM712_DATAPORT_BASE; -+#ifdef __BIG_ENDIAN -+ if (sfb->fb.var.bits_per_pixel == 32) { -+ sfb->lfb += 0x800000; -+ dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb); -+ } -+#endif -+ if (!sfb->mmio) { -+ dev_err(&pdev->dev, -+ "%s: unable to map memory mapped IO!", sfb->fb.fix.id); -+ err = -ENOMEM; -+ goto fb_fail; -+ } -+ -+ sm712_init_hw(sfb); -+ -+ /* can support 32 bpp */ -+ if (15 == sfb->fb.var.bits_per_pixel) -+ sfb->fb.var.bits_per_pixel = 16; -+ -+ sfb->fb.var.xres_virtual = sfb->fb.var.xres; -+ sfb->fb.var.yres_virtual = sfb->fb.var.yres; -+ err = sm712_map_smem(sfb, pdev, SM712_VRAM_SIZE); -+ if (err) -+ goto fail; -+ -+ sm712fb_setmode(sfb); -+ -+ err = register_framebuffer(&sfb->fb); -+ if (err < 0) -+ goto fail; -+ -+ dev_info(&pdev->dev, -+ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.", -+ sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres, -+ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); -+ -+ return 0; -+ -+fail: -+ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail."); -+ -+ sm712_unmap_smem(sfb); -+fb_fail: -+ sm712_fb_info_free(sfb); -+free_fail: -+ pci_disable_device(pdev); -+ -+ return err; -+} -+ -+/* -+ * 0x712 (LynxEM+) -+ */ -+static const struct pci_device_id sm712fb_pci_table[] = { -+ {PCI_DEVICE(0x126f, 0x712),}, -+ {0,} -+}; -+ -+static void sm712fb_pci_remove(struct pci_dev *pdev) -+{ -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ sm712_unmap_smem(sfb); -+ unregister_framebuffer(&sfb->fb); -+ sm712_fb_info_free(sfb); -+} -+ -+#ifdef CONFIG_PM -+static int sm712fb_pci_suspend(struct device *device) -+{ -+ struct pci_dev *pdev = to_pci_dev(device); -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ -+ /* set the hw in sleep mode use external clock and self memory refresh -+ * so that we can turn off internal PLLs later on -+ */ -+ sm712_write_seq(sfb, 0x20, (sm712_read_seq(sfb, 0x20) | 0xc0)); -+ sm712_write_seq(sfb, 0x69, (sm712_read_seq(sfb, 0x69) & 0xf7)); -+ -+ console_lock(); -+ fb_set_suspend(&sfb->fb, 1); -+ console_unlock(); -+ -+ /* additionally turn off all function blocks including internal PLLs */ -+ sm712_write_seq(sfb, 0x21, 0xff); -+ -+ return 0; -+} -+ -+static int sm712fb_pci_resume(struct device *device) -+{ -+ struct pci_dev *pdev = to_pci_dev(device); -+ struct sm712fb_info *sfb; -+ -+ sfb = pci_get_drvdata(pdev); -+ -+ /* reinit hardware */ -+ sm712_init_hw(sfb); -+ -+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0xc0)); -+ sm712_write_seq(sfb, 0x33, ((sm712_read_seq(sfb, 0x33) | 0x08) & 0xfb)); -+ -+ sm712fb_setmode(sfb); -+ -+ console_lock(); -+ fb_set_suspend(&sfb->fb, 0); -+ console_unlock(); -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(sm712_pm_ops, sm712fb_pci_suspend, sm712fb_pci_resume); -+#define SM712_PM_OPS (&sm712_pm_ops) -+ -+#else /* !CONFIG_PM */ -+ -+#define SM712_PM_OPS NULL -+ -+#endif /* !CONFIG_PM */ -+ -+static struct pci_driver sm712fb_driver = { -+ .name = "sm712fb", -+ .id_table = sm712fb_pci_table, -+ .probe = sm712fb_pci_probe, -+ .remove = sm712fb_pci_remove, -+ .driver.pm = SM712_PM_OPS, -+}; -+ -+module_pci_driver(sm712fb_driver); -+ -+module_param(accel, bool, S_IRUGO); -+MODULE_PARM_DESC(accel, "Enable or disable 2D Acceleration"); -+ -+MODULE_AUTHOR("Siliconmotion "); -+MODULE_DESCRIPTION("Framebuffer driver for Silicon Motion SM712 Graphic Cards"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.h b/drivers/video/fbdev/sm712fb/sm712fb_drv.h -new file mode 100644 -index 0000000..bf81bff ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.h -@@ -0,0 +1,130 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Framebuffer driver for Silicon Motion SM712 chip -+ */ -+ -+#ifndef _SM712FB_DRV_H -+#define _SM712FB_DRV_H -+ -+/* -+* Private structure -+*/ -+struct sm712fb_info { -+ struct pci_dev *pdev; -+ struct fb_info fb; -+ u16 chip_id; -+ u8 chip_rev_id; -+ -+ void __iomem *lfb; /* linear frame buffer, the base address */ -+ -+ void __iomem *dpr; /* drawing processor control regs */ -+ void __iomem *vpr; /* video processor control regs */ -+ void __iomem *cpr; /* capture processor control regs */ -+ void __iomem *mmio; /* memory map IO port */ -+ void __iomem *dataport; /* 2d drawing engine data port */ -+ -+ u_int width; -+ u_int height; -+ u_int hz; -+ -+ u32 colreg[17]; -+ -+ bool accel; -+}; -+ -+/* constants for registers operations */ -+ -+#include "sm712fb_io.h" -+ -+#define FB_ACCEL_SMI_LYNX 88 -+ -+#define SM712_DEFAULT_XRES 1024 -+#define SM712_DEFAULT_YRES 600 -+#define SM712_DEFAULT_BPP 16 -+ -+#define SM712_VRAM_SIZE 0x00400000 -+ -+#define SM712_REG_BASE 0x00400000 -+#define SM712_REG_SIZE 0x00400000 -+ -+#define SM712_MMIO_BASE 0x00700000 -+ -+#define SM712_DPR_BASE 0x00408000 -+#define SM712_DPR_SIZE (0x6C + 1) -+ -+#define DPR_COORDS(x, y) (((x) << 16) | (y)) -+ -+#define DPR_SRC_COORDS 0x00 -+#define DPR_DST_COORDS 0x04 -+#define DPR_SPAN_COORDS 0x08 -+#define DPR_DE_CTRL 0x0c -+#define DPR_PITCH 0x10 -+#define DPR_FG_COLOR 0x14 -+#define DPR_BG_COLOR 0x18 -+#define DPR_STRETCH 0x1c -+#define DPR_COLOR_COMPARE 0x20 -+#define DPR_COLOR_COMPARE_MASK 0x24 -+#define DPR_BYTE_BIT_MASK 0x28 -+#define DPR_CROP_TOPLEFT_COORDS 0x2c -+#define DPR_CROP_BOTRIGHT_COORDS 0x30 -+#define DPR_SRC_WINDOW 0x3c -+#define DPR_SRC_BASE 0x40 -+#define DPR_DST_BASE 0x44 -+ -+#define DE_CTRL_START 0x80000000 -+#define DE_CTRL_RTOL 0x08000000 -+#define DE_CTRL_COMMAND_MASK 0x001f0000 -+#define DE_CTRL_COMMAND_SHIFT 16 -+#define DE_CTRL_COMMAND_BITBLT 0x00 -+#define DE_CTRL_COMMAND_SOLIDFILL 0x01 -+#define DE_CTRL_COMMAND_HOST_WRITE 0x08 -+#define DE_CTRL_ROP_ENABLE 0x00008000 -+#define DE_CTRL_ROP_MASK 0x000000ff -+#define DE_CTRL_ROP_SHIFT 0 -+#define DE_CTRL_ROP_SRC 0x0c -+ -+#define DE_CTRL_HOST_SHIFT 22 -+#define DE_CTRL_HOST_MONO 1 -+ -+#define SCR_DE_STATUS 0x16 -+#define SCR_DE_STATUS_MASK 0x18 -+#define SCR_DE_ENGINE_IDLE 0x10 -+ -+#define SM712_VPR_BASE 0x0040c000 -+#define SM712_VPR_SIZE (0x44 + 1) -+ -+#define SM712_DATAPORT_BASE 0x00400000 -+ -+#define SR00_SR04_SIZE (0x04 - 0x00 + 1) -+#define SR10_SR24_SIZE (0x24 - 0x10 + 1) -+#define SR30_SR75_SIZE (0x75 - 0x30 + 1) -+#define SR80_SR93_SIZE (0x93 - 0x80 + 1) -+#define SRA0_SRAF_SIZE (0xAF - 0xA0 + 1) -+#define GR00_GR08_SIZE (0x08 - 0x00 + 1) -+#define AR00_AR14_SIZE (0x14 - 0x00 + 1) -+#define CR00_CR18_SIZE (0x18 - 0x00 + 1) -+#define CR30_CR4D_SIZE (0x4D - 0x30 + 1) -+#define CR90_CRA7_SIZE (0xA7 - 0x90 + 1) -+ -+#define DAC_REG (0x3c8) -+#define DAC_VAL (0x3c9) -+ -+#endif -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_io.h b/drivers/video/fbdev/sm712fb/sm712fb_io.h -new file mode 100644 -index 0000000..93346a0 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_io.h -@@ -0,0 +1,90 @@ -+/* -+ * Silicon Motion SM712 frame buffer device -+ * -+ * Copyright (C) 2006 Silicon Motion Technology Corp. -+ * Authors: Ge Wang, gewang@siliconmotion.com -+ * Boyod boyod.yang@siliconmotion.com.cn -+ * -+ * Copyright (C) 2009 Lemote, Inc. -+ * Author: Wu Zhangjin, wuzhangjin@gmail.com -+ * -+ * Copyright (C) 2011 Igalia, S.L. -+ * Author: Javier M. Mellid -+ * -+ * Copyright (C) 2014 Tom Li. -+ * Author: Tom Li (Yifeng Li) -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ */ -+ -+ -+#define sm712_writeb(base, reg, dat) writeb(dat, base + reg) -+#define sm712_writew(base, reg, dat) writew(dat, base + reg) -+#define sm712_writel(base, reg, dat) writel(dat, base + reg) -+ -+#define sm712_readb(base, reg) readb(base + reg) -+#define sm712_readw(base, reg) readw(base + reg) -+#define sm712_readl(base, reg) readl(base + reg) -+ -+ -+static inline void sm712_write_crtc(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3d4, reg); -+ sm712_writeb(fb->mmio, 0x3d5, val); -+} -+ -+static inline u8 sm712_read_crtc(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3d4, reg); -+ return sm712_readb(fb->mmio, 0x3d5); -+} -+ -+static inline void sm712_write_grph(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3ce, reg); -+ sm712_writeb(fb->mmio, 0x3cf, val); -+} -+ -+static inline u8 sm712_read_grph(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3ce, reg); -+ return sm712_readb(fb->mmio, 0x3cf); -+} -+ -+static inline void sm712_write_attr(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_readb(fb->mmio, 0x3da); -+ sm712_writeb(fb->mmio, 0x3c0, reg); -+ sm712_readb(fb->mmio, 0x3c1); -+ sm712_writeb(fb->mmio, 0x3c0, val); -+} -+ -+static inline void sm712_write_seq(struct sm712fb_info *fb, u8 reg, u8 val) -+{ -+ sm712_writeb(fb->mmio, 0x3c4, reg); -+ sm712_writeb(fb->mmio, 0x3c5, val); -+} -+ -+static inline u8 sm712_read_seq(struct sm712fb_info *fb, u8 reg) -+{ -+ sm712_writeb(fb->mmio, 0x3c4, reg); -+ return sm712_readb(fb->mmio, 0x3c5); -+} -+ -+static inline u32 sm712_read_dpr(struct sm712fb_info *fb, u8 reg) -+{ -+ return sm712_readl(fb->dpr, reg); -+} -+ -+static inline void sm712_write_dpr(struct sm712fb_info *fb, u8 reg, u32 val) -+{ -+ sm712_writel(fb->dpr, reg, val); -+} -+ -+static inline void sm712_write_dataport(struct sm712fb_info *fb, u32 val) -+{ -+ sm712_writel(fb->dataport, 0, val); -+} -diff --git a/drivers/video/fbdev/sm712fb/sm712fb_modedb.h b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h -new file mode 100644 -index 0000000..16ee7e3 ---- /dev/null -+++ b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h -@@ -0,0 +1,682 @@ -+/* The next structure holds all information relevant for a specific video mode. -+ */ -+ -+struct ModeInit { -+ int mmSizeX; -+ int mmSizeY; -+ int bpp; -+ int hz; -+ unsigned char Init_MISC; -+ unsigned char Init_SR00_SR04[SR00_SR04_SIZE]; -+ unsigned char Init_SR10_SR24[SR10_SR24_SIZE]; -+ unsigned char Init_SR30_SR75[SR30_SR75_SIZE]; -+ unsigned char Init_SR80_SR93[SR80_SR93_SIZE]; -+ unsigned char Init_SRA0_SRAF[SRA0_SRAF_SIZE]; -+ unsigned char Init_GR00_GR08[GR00_GR08_SIZE]; -+ unsigned char Init_AR00_AR14[AR00_AR14_SIZE]; -+ unsigned char Init_CR00_CR18[CR00_CR18_SIZE]; -+ unsigned char Init_CR30_CR4D[CR30_CR4D_SIZE]; -+ unsigned char Init_CR90_CRA7[CR90_CRA7_SIZE]; -+}; -+ -+/********************************************************************** -+ SM712 Mode table. -+ **********************************************************************/ -+struct ModeInit VGAMode[] = { -+ { -+ /* mode#0: 640 x 480 16Bpp 60Hz */ -+ 640, 480, 16, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ { -+ /* mode#1: 640 x 480 24Bpp 60Hz */ -+ 640, 480, 24, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ { -+ /* mode#0: 640 x 480 32Bpp 60Hz */ -+ 640, 480, 32, 60, -+ /* Init_MISC */ -+ 0xE3, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, -+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, -+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, -+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, -+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, -+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, -+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, -+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, -+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, -+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, -+ }, -+ }, -+ -+ { /* mode#2: 800 x 600 16Bpp 60Hz */ -+ 800, 600, 16, 60, -+ /* Init_MISC */ -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, -+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, -+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ { /* mode#3: 800 x 600 24Bpp 60Hz */ -+ 800, 600, 24, 60, -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, -+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, -+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ { /* mode#7: 800 x 600 32Bpp 60Hz */ -+ 800, 600, 32, 60, -+ /* Init_MISC */ -+ 0x2B, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, -+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, -+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, -+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, -+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, -+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, -+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, -+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, -+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, -+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, -+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, -+ }, -+ }, -+ /* We use 1024x768 table to light 1024x600 panel for lemote */ -+ { /* mode#4: 1024 x 600 16Bpp 60Hz */ -+ 1024, 600, 16, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x00, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, -+ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x00, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, -+ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, -+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, -+ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, -+ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#5: 1024 x 768 24Bpp 60Hz */ -+ 1024, 768, 24, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x30, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, -+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#4: 1024 x 768 32Bpp 60Hz */ -+ 1024, 768, 32, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, -+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ { /* mode#6: 320 x 240 16Bpp 60Hz */ -+ 320, 240, 16, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, -+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+ -+ { /* mode#8: 320 x 240 32Bpp 60Hz */ -+ 320, 240, 32, 60, -+ /* Init_MISC */ -+ 0xEB, -+ { /* Init_SR0_SR4 */ -+ 0x03, 0x01, 0x0F, 0x03, 0x0E, -+ }, -+ { /* Init_SR10_SR24 */ -+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, -+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xC4, 0x32, 0x02, 0x01, 0x01, -+ }, -+ { /* Init_SR30_SR75 */ -+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, -+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, -+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, -+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, -+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, -+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, -+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, -+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, -+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, -+ }, -+ { /* Init_SR80_SR93 */ -+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, -+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, -+ 0x00, 0x00, 0x00, 0x00, -+ }, -+ { /* Init_SRA0_SRAF */ -+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, -+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, -+ }, -+ { /* Init_GR00_GR08 */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, -+ 0xFF, -+ }, -+ { /* Init_AR00_AR14 */ -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -+ 0x41, 0x00, 0x0F, 0x00, 0x00, -+ }, -+ { /* Init_CR00_CR18 */ -+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, -+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, -+ 0xFF, -+ }, -+ { /* Init_CR30_CR4D */ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, -+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, -+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, -+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, -+ }, -+ { /* Init_CR90_CRA7 */ -+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, -+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, -+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, -+ }, -+ }, -+}; -+ -+#define numVGAModes ARRAY_SIZE(VGAMode) -diff --git a/drivers/video/output.c b/drivers/video/output.c -new file mode 100644 -index 0000000..1446c49 ---- /dev/null -+++ b/drivers/video/output.c -@@ -0,0 +1,133 @@ -+/* -+ * output.c - Display Output Switch driver -+ * -+ * Copyright (C) 2006 Luming Yu -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+ -+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Luming Yu "); -+ -+static ssize_t state_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ ssize_t ret_size = 0; -+ struct output_device *od = to_output_device(dev); -+ if (od->props) -+ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); -+ return ret_size; -+} -+ -+static ssize_t state_store(struct device *dev, struct device_attribute *attr, -+ const char *buf,size_t count) -+{ -+ char *endp; -+ struct output_device *od = to_output_device(dev); -+ int request_state = simple_strtoul(buf,&endp,0); -+ size_t size = endp - buf; -+ -+ if (isspace(*endp)) -+ size++; -+ if (size != count) -+ return -EINVAL; -+ -+ if (od->props) { -+ od->request_state = request_state; -+ od->props->set_state(od); -+ } -+ return count; -+} -+static DEVICE_ATTR_RW(state); -+ -+static void video_output_release(struct device *dev) -+{ -+ struct output_device *od = to_output_device(dev); -+ kfree(od); -+} -+ -+static struct attribute *video_output_attrs[] = { -+ &dev_attr_state.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(video_output); -+ -+static struct class video_output_class = { -+ .name = "video_output", -+ .dev_release = video_output_release, -+ .dev_groups = video_output_groups, -+}; -+ -+struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op) -+{ -+ struct output_device *new_dev; -+ int ret_code = 0; -+ -+ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); -+ if (!new_dev) { -+ ret_code = -ENOMEM; -+ goto error_return; -+ } -+ new_dev->props = op; -+ new_dev->dev.class = &video_output_class; -+ new_dev->dev.parent = dev; -+ dev_set_name(&new_dev->dev, "%s", name); -+ dev_set_drvdata(&new_dev->dev, devdata); -+ ret_code = device_register(&new_dev->dev); -+ if (ret_code) { -+ kfree(new_dev); -+ goto error_return; -+ } -+ return new_dev; -+ -+error_return: -+ return ERR_PTR(ret_code); -+} -+EXPORT_SYMBOL(video_output_register); -+ -+void video_output_unregister(struct output_device *dev) -+{ -+ if (!dev) -+ return; -+ device_unregister(&dev->dev); -+} -+EXPORT_SYMBOL(video_output_unregister); -+ -+static void __exit video_output_class_exit(void) -+{ -+ class_unregister(&video_output_class); -+} -+ -+static int __init video_output_class_init(void) -+{ -+ return class_register(&video_output_class); -+} -+ -+postcore_initcall(video_output_class_init); -+module_exit(video_output_class_exit); -diff --git a/include/linux/sm501.h b/include/linux/sm501.h -index 02fde50..a8677f0 100644 ---- a/include/linux/sm501.h -+++ b/include/linux/sm501.h -@@ -27,6 +27,9 @@ extern unsigned long sm501_set_clock(struct device *dev, - extern unsigned long sm501_find_clock(struct device *dev, - int clksrc, unsigned long req_freq); - -+extern void sm501_configure_gpio(struct device *dev, -+ unsigned int gpio, unsigned char mode); -+ - /* sm501_misc_control - * - * Modify the SM501's MISC_CONTROL register -@@ -122,6 +125,7 @@ struct sm501_reg_init { - #define SM501_USE_AC97 (1<<7) - #define SM501_USE_I2S (1<<8) - #define SM501_USE_GPIO (1<<9) -+#define SM501_USE_PWM (1<<10) - - #define SM501_USE_ALL (0xffffffff) - -diff --git a/include/linux/video_output.h b/include/linux/video_output.h -new file mode 100644 -index 0000000..ed5cdeb ---- /dev/null -+++ b/include/linux/video_output.h -@@ -0,0 +1,57 @@ -+/* -+ * -+ * Copyright (C) 2006 Luming Yu -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ */ -+#ifndef _LINUX_VIDEO_OUTPUT_H -+#define _LINUX_VIDEO_OUTPUT_H -+#include -+#include -+struct output_device; -+struct output_properties { -+ int (*set_state)(struct output_device *); -+ int (*get_status)(struct output_device *); -+}; -+struct output_device { -+ int request_state; -+ struct output_properties *props; -+ struct device dev; -+}; -+#define to_output_device(obj) container_of(obj, struct output_device, dev) -+#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE) -+struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op); -+void video_output_unregister(struct output_device *dev); -+#else -+static struct output_device *video_output_register(const char *name, -+ struct device *dev, -+ void *devdata, -+ struct output_properties *op) -+{ -+ return ERR_PTR(-ENODEV); -+} -+static void video_output_unregister(struct output_device *dev) -+{ -+ return; -+} -+#endif -+#endif -diff --git a/init/calibrate.c b/init/calibrate.c -index ce635dc..10e775d 100644 ---- a/init/calibrate.c -+++ b/init/calibrate.c -@@ -21,6 +21,7 @@ static int __init lpj_setup(char *str) - - __setup("lpj=", lpj_setup); - -+#ifndef ARCH_HAS_PREPARED_LPJ - #ifdef ARCH_HAS_READ_CURRENT_TIMER - - /* This routine uses the read_current_timer() routine and gets the -@@ -171,6 +172,7 @@ static unsigned long calibrate_delay_direct(void) - return 0; - } - #endif -+#endif /* ARCH_HAS_PREPARED_LPJ */ - - /* - * This is the number of bits of precision for the loops_per_jiffy. Each -@@ -291,6 +293,7 @@ void calibrate_delay(void) - lpj = lpj_fine; - pr_info("Calibrating delay loop (skipped), " - "value calculated using timer frequency.. "); -+#ifndef ARCH_HAS_PREPARED_LPJ - } else if ((lpj = calibrate_delay_is_known())) { - ; - } else if ((lpj = calibrate_delay_direct()) != 0) { -@@ -301,6 +304,7 @@ void calibrate_delay(void) - if (!printed) - pr_info("Calibrating delay loop... "); - lpj = calibrate_delay_converge(); -+#endif /* ARCH_HAS_PREPARED_LPJ */ - } - per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj; - if (!printed) -diff --git a/net/rfkill/core.c b/net/rfkill/core.c -index fa7cd79..616abb5 100644 ---- a/net/rfkill/core.c -+++ b/net/rfkill/core.c -@@ -111,7 +111,7 @@ static LIST_HEAD(rfkill_list); /* list of registered rf switches */ - static DEFINE_MUTEX(rfkill_global_mutex); - static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ - --static unsigned int rfkill_default_state = 1; -+static unsigned int rfkill_default_state; /* default: 0 = radio off */ - module_param_named(default_state, rfkill_default_state, uint, 0444); - MODULE_PARM_DESC(default_state, - "Default initial state for all radio types, 0 = radio off"); -diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl -index 826470d..9e6dc30 100755 ---- a/scripts/recordmcount.pl -+++ b/scripts/recordmcount.pl -@@ -309,14 +309,33 @@ if ($arch eq "x86_64") { - $cc .= " -m64"; - $objcopy .= " -O elf64-sparc"; - } elsif ($arch eq "mips") { -- # To enable module support, we need to enable the -mlong-calls option -- # of gcc for module, after using this option, we can not get the real -- # offset of the calling to _mcount, but the offset of the lui -- # instruction or the addiu one. herein, we record the address of the -- # first one, and then we can replace this instruction by a branch -- # instruction to jump over the profiling function to filter the -- # indicated functions, or swith back to the lui instruction to trace -- # them, which means dynamic tracing. -+ # -+ # To disable tracing, just replace "jal _mcount" with nop; -+ # to enable tracing, replace back. so, the offset 14 is -+ # needed to be recorded. -+ # -+ # 10: 03e0082d move at,ra -+ # 14: 0c000000 jal 0 -+ # 14: R_MIPS_26 _mcount -+ # 14: R_MIPS_NONE *ABS* -+ # 14: R_MIPS_NONE *ABS* -+ # 18: 00020021 nop -+ # -+ # -+ # -+ # If no long call(-mlong-calls), the same to kernel. -+ # -+ # If the module space differs from the kernel space, long -+ # call is needed, as a result, the address of _mcount is -+ # needed to be recorded in a register and then jump from -+ # module space to kernel space via "jalr ". To -+ # disable tracing, "jalr " can be replaced by -+ # nop; to enable tracing, replace it back. Since the -+ # offset of "jalr " is not easy to be matched, -+ # the offset of the 1st _mcount below is recorded and to -+ # disable tracing, "lui v1, 0x0" is substituted with "b -+ # label", which jumps over "jalr "; to enable -+ # tracing, replace it back. - # - # c: 3c030000 lui v1,0x0 - # c: R_MIPS_HI16 _mcount -@@ -328,19 +347,12 @@ if ($arch eq "x86_64") { - # 10: R_MIPS_NONE *ABS* - # 14: 03e0082d move at,ra - # 18: 0060f809 jalr v1 -+ # label: - # -- # for the kernel: -- # -- # 10: 03e0082d move at,ra -- # 14: 0c000000 jal 0 -- # 14: R_MIPS_26 _mcount -- # 14: R_MIPS_NONE *ABS* -- # 14: R_MIPS_NONE *ABS* -- # 18: 00020021 nop - if ($is_module eq "0") { - $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$"; - } else { -- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$"; -+ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_(HI16|26)\\s+_mcount\$"; - } - $objdump .= " -Melf-trad".$endian."mips "; - -diff --git a/scripts/sstrip.sh b/scripts/sstrip.sh -new file mode 100755 -index 0000000..49b973a ---- /dev/null -+++ b/scripts/sstrip.sh -@@ -0,0 +1,59 @@ -+#!/bin/bash -+# sstrip.sh -- strip the section table of an elf file -+# -+# Copyright (C) 2010 Wu Zhangjin, wuzhangjin@gmail.com -+# Licensed under the GPLv2 -+# -+# Since the section table is useless for the embedded device, it can be -+# stripped out. -+# -+# Note: Some bootloader may check the section table but most of the time, it -+# may be not really used, If it really need the section table, it may need the -+# decompressed kernel image. -+ -+# Usage -+ -+function usage -+{ -+cat </dev/null` -+[ "xELF" != "x${FILE_TYPE}" ] && echo "$0: ${IMAGE} is not an ELF file" && exit -1 -+ -+[ "x${V}" == "x1" ] && orig_filesz=`wc -c ${IMAGE} | cut -d' ' -f1` -+ -+# Get the offset of the section table, here get the end of the program section -+filesz=$((`${OBJDUMP} -p ${IMAGE} | grep -m1 filesz | tr -s ' ' | cut -d' ' -f3`)) -+ -+# Truncate it via the dd tool -+dd if=/dev/null bs=1 of=${IMAGE} seek=${filesz} 2>/dev/null -+ -+# Clear the section table information in the ELF header -+# The last 6 bytes of the ELF header are the section table information -+echo -ne "\x00\x00\x00\x00\x00\x00" | dd of=${IMAGE} bs=1 seek=46 count=6 conv=notrunc 2>/dev/null -+ -+# Debug -+if [ "x${V}" == "x1" ]; then -+ echo "----------------------------------------------------------------" -+ echo "Strip the section table at ${filesz} of ${IMAGE}" -+ echo "----------------------------------------------------------------" -+ echo " sstrip: $0" -+ echo " objdump: ${OBJDUMP}" -+ echo "original size: ${orig_filesz}" -+ echo "current size: ${filesz}" -+ echo "reduced size: $((${orig_filesz} - ${filesz}))" -+fi diff --git a/libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch b/libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch new file mode 100644 index 000000000..c550ff3da --- /dev/null +++ b/libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch @@ -0,0 +1,12168 @@ +diff --git a/Makefile b/Makefile +index 0649a60..d43fa5e 100644 +--- a/Makefile ++++ b/Makefile +@@ -297,8 +297,8 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + + HOSTCC = gcc + HOSTCXX = g++ +-HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 +-HOSTCXXFLAGS = -O2 ++HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O3 -fomit-frame-pointer -std=gnu89 ++HOSTCXXFLAGS = -O3 + + ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1) + HOSTCFLAGS += -Wno-unused-value -Wno-unused-parameter \ +@@ -616,7 +616,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE + KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) + else +-KBUILD_CFLAGS += -O2 ++KBUILD_CFLAGS += -O3 + endif + + # Tell gcc to never replace conditional load with a non-conditional one +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index c7a1690..0f854f0 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -333,7 +333,7 @@ config LASAT + + config MACH_LOONGSON + bool "Loongson family of machines" +- select SYS_SUPPORTS_ZBOOT ++ select SYS_SUPPORTS_ZBOOT_UART16550 + help + This enables the support of Loongson family of machines. + +@@ -1640,6 +1640,15 @@ config CPU_LOONGSON2 + bool + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_64BIT_KERNEL ++ select CPU_SUPPORTS_HIGHMEM if ! EMBEDDED ++ select ARCH_WANT_OPTIONAL_GPIOLIB ++ ++config CPU_LOONGSON1 ++ bool ++ select CPU_MIPS32 ++ select CPU_MIPSR2 ++ select CPU_HAS_PREFETCH ++ select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select CPU_SUPPORTS_HUGEPAGES + +@@ -2313,7 +2322,7 @@ config CPU_SUPPORTS_MSA + + config ARCH_FLATMEM_ENABLE + def_bool y +- depends on !NUMA && !CPU_LOONGSON2 ++ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION) + + config ARCH_DISCONTIGMEM_ENABLE + bool +diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile +index 61af6b6..8598044 100644 +--- a/arch/mips/boot/compressed/Makefile ++++ b/arch/mips/boot/compressed/Makefile +@@ -30,9 +30,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ + targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o + + # decompressor objects (linked with vmlinuz) +-vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o ++vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o + + ifdef CONFIG_DEBUG_ZBOOT ++vmlinuzobjs-y += $(obj)/dbg.o + vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o + vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o + endif +@@ -79,9 +80,18 @@ quiet_cmd_zld = LD $@ + cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ + quiet_cmd_strip = STRIP $@ + cmd_strip = $(STRIP) -s $@ ++ifdef CONFIG_EMBEDDED ++quiet_cmd_sstrip = SSTRIP $@ ++ cmd_sstrip = $(srctree)/scripts/sstrip.sh $@ ++endif + vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr + $(call cmd,zld) + $(call cmd,strip) ++ $(call cmd,sstrip) ++ ++vmlinuz.unsstrip: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr ++ $(call cmd,zld) ++ $(call cmd,strip) + + # + # Some DECstations need all possible sections of an ECOFF executable +@@ -94,14 +104,14 @@ endif + hostprogs-y += ../elf2ecoff + + ifdef CONFIG_32BIT +- VMLINUZ = vmlinuz ++ VMLINUZ = vmlinuz.unsstrip + else + VMLINUZ = vmlinuz.32 + endif + + quiet_cmd_32 = OBJCOPY $@ + cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ +-vmlinuz.32: vmlinuz ++vmlinuz.32: vmlinuz.unsstrip + $(call cmd,32) + + quiet_cmd_ecoff = ECOFF $@ +@@ -110,11 +120,11 @@ vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ) + $(call cmd,ecoff) + + OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary +-vmlinuz.bin: vmlinuz ++vmlinuz.bin: vmlinuz.unsstrip + $(call cmd,objcopy) + + OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec +-vmlinuz.srec: vmlinuz ++vmlinuz.srec: vmlinuz.unsstrip + $(call cmd,objcopy) + +-clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} ++clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec,unsstrip} +diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c +index 31903cf..14da73c 100644 +--- a/arch/mips/boot/compressed/decompress.c ++++ b/arch/mips/boot/compressed/decompress.c +@@ -28,8 +28,13 @@ unsigned long free_mem_end_ptr; + extern unsigned char __image_begin, __image_end; + + /* debug interfaces */ ++#ifdef CONFIG_DEBUG_ZBOOT + extern void puts(const char *s); + extern void puthex(unsigned long long val); ++#else ++#define puts(s) ++#define puthex(val) ++#endif + + void error(char *x) + { +diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script +index 5a33409..de04ac9 100644 +--- a/arch/mips/boot/compressed/ld.script ++++ b/arch/mips/boot/compressed/ld.script +@@ -49,5 +49,6 @@ SECTIONS + *(.reginfo) + *(.comment) + *(.note) ++ *(.gnu.attributes) + } + } +diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h +index a0ee0cb..4e18add 100644 +--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h ++++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h +@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo); + /* GPIO : I/O SPACE; REG : 32BITS */ + #define GPIOL_OUT_VAL 0x00 + #define GPIOL_OUT_EN 0x04 ++#define GPIOL_OUT_AUX1_SEL 0x10 ++/* SMB : I/O SPACE, REG : 8BITS WIDTH */ ++#define SMB_SDA 0x00 ++#define SMB_STS 0x01 ++#define SMB_STS_SLVSTP (1 << 7) ++#define SMB_STS_SDAST (1 << 6) ++#define SMB_STS_BER (1 << 5) ++#define SMB_STS_NEGACK (1 << 4) ++#define SMB_STS_STASTR (1 << 3) ++#define SMB_STS_NMATCH (1 << 2) ++#define SMB_STS_MASTER (1 << 1) ++#define SMB_STS_XMIT (1 << 0) ++#define SMB_CTRL_STS 0x02 ++#define SMB_CSTS_TGSTL (1 << 5) ++#define SMB_CSTS_TSDA (1 << 4) ++#define SMB_CSTS_GCMTCH (1 << 3) ++#define SMB_CSTS_MATCH (1 << 2) ++#define SMB_CSTS_BB (1 << 1) ++#define SMB_CSTS_BUSY (1 << 0) ++#define SMB_CTRL1 0x03 ++#define SMB_CTRL1_STASTRE (1 << 7) ++#define SMB_CTRL1_NMINTE (1 << 6) ++#define SMB_CTRL1_GCMEN (1 << 5) ++#define SMB_CTRL1_ACK (1 << 4) ++#define SMB_CTRL1_RSVD (1 << 3) ++#define SMB_CTRL1_INTEN (1 << 2) ++#define SMB_CTRL1_STOP (1 << 1) ++#define SMB_CTRL1_START (1 << 0) ++#define SMB_ADDR 0x04 ++#define SMB_ADDR_SAEN (1 << 7) ++#define SMB_CONTROLLER_ADDR (0xef << 0) ++#define SMB_CTRL2 0x05 ++#define SMB_FREQ (0x20 << 1) ++#define SMB_ENABLE (0x01 << 0) ++#define SMB_CTRL3 0x06 + + #endif /* _CS5536_H */ +diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h +index 021d017..50aafca 100644 +--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h ++++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h +@@ -28,8 +28,19 @@ static inline void __maybe_unused enable_mfgpt0_counter(void) + #define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ) + + #define MFGPT_BASE mfgpt_base ++#define MFGPT0_CMP1 (MFGPT_BASE + 0) + #define MFGPT0_CMP2 (MFGPT_BASE + 2) + #define MFGPT0_CNT (MFGPT_BASE + 4) + #define MFGPT0_SETUP (MFGPT_BASE + 6) + ++#define MFGPT1_CMP1 (MFGPT_BASE + 0x08) ++#define MFGPT1_CMP2 (MFGPT_BASE + 0x0A) ++#define MFGPT1_CNT (MFGPT_BASE + 0x0C) ++#define MFGPT1_SETUP (MFGPT_BASE + 0x0E) ++ ++#define MFGPT2_CMP1 (MFGPT_BASE + 0x10) ++#define MFGPT2_CMP2 (MFGPT_BASE + 0x12) ++#define MFGPT2_CNT (MFGPT_BASE + 0x14) ++#define MFGPT2_SETUP (MFGPT_BASE + 0x16) ++ + #endif /*!_CS5536_MFGPT_H */ +diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h +index 5459ac0..14e82d9 100644 +--- a/arch/mips/include/asm/mach-loongson/loongson.h ++++ b/arch/mips/include/asm/mach-loongson/loongson.h +@@ -46,6 +46,12 @@ static inline void prom_init_uart_base(void) + #endif + } + ++/* ++ * Copy kernel command line from arcs_cmdline ++ */ ++#include ++extern char loongson_cmdline[COMMAND_LINE_SIZE]; ++ + /* irq operation functions */ + extern void bonito_irqdispatch(void); + extern void __init bonito_irq_init(void); +diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h +index cb2b602..78fcd38 100644 +--- a/arch/mips/include/asm/mach-loongson/machine.h ++++ b/arch/mips/include/asm/mach-loongson/machine.h +@@ -24,6 +24,12 @@ + + #endif + ++#ifdef CONFIG_DEXXON_GDIUM ++ ++#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10 ++ ++#endif ++ + #ifdef CONFIG_LOONGSON_MACH3X + + #define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC +diff --git a/arch/mips/include/asm/mach-loongson1/clock.h b/arch/mips/include/asm/mach-loongson1/clock.h +new file mode 100644 +index 0000000..dd1afdb +--- /dev/null ++++ b/arch/mips/include/asm/mach-loongson1/clock.h +@@ -0,0 +1,53 @@ ++#ifndef __ASM_MACH_LOONGSON1_CLOCK_H ++#define __ASM_MACH_LOONGSON1_CLOCK_H ++ ++#include ++#include ++#include ++#include ++ ++extern void (*cpu_wait) (void); ++ ++struct clk; ++ ++struct clk_ops { ++ void (*init) (struct clk *clk); ++ void (*enable) (struct clk *clk); ++ void (*disable) (struct clk *clk); ++ void (*recalc) (struct clk *clk); ++ int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id); ++ long (*round_rate) (struct clk *clk, unsigned long rate); ++}; ++ ++struct clk { ++ struct list_head node; ++ const char *name; ++ int id; ++ struct module *owner; ++ ++ struct clk *parent; ++ struct clk_ops *ops; ++ ++ struct kref kref; ++ ++ unsigned long rate; ++ unsigned long flags; ++}; ++ ++#define CLK_ALWAYS_ENABLED (1 << 0) ++#define CLK_RATE_PROPAGATES (1 << 1) ++ ++/* Should be defined by processor-specific code */ ++void arch_init_clk_ops(struct clk_ops **, int type); ++ ++int clk_init(void); ++ ++int __clk_enable(struct clk *); ++void __clk_disable(struct clk *); ++ ++void clk_recalc_rate(struct clk *); ++ ++int clk_register(struct clk *); ++void clk_unregister(struct clk *); ++ ++#endif /* __ASM_MIPS_CLOCK_H */ +diff --git a/arch/mips/include/asm/mach-loongson1/regs-intc.h b/arch/mips/include/asm/mach-loongson1/regs-intc.h +new file mode 100644 +index 0000000..6d5db23 +--- /dev/null ++++ b/arch/mips/include/asm/mach-loongson1/regs-intc.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (c) 2011 Zhang, Keguang ++ * ++ * Loongson1 Interrupt register definitions. ++ * ++ * 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. ++ */ ++ ++#ifndef __ASM_MACH_LOONGSON1_REGS_INTC_H ++#define __ASM_MACH_LOONGSON1_REGS_INTC_H ++ ++#define LS1X_INTC_REG(n, x) \ ++ (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4)) ++ ++#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) ++#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) ++#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) ++#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) ++#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) ++#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) ++ ++#endif /* __ASM_MACH_LOONGSON1_REGS_INTC_H */ +diff --git a/arch/mips/include/asm/sparsemem.h b/arch/mips/include/asm/sparsemem.h +index b1071c1..8b8e551 100644 +--- a/arch/mips/include/asm/sparsemem.h ++++ b/arch/mips/include/asm/sparsemem.h +@@ -11,7 +11,11 @@ + #else + # define SECTION_SIZE_BITS 28 + #endif +-#define MAX_PHYSMEM_BITS 48 ++#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit c461731836 broke Loongson2. */ ++# define MAX_PHYSMEM_BITS 48 ++#else ++# define MAX_PHYSMEM_BITS 35 ++#endif + + #endif /* CONFIG_SPARSEMEM */ + #endif /* _MIPS_SPARSEMEM_H */ +diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h +index b05bb70..44c9a69 100644 +--- a/arch/mips/include/asm/timex.h ++++ b/arch/mips/include/asm/timex.h +@@ -11,6 +11,10 @@ + + #ifdef __KERNEL__ + ++#ifdef CONFIG_CSRC_R4K ++#define ARCH_HAS_PREPARED_LPJ ++#endif ++ + #include + + #include +diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h +index fc0cf5a..99e6430 100644 +--- a/arch/mips/include/uapi/asm/inst.h ++++ b/arch/mips/include/uapi/asm/inst.h +@@ -65,6 +65,8 @@ enum spec_op { + enum spec2_op { + madd_op, maddu_op, mul_op, spec2_3_unused_op, + msub_op, msubu_op, /* more unused ops */ ++ loongson_madd_op = 0x18, loongson_msub_op, ++ loongson_nmadd_op, loongson_nmsub_op, + clz_op = 0x20, clo_op, + dclz_op = 0x24, dclo_op, + sdbpp_op = 0x3f +@@ -151,7 +153,7 @@ enum cop0_com_func { + */ + enum cop1_fmt { + s_fmt, d_fmt, e_fmt, q_fmt, +- w_fmt, l_fmt ++ w_fmt, l_fmt, ps_fmt + }; + + /* +@@ -180,7 +182,8 @@ enum cop1_sdw_func { + enum cop1x_func { + lwxc1_op = 0x00, ldxc1_op = 0x01, + swxc1_op = 0x08, sdxc1_op = 0x09, +- pfetch_op = 0x0f, madd_s_op = 0x20, ++ pfetch_op = 0x0f, ++ prefx_op = 0x17, madd_s_op = 0x20, + madd_d_op = 0x21, madd_e_op = 0x22, + msub_s_op = 0x28, msub_d_op = 0x29, + msub_e_op = 0x2a, nmadd_s_op = 0x30, +diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S +index d07b210..69996f2 100644 +--- a/arch/mips/kernel/scall64-o32.S ++++ b/arch/mips/kernel/scall64-o32.S +@@ -26,6 +26,18 @@ + + .align 5 + NESTED(handle_sys, PT_SIZE, sp) ++#ifdef CONFIG_MIPS_USER_RDTSC ++ MFC0 k0, CP0_EPC ++ lw k1, 0(k0) ++ sltiu k1, k1, 0x1c ++ bne k1, zero, 1f # Normal syscall code: 0x0c < 0x1c ++ nop ++ mfc0 v0, CP0_COUNT # Get TSC ++ PTR_ADDIU k0, 4 # ret from syscall ++ MTC0 k0, CP0_EPC ++ eret ++1: ++#endif /* CONFIG_MIPS_USER_RDTSC */ + .set noat + SAVE_SOME + TRACE_IRQS_ON_RELOAD +diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c +index 8d01709..9cd25da 100644 +--- a/arch/mips/kernel/time.c ++++ b/arch/mips/kernel/time.c +@@ -119,6 +119,11 @@ static __init int cpu_has_mfc0_count_bug(void) + + void __init time_init(void) + { ++#ifdef CONFIG_HR_SCHED_CLOCK ++ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug()) ++ write_c0_count(0); ++#endif ++ + plat_time_init(); + + /* +diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile +index 1e9e900..36fcccc 100644 +--- a/arch/mips/lib/Makefile ++++ b/arch/mips/lib/Makefile +@@ -2,10 +2,14 @@ + # Makefile for MIPS-specific library files.. + # + +-lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ ++lib-y += bitops.o csum_partial.o memcpy.o memset.o \ + mips-atomic.o strlen_user.o strncpy_user.o \ + strnlen_user.o uncached.o + ++ifndef CONFIG_CSRC_R4K ++lib-y += delay.o ++endif ++ + obj-y += iomap.o + obj-$(CONFIG_PCI) += iomap-pci.o + lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y)) +diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig +index 156de85..0a433e6 100644 +--- a/arch/mips/loongson/Kconfig ++++ b/arch/mips/loongson/Kconfig +@@ -32,12 +32,12 @@ config LEMOTE_FULOONG2E + + config LEMOTE_MACH2F + bool "Lemote Loongson 2F family machines" +- select ARCH_SPARSEMEM_ENABLE ++ select ARCH_SPARSEMEM_ENABLE if HIBERNATION + select BOARD_SCACHE + select BOOT_ELF32 + select CEVT_R4K if ! MIPS_EXTERNAL_TIMER + select CPU_HAS_WB +- select CS5536 ++ select CS5536 if PCI + select CSRC_R4K if ! MIPS_EXTERNAL_TIMER + select DMA_NONCOHERENT + select GENERIC_ISA_DMA_SUPPORT_BROKEN +@@ -45,14 +45,13 @@ config LEMOTE_MACH2F + select HW_HAS_PCI + select I8259 + select IRQ_CPU +- select ISA + select SYS_HAS_CPU_LOONGSON2F + select SYS_HAS_EARLY_PRINTK + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL +- select SYS_SUPPORTS_HIGHMEM ++ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED + select SYS_SUPPORTS_LITTLE_ENDIAN +- select LOONGSON_MC146818 ++ select LOONGSON_MC146818 if RTC_DRV_CMOS + help + Lemote Loongson 2F family machines utilize the 2F revision of + Loongson processor and the AMD CS5536 south bridge. +@@ -60,6 +59,31 @@ config LEMOTE_MACH2F + These family machines include fuloong2f mini PC, yeeloong2f notebook, + LingLoong allinone PC and so forth. + ++config DEXXON_GDIUM ++ bool "Dexxon Gdium Netbook" ++ select ARCH_SPARSEMEM_ENABLE ++ select BOARD_SCACHE ++ select BOOT_ELF32 ++ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER ++ select CPU_HAS_WB ++ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER ++ select DMA_NONCOHERENT ++ select GENERIC_ISA_DMA_SUPPORT_BROKEN ++ select HW_HAS_PCI ++ select I8259 ++ select IRQ_CPU ++ select ISA ++ select SYS_HAS_CPU_LOONGSON2F ++ select SYS_HAS_EARLY_PRINTK ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_64BIT_KERNEL ++ select SYS_SUPPORTS_HIGHMEM ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select ARCH_REQUIRE_GPIOLIB ++ select HAVE_PWM if MFD_SM501 ++ help ++ Dexxon gdium netbook based on Loongson 2F and SM502. ++ + config LOONGSON_MACH3X + bool "Generic Loongson 3 family machines" + select ARCH_SPARSEMEM_ENABLE +@@ -152,6 +176,24 @@ config LOONGSON_MC146818 + bool + default n + ++config GDIUM_PWM_CLOCK ++ tristate "Gdium PWM Timer" ++ default n ++ depends on HAVE_PWM && EXPERIMENTAL && BROKEN ++ select MIPS_EXTERNAL_TIMER ++ help ++ This options enables the experimental sm501-pwm based clock. With it, ++ you may be possible to use the loongson2f cpufreq driver. ++ ++config GDIUM_VERSION ++ int "Configure Gdium Version" ++ depends on DEXXON_GDIUM ++ default "3" ++ help ++ I have no information about how to determine which version your board ++ is, If the default config doesn't work for it, please change it to ++ smaller ones. ++ + config LEFI_FIRMWARE_INTERFACE + bool + +diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile +index 7429994..63214c8 100644 +--- a/arch/mips/loongson/Makefile ++++ b/arch/mips/loongson/Makefile +@@ -17,6 +17,12 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ + obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ + + # ++# Dexxon gdium netbook, based on loongson 2F and SM502 ++# ++ ++obj-$(CONFIG_DEXXON_GDIUM) += gdium/ ++ ++# + # All Loongson-3 family machines + # + +diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform +index 0ac20eb..cd957dd 100644 +--- a/arch/mips/loongson/Platform ++++ b/arch/mips/loongson/Platform +@@ -30,4 +30,5 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/ + cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely + load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 + load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 ++load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000 + load-$(CONFIG_LOONGSON_MACH3X) += 0xffffffff80200000 +diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c +index 72fed00..96d5919 100644 +--- a/arch/mips/loongson/common/cmdline.c ++++ b/arch/mips/loongson/common/cmdline.c +@@ -17,10 +17,15 @@ + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ ++#include + #include + + #include + ++/* the kernel command line copied from arcs_cmdline */ ++char loongson_cmdline[COMMAND_LINE_SIZE]; ++EXPORT_SYMBOL(loongson_cmdline); ++ + void __init prom_init_cmdline(void) + { + int prom_argc; +@@ -45,4 +50,31 @@ void __init prom_init_cmdline(void) + } + + prom_init_machtype(); ++ ++ /* append machine specific command line */ ++ switch (mips_machtype) { ++ case MACH_LEMOTE_LL2F: ++ if ((strstr(arcs_cmdline, "video=")) == NULL) ++ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60"); ++ break; ++ case MACH_LEMOTE_FL2F: ++ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL) ++ strcat(arcs_cmdline, " ide_core.ignore_cable=0"); ++ break; ++ case MACH_LEMOTE_ML2F7: ++ /* Mengloong-2F has a 800x480 screen */ ++ if ((strstr(arcs_cmdline, "vga=")) == NULL) ++ strcat(arcs_cmdline, " vga=0x313"); ++ break; ++ case MACH_DEXXON_GDIUM2F10: ++ /* gdium has a 1024x600 screen */ ++ if ((strstr(arcs_cmdline, "video=")) == NULL) ++ strcat(arcs_cmdline, " video=sm501fb:1024x600@60"); ++ break; ++ default: ++ break; ++ } ++ ++ /* copy arcs_cmdline into loongson_cmdline */ ++ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE); + } +diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c +index 045ea3d..1d1db80 100644 +--- a/arch/mips/loongson/common/env.c ++++ b/arch/mips/loongson/common/env.c +@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap; + struct loongson_system_configuration loongson_sysconf; + + u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; ++EXPORT_SYMBOL_GPL(loongson_chipcfg); + u64 loongson_freqctrl[MAX_PACKAGES]; + + unsigned long long smp_group[4]; +diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile +new file mode 100644 +index 0000000..f3f4f51 +--- /dev/null ++++ b/arch/mips/loongson/gdium/Makefile +@@ -0,0 +1,6 @@ ++# Makefile for gdium ++ ++obj-y += irq.o reset.o platform.o ++ ++obj-$(CONFIG_MFD_SM501) += sm501-pwm.o ++obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o +diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c +new file mode 100644 +index 0000000..fdbf42a +--- /dev/null ++++ b/arch/mips/loongson/gdium/gdium-clock.c +@@ -0,0 +1,234 @@ ++/* ++ * Doesn't work really well. When used, the clocksource is producing ++ * bad timings and the clockevent can't be used (don't have one shot feature ++ * thus can't switch on the fly and the pwm is initialised too late to be able ++ * to use it at boot time). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define CLOCK_PWM 1 ++#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */ ++#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ) ++#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */ ++#define CLOCK_PWM_DUTY 50 ++#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4) ++ ++static const char drv_name[] = "gdium-clock"; ++ ++static struct pwm_device *clock_pwm; ++ ++static DEFINE_SPINLOCK(clock_pwm_lock); ++static uint64_t clock_tick; ++ ++static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *cd = dev_id; ++ unsigned long flag; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ clock_tick++; ++ /* wait intn2 to finish */ ++ do { ++ LOONGSON_INTENCLR = (1 << 13); ++ } while (LOONGSON_INTISR & (1 << 13)); ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ ++ if (cd && cd->event_handler) ++ cd->event_handler(cd); ++ ++ return IRQ_HANDLED; ++} ++ ++static cycle_t gdium_pwm_clock_read(struct clocksource *cs) ++{ ++ unsigned long flag; ++ uint32_t jifs; ++ uint64_t ticks; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ jifs = jiffies; ++ ticks = clock_tick; ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ /* return (cycle_t)ticks; */ ++ return (cycle_t)(CLOCK_LATCH * jifs); ++} ++ ++static struct clocksource gdium_pwm_clock_clocksource = { ++ .name = "gdium_csrc", ++ .read = gdium_pwm_clock_read, ++ .mask = CLOCKSOURCE_MASK(64), ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY, ++ .shift = 20, ++}; ++ ++/* Debug fs */ ++static int gdium_pwm_clock_show(struct seq_file *s, void *p) ++{ ++ unsigned long flag; ++ uint64_t ticks; ++ ++ spin_lock_irqsave(&clock_pwm_lock, flag); ++ ticks = clock_tick; ++ spin_unlock_irqrestore(&clock_pwm_lock, flag); ++ seq_printf(s, "%lld\n", ticks); ++ return 0; ++} ++ ++static int gdium_pwm_clock_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, gdium_pwm_clock_show, inode->i_private); ++} ++ ++static const struct file_operations gdium_pwm_clock_fops = { ++ .open = gdium_pwm_clock_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++static struct dentry *debugfs_file; ++ ++static void gdium_pwm_clock_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ /* Nothing to do ... */ ++} ++ ++static struct clock_event_device gdium_pwm_clock_cevt = { ++ .name = "gdium_cevt", ++ .features = CLOCK_EVT_FEAT_PERIODIC, ++ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ ++ .rating = 299, ++ .irq = CLOCK_PWM_IRQ, ++ .set_mode = gdium_pwm_clock_set_mode, ++}; ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "gdium-pwmclk", ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver gdium_pwm_clock_driver = { ++ .driver = { ++ .name = drv_name, ++ .owner = THIS_MODULE, ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int gdium_pwm_clock_drvinit(void) ++{ ++ int ret; ++ struct clocksource *cs = &gdium_pwm_clock_clocksource; ++ struct clock_event_device *cd = &gdium_pwm_clock_cevt; ++ unsigned int cpu = smp_processor_id(); ++ ++ clock_tick = 0; ++ ++ clock_pwm = pwm_request(CLOCK_PWM, drv_name); ++ if (clock_pwm == NULL) { ++ pr_err("unable to request PWM for Gdium clock\n"); ++ return -EBUSY; ++ } ++ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD); ++ if (ret) { ++ pr_err("unable to configure PWM for Gdium clock\n"); ++ goto err_pwm_request; ++ } ++ ret = pwm_enable(clock_pwm); ++ if (ret) { ++ pr_err("unable to enable PWM for Gdium clock\n"); ++ goto err_pwm_request; ++ } ++ ++ cd->cpumask = cpumask_of(cpu); ++ ++ cd->shift = 22; ++ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift); ++ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd); ++ cd->min_delta_ns = clockevent_delta2ns(0xF, cd); ++ clockevents_register_device(&gdium_pwm_clock_cevt); ++ ++ /* SM501 PWM1 connected to intn2 <->ip4 */ ++ LOONGSON_INTPOL = (1 << 13); ++ LOONGSON_INTEDGE &= ~(1 << 13); ++ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt); ++ if (ret) { ++ pr_err("Can't claim irq\n"); ++ goto err_pwm_disable; ++ } ++ ++ cs->rating = 200; ++ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift); ++ ret = clocksource_register(&gdium_pwm_clock_clocksource); ++ if (ret) { ++ pr_err("Can't register clocksource\n"); ++ goto err_irq; ++ } ++ pr_info("Clocksource registered with shift %d and mult %d\n", ++ cs->shift, cs->mult); ++ ++ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO, ++ NULL, NULL, &gdium_pwm_clock_fops); ++ ++ return 0; ++ ++err_irq: ++ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); ++err_pwm_disable: ++ pwm_disable(clock_pwm); ++err_pwm_request: ++ pwm_free(clock_pwm); ++ return ret; ++} ++ ++static void gdium_pwm_clock_drvexit(void) ++{ ++ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt); ++ pwm_disable(clock_pwm); ++ pwm_free(clock_pwm); ++} ++ ++ ++static int __devinit gdium_pwm_clock_init(void) ++{ ++ int ret = gdium_pwm_clock_drvinit(); ++ ++ if (ret) { ++ pr_err("Fail to register gdium clock driver\n"); ++ return ret; ++ } ++ ++ return platform_driver_register(&gdium_pwm_clock_driver); ++} ++ ++static void __exit gdium_pwm_clock_cleanup(void) ++{ ++ gdium_pwm_clock_drvexit(); ++ platform_driver_unregister(&gdium_pwm_clock_driver); ++} ++ ++module_init(gdium_pwm_clock_init); ++module_exit(gdium_pwm_clock_cleanup); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("Gdium PWM clock driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:gdium-pwmclk"); +diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c +new file mode 100644 +index 0000000..2415d20 +--- /dev/null ++++ b/arch/mips/loongson/gdium/irq.c +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2007 Lemote Inc. ++ * Author: Fuxin Zhang, zhangfx@lemote.com ++ * ++ * Copyright (c) 2010 yajin ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */ ++#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */ ++#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */ ++ ++void mach_irq_dispatch(unsigned int pending) ++{ ++ if (pending & CAUSEF_IP7) ++ do_IRQ(LOONGSON_TIMER_IRQ); ++ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ ++ do_perfcnt_IRQ(); ++ bonito_irqdispatch(); ++ } else if (pending & CAUSEF_IP3) /* CPU UART */ ++ do_IRQ(LOONGSON_UART_IRQ); ++#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE) ++ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 4); ++#endif ++ else ++ spurious_interrupt(); ++} ++ ++static irqreturn_t ip6_action(int cpl, void *dev_id) ++{ ++ return IRQ_HANDLED; ++} ++ ++struct irqaction ip6_irqaction = { ++ .handler = ip6_action, ++ .name = "cascade", ++ .flags = IRQF_SHARED, ++}; ++ ++void __init mach_init_irq(void) ++{ ++ /* setup north bridge irq (bonito) */ ++ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction); ++} +diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c +new file mode 100644 +index 0000000..ffafba4 +--- /dev/null ++++ b/arch/mips/loongson/gdium/platform.c +@@ -0,0 +1,135 @@ ++/* ++ * Copyright (c) 2009 Philippe Vachon ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define GDIUM_GPIO_BASE 224 ++ ++static struct i2c_board_info __initdata sm502dev_i2c_devices[] = { ++ { ++ I2C_BOARD_INFO("lm75", 0x48), ++ }, ++ { ++ I2C_BOARD_INFO("m41t83", 0x68), ++ }, ++ { ++ I2C_BOARD_INFO("gdium-laptop", 0x40), ++ }, ++}; ++ ++static int sm502dev_backlight_init(struct device *dev) ++{ ++ /* Add gpio request stuff here */ ++ return 0; ++} ++ ++static void sm502dev_backlight_exit(struct device *dev) ++{ ++ /* Add gpio free stuff here */ ++} ++ ++static struct platform_pwm_backlight_data backlight_data = { ++ .pwm_id = 0, ++ .max_brightness = 15, ++ .dft_brightness = 8, ++ .pwm_period_ns = 50000, /* 20 kHz */ ++ .init = sm502dev_backlight_init, ++ .exit = sm502dev_backlight_exit, ++}; ++ ++static struct platform_device backlight = { ++ .name = "pwm-backlight", ++ .dev = { ++ .platform_data = &backlight_data, ++ }, ++ .id = -1, ++}; ++ ++/* ++ * Warning this stunt is very dangerous ++ * as the sm501 gpio have dynamic numbers... ++ */ ++/* bus 0 is the one for the ST7, DS75 etc... */ ++static struct i2c_gpio_platform_data i2c_gpio0_data = { ++#if CONFIG_GDIUM_VERSION > 2 ++ .sda_pin = GDIUM_GPIO_BASE + 13, ++ .scl_pin = GDIUM_GPIO_BASE + 6, ++#else ++ .sda_pin = 192+15, ++ .scl_pin = 192+14, ++#endif ++ .udelay = 5, ++ .timeout = HZ / 10, ++ .sda_is_open_drain = 0, ++ .scl_is_open_drain = 0, ++}; ++ ++static struct platform_device i2c_gpio0_device = { ++ .name = "i2c-gpio", ++ .id = 0, ++ .dev = { .platform_data = &i2c_gpio0_data, }, ++}; ++ ++/* bus 1 is for the CRT/VGA external screen */ ++static struct i2c_gpio_platform_data i2c_gpio1_data = { ++ .sda_pin = GDIUM_GPIO_BASE + 10, ++ .scl_pin = GDIUM_GPIO_BASE + 9, ++ .udelay = 5, ++ .timeout = HZ / 10, ++ .sda_is_open_drain = 0, ++ .scl_is_open_drain = 0, ++}; ++ ++static struct platform_device i2c_gpio1_device = { ++ .name = "i2c-gpio", ++ .id = 1, ++ .dev = { .platform_data = &i2c_gpio1_data, }, ++}; ++ ++static struct platform_device gdium_clock = { ++ .name = "gdium-pwmclk", ++ .id = -1, ++}; ++ ++static struct platform_device *devices[] __initdata = { ++ &i2c_gpio0_device, ++ &i2c_gpio1_device, ++ &backlight, ++ &gdium_clock, ++}; ++ ++static int __init gdium_platform_devices_setup(void) ++{ ++ int ret; ++ ++ pr_info("Registering gdium platform devices\n"); ++ ++ ret = i2c_register_board_info(0, sm502dev_i2c_devices, ++ ARRAY_SIZE(sm502dev_i2c_devices)); ++ ++ if (ret != 0) { ++ pr_info("Error while registering platform devices: %d\n", ret); ++ return ret; ++ } ++ ++ platform_add_devices(devices, ARRAY_SIZE(devices)); ++ ++ return 0; ++} ++ ++/* ++ * some devices are on the pwm stuff which is behind the mfd which is ++ * behind the pci bus so arch_initcall can't work because too early ++ */ ++late_initcall(gdium_platform_devices_setup); +diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c +new file mode 100644 +index 0000000..8289f95 +--- /dev/null ++++ b/arch/mips/loongson/gdium/reset.c +@@ -0,0 +1,22 @@ ++/* Board-specific reboot/shutdown routines ++ * ++ * Copyright (C) 2010 yajin ++ * ++ * 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. ++ */ ++#include ++ ++void mach_prepare_shutdown(void) ++{ ++ LOONGSON_GPIOIE &= ~(1<<1); ++ LOONGSON_GPIODATA |= (1<<1); ++} ++ ++void mach_prepare_reboot(void) ++{ ++ LOONGSON_GPIOIE &= ~(1<<2); ++ LOONGSON_GPIODATA &= ~(1<<2); ++} +diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c +new file mode 100644 +index 0000000..5af3b23 +--- /dev/null ++++ b/arch/mips/loongson/gdium/sm501-pwm.c +@@ -0,0 +1,465 @@ ++/* ++ * SM501 PWM clock ++ * Copyright (C) 2009-2010 Arnaud Patard ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const char drv_name[] = "sm501-pwm"; ++ ++#define INPUT_CLOCK 96 /* MHz */ ++#define PWM_COUNT 3 ++ ++#define SM501PWM_HIGH_COUNTER (1<<20) ++#define SM501PWM_LOW_COUNTER (1<<8) ++#define SM501PWM_CLOCK_DIVIDE (1>>4) ++#define SM501PWM_IP (1<<3) ++#define SM501PWM_I (1<<2) ++#define SM501PWM_E (1<<0) ++ ++struct pwm_device { ++ struct list_head node; ++ struct device *dev; ++ void __iomem *regs; ++ int duty_ns; ++ int period_ns; ++ char enabled; ++ void (*handler)(struct pwm_device *pwm); ++ ++ const char *label; ++ unsigned int use_count; ++ unsigned int pwm_id; ++}; ++ ++struct sm501pwm_info { ++ void __iomem *regs; ++ int irq; ++ struct resource *res; ++ struct device *dev; ++ struct dentry *debugfs; ++ ++ struct pwm_device pwm[3]; ++}; ++ ++int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) ++{ ++ unsigned int high, low, divider; ++ int divider1, divider2; ++ unsigned long long delay; ++ ++ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns) ++ return -EINVAL; ++ ++ /* Get delay ++ * We're loosing some precision but multiplying then dividing ++ * will overflow ++ */ ++ if (period_ns > 1000) { ++ delay = period_ns / 1000; ++ delay *= INPUT_CLOCK; ++ } else { ++ delay = period_ns * 96; ++ delay /= 1000; ++ } ++ ++ /* Get the number of clock low and high */ ++ high = delay * duty_ns / period_ns; ++ low = delay - high; ++ ++ /* Get divider to make 'low' and 'high' fit into 12 bits */ ++ /* No need to say that the divider must be >= 0 */ ++ divider1 = fls(low)-12; ++ divider2 = fls(high)-12; ++ ++ if (divider1 < 0) ++ divider1 = 0; ++ if (divider2 < 0) ++ divider2 = 0; ++ ++ divider = max(divider1, divider2); ++ ++ low >>= divider; ++ high >>= divider; ++ ++ pwm->duty_ns = duty_ns; ++ pwm->period_ns = period_ns; ++ ++ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_config); ++ ++int pwm_enable(struct pwm_device *pwm) ++{ ++ u32 reg; ++ ++ if (!pwm) ++ return -EINVAL; ++ ++ switch (pwm->pwm_id) { ++ case 0: ++ sm501_configure_gpio(pwm->dev->parent, 29, 1); ++ break; ++ case 1: ++ sm501_configure_gpio(pwm->dev->parent, 30, 1); ++ break; ++ case 2: ++ sm501_configure_gpio(pwm->dev->parent, 31, 1); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ reg = readl(pwm->regs); ++ reg |= (SM501PWM_IP | SM501PWM_E); ++ writel(reg, pwm->regs); ++ pwm->enabled = 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(pwm_enable); ++ ++void pwm_disable(struct pwm_device *pwm) ++{ ++ u32 reg; ++ ++ if (!pwm) ++ return; ++ ++ reg = readl(pwm->regs); ++ reg &= ~(SM501PWM_IP | SM501PWM_E); ++ writel(reg, pwm->regs); ++ ++ switch (pwm->pwm_id) { ++ case 0: ++ sm501_configure_gpio(pwm->dev->parent, 29, 0); ++ break; ++ case 1: ++ sm501_configure_gpio(pwm->dev->parent, 30, 0); ++ break; ++ case 2: ++ sm501_configure_gpio(pwm->dev->parent, 31, 0); ++ break; ++ default: ++ break; ++ } ++ pwm->enabled = 0; ++} ++EXPORT_SYMBOL(pwm_disable); ++ ++static DEFINE_MUTEX(pwm_lock); ++static LIST_HEAD(pwm_list); ++ ++struct pwm_device *pwm_request(int pwm_id, const char *label) ++{ ++ struct pwm_device *pwm; ++ int found = 0; ++ ++ mutex_lock(&pwm_lock); ++ ++ list_for_each_entry(pwm, &pwm_list, node) { ++ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) { ++ pwm->use_count++; ++ pwm->label = label; ++ found = 1; ++ break; ++ } ++ } ++ ++ mutex_unlock(&pwm_lock); ++ ++ return (found) ? pwm : NULL; ++} ++EXPORT_SYMBOL(pwm_request); ++ ++void pwm_free(struct pwm_device *pwm) ++{ ++ mutex_lock(&pwm_lock); ++ ++ if (pwm->use_count) { ++ pwm->use_count--; ++ pwm->label = NULL; ++ } else ++ dev_warn(pwm->dev, "PWM device already freed\n"); ++ ++ mutex_unlock(&pwm_lock); ++} ++EXPORT_SYMBOL(pwm_free); ++ ++int pwm_int_enable(struct pwm_device *pwm) ++{ ++ unsigned long conf; ++ ++ if (!pwm || !pwm->regs || !pwm->handler) ++ return -EINVAL; ++ ++ conf = readl(pwm->regs); ++ conf |= SM501PWM_I; ++ writel(conf, pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_int_enable); ++ ++int pwm_int_disable(struct pwm_device *pwm) ++{ ++ unsigned long conf; ++ ++ if (!pwm || !pwm->regs || !pwm->handler) ++ return -EINVAL; ++ ++ conf = readl(pwm->regs); ++ conf &= ~SM501PWM_I; ++ writel(conf, pwm->regs); ++ return 0; ++} ++EXPORT_SYMBOL(pwm_int_disable); ++ ++int pwm_set_handler(struct pwm_device *pwm, ++ void (*handler)(struct pwm_device *pwm)) ++{ ++ if (!pwm || !handler) ++ return -EINVAL; ++ pwm->handler = handler; ++ return 0; ++} ++EXPORT_SYMBOL(pwm_set_handler); ++ ++static irqreturn_t sm501pwm_irq(int irq, void *dev_id) ++{ ++ unsigned long value; ++ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id; ++ struct pwm_device *pwm; ++ int i; ++ ++ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0); ++ ++ /* Check is the interrupt is for us */ ++ if (value & (1<<22)) { ++ for (i = 0 ; i < PWM_COUNT ; i++) { ++ /* ++ * Find which pwm triggered the interrupt ++ * and ack ++ */ ++ value = readl(info->regs + i*4); ++ if (value & SM501PWM_IP) ++ writel(value | SM501PWM_IP, info->regs + i*4); ++ ++ pwm = &info->pwm[i]; ++ if (pwm->handler) ++ pwm->handler(pwm); ++ } ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static void add_pwm(int id, struct sm501pwm_info *info) ++{ ++ struct pwm_device *pwm = &info->pwm[id]; ++ ++ pwm->use_count = 0; ++ pwm->pwm_id = id; ++ pwm->dev = info->dev; ++ pwm->regs = info->regs + id * 4; ++ ++ mutex_lock(&pwm_lock); ++ list_add_tail(&pwm->node, &pwm_list); ++ mutex_unlock(&pwm_lock); ++} ++ ++static void del_pwm(int id, struct sm501pwm_info *info) ++{ ++ struct pwm_device *pwm = &info->pwm[id]; ++ ++ pwm->use_count = 0; ++ pwm->pwm_id = -1; ++ mutex_lock(&pwm_lock); ++ list_del(&pwm->node); ++ mutex_unlock(&pwm_lock); ++} ++ ++/* Debug fs */ ++static int sm501pwm_show(struct seq_file *s, void *p) ++{ ++ struct pwm_device *pwm; ++ ++ mutex_lock(&pwm_lock); ++ list_for_each_entry(pwm, &pwm_list, node) { ++ if (pwm->use_count) { ++ seq_printf(s, "pwm-%d (%12s) %d %d %s\n", ++ pwm->pwm_id, pwm->label, ++ pwm->duty_ns, pwm->period_ns, ++ pwm->enabled ? "on" : "off"); ++ seq_printf(s, " %08x\n", readl(pwm->regs)); ++ } ++ } ++ mutex_unlock(&pwm_lock); ++ ++ return 0; ++} ++ ++static int sm501pwm_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, sm501pwm_show, inode->i_private); ++} ++ ++static const struct file_operations sm501pwm_fops = { ++ .open = sm501pwm_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init sm501pwm_probe(struct platform_device *pdev) ++{ ++ struct sm501pwm_info *info; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ int ret = 0; ++ int res_len; ++ int i; ++ ++ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL); ++ if (!info) { ++ dev_err(dev, "Allocation failure\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ info->dev = dev; ++ platform_set_drvdata(pdev, info); ++ ++ /* Get irq number */ ++ info->irq = platform_get_irq(pdev, 0); ++ if (!info->irq) { ++ dev_err(dev, "no irq found\n"); ++ ret = -ENODEV; ++ goto err_alloc; ++ } ++ ++ /* Get regs address */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(dev, "No memory resource found\n"); ++ ret = -ENODEV; ++ goto err_alloc; ++ } ++ info->res = res; ++ res_len = (res->end - res->start)+1; ++ ++ if (!request_mem_region(res->start, res_len, drv_name)) { ++ dev_err(dev, "Can't request iomem resource\n"); ++ ret = -EBUSY; ++ goto err_alloc; ++ } ++ ++ info->regs = ioremap(res->start, res_len); ++ if (!info->regs) { ++ dev_err(dev, "ioremap failed\n"); ++ ret = -ENOMEM; ++ goto err_mem; ++ } ++ ++ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info); ++ if (ret != 0) { ++ dev_err(dev, "can't get irq\n"); ++ goto err_map; ++ } ++ ++ ++ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1); ++ ++ for (i = 0; i < 3; i++) ++ add_pwm(i, info); ++ ++ dev_info(dev, "SM501 PWM Found at %lx irq %d\n", ++ (unsigned long)info->res->start, info->irq); ++ ++ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO, ++ NULL, info, &sm501pwm_fops); ++ ++ ++ return 0; ++ ++err_map: ++ iounmap(info->regs); ++ ++err_mem: ++ release_mem_region(res->start, res_len); ++ ++err_alloc: ++ kfree(info); ++ platform_set_drvdata(pdev, NULL); ++err: ++ return ret; ++} ++ ++static int sm501pwm_remove(struct platform_device *pdev) ++{ ++ struct sm501pwm_info *info = platform_get_drvdata(pdev); ++ int i; ++ ++ if (info->debugfs) ++ debugfs_remove(info->debugfs); ++ ++ for (i = 0; i < 3; i++) { ++ pwm_disable(&info->pwm[i]); ++ del_pwm(i, info); ++ } ++ ++ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0); ++ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22); ++ ++ free_irq(info->irq, info); ++ iounmap(info->regs); ++ release_mem_region(info->res->start, ++ (info->res->end - info->res->start)+1); ++ kfree(info); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static struct platform_driver sm501pwm_driver = { ++ .probe = sm501pwm_probe, ++ .remove = sm501pwm_remove, ++ .driver = { ++ .name = drv_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __devinit sm501pwm_init(void) ++{ ++ return platform_driver_register(&sm501pwm_driver); ++} ++ ++static void __exit sm501pwm_cleanup(void) ++{ ++ platform_driver_unregister(&sm501pwm_driver); ++} ++ ++module_init(sm501pwm_init); ++module_exit(sm501pwm_cleanup); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("SM501 PWM driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:sm501-pwm"); +diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile +index 4f9eaa3..f945bd7a 100644 +--- a/arch/mips/loongson/lemote-2f/Makefile ++++ b/arch/mips/loongson/lemote-2f/Makefile +@@ -2,7 +2,7 @@ + # Makefile for lemote loongson2f family machines + # + +-obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o ++obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o platform.o + + # + # Suspend Support +diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c +new file mode 100644 +index 0000000..5316360 +--- /dev/null ++++ b/arch/mips/loongson/lemote-2f/platform.c +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++ ++static struct platform_device yeeloong_pdev = { ++ .name = "yeeloong_laptop", ++ .id = -1, ++}; ++ ++static struct platform_device lynloong_pdev = { ++ .name = "lynloong_pc", ++ .id = -1, ++}; ++ ++static int __init lemote2f_platform_init(void) ++{ ++ struct platform_device *pdev = NULL; ++ ++ switch (mips_machtype) { ++ case MACH_LEMOTE_YL2F89: ++ pdev = &yeeloong_pdev; ++ break; ++ case MACH_LEMOTE_LL2F: ++ pdev = &lynloong_pdev; ++ break; ++ default: ++ break; ++ ++ } ++ ++ if (pdev != NULL) ++ return platform_device_register(pdev); ++ ++ return -ENODEV; ++} ++ ++arch_initcall(lemote2f_platform_init); +diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c +index b30bf65..c0177cb 100644 +--- a/arch/mips/math-emu/cp1emu.c ++++ b/arch/mips/math-emu/cp1emu.c +@@ -7,6 +7,9 @@ + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. + * ++ * Loongson instruction support ++ * Copyright (C) 2011 Mark H Weaver ++ * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. +@@ -60,6 +63,11 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, + static int fpux_emu(struct pt_regs *, + struct mips_fpu_struct *, mips_instruction, void *__user *); + ++#ifdef CONFIG_MACH_LOONGSON ++static int loongson_spec2_emu(struct pt_regs *, ++ struct mips_fpu_struct *, mips_instruction, void *__user *); ++#endif ++ + /* Control registers */ + + #define FPCREG_RID 0 /* $0 = revision id */ +@@ -842,6 +850,14 @@ do { \ + #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) + #define DPTOREG(dp, x) DITOREG((dp).bits, x) + ++/* Support for Loongson paired single floating-point format */ ++#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \ ++ (si1) = (u32)di; (si2) = (u32)(di >> 32); }) ++#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x) ++ ++#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x) ++#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x) ++ + /* + * Emulate the single floating point instruction pointed at by EPC. + * Two instructions if the instruction is in a branch delay slot. +@@ -1235,6 +1251,16 @@ emul: + xcp->regs[MIPSInst_RD(ir)] = + xcp->regs[MIPSInst_RS(ir)]; + break; ++ ++#ifdef CONFIG_MACH_LOONGSON ++ case spec2_op:{ ++ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr); ++ if (sig) ++ return sig; ++ break; ++ } ++#endif ++ + default: + sigill: + return SIGILL; +@@ -1312,6 +1338,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); + DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); + DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); + ++#ifdef CONFIG_MACH_LOONGSON ++static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, ++ mips_instruction ir, void *__user *fault_addr) ++{ ++ int rfmt; /* resulting format */ ++ unsigned rcsr = 0; /* resulting csr */ ++ union { ++ union ieee754dp d; ++ struct { ++ union ieee754sp s; ++ union ieee754sp s2; ++ }; ++ } rv; /* resulting value */ ++ ++ /* XXX maybe add a counter for loongson spec2 fp instructions? */ ++ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */ ++ ++ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { ++ case s_fmt:{ ++ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); ++ union ieee754sp fd, fs, ft; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_sp_madd; ++ goto scoptop; ++ case loongson_msub_op: ++ handler = fpemu_sp_msub; ++ goto scoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_sp_nmadd; ++ goto scoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_sp_nmsub; ++ goto scoptop; ++ ++ scoptop: ++ SPFROMREG(fd, MIPSInst_FD(ir)); ++ SPFROMREG(fs, MIPSInst_FS(ir)); ++ SPFROMREG(ft, MIPSInst_FT(ir)); ++ rv.s = (*handler) (fd, fs, ft); ++ ++ copcsr: ++ if (ieee754_cxtest(IEEE754_INEXACT)) ++ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; ++ if (ieee754_cxtest(IEEE754_UNDERFLOW)) ++ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; ++ if (ieee754_cxtest(IEEE754_OVERFLOW)) ++ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; ++ if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) ++ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; ++ ++ break; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ case d_fmt:{ ++ union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); ++ union ieee754dp fd, fs, ft; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_dp_madd; ++ goto dcoptop; ++ case loongson_msub_op: ++ handler = fpemu_dp_msub; ++ goto dcoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_dp_nmadd; ++ goto dcoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_dp_nmsub; ++ goto dcoptop; ++ ++ dcoptop: ++ DPFROMREG(fd, MIPSInst_FD(ir)); ++ DPFROMREG(fs, MIPSInst_FS(ir)); ++ DPFROMREG(ft, MIPSInst_FT(ir)); ++ rv.d = (*handler) (fd, fs, ft); ++ goto copcsr; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ case ps_fmt:{ ++ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fd1, fs1, ft1; ++ union ieee754sp fd2, fs2, ft2; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ case loongson_madd_op: ++ handler = fpemu_sp_madd; ++ goto pscoptop; ++ case loongson_msub_op: ++ handler = fpemu_sp_msub; ++ goto pscoptop; ++ case loongson_nmadd_op: ++ handler = fpemu_sp_nmadd; ++ goto pscoptop; ++ case loongson_nmsub_op: ++ handler = fpemu_sp_nmsub; ++ goto pscoptop; ++ ++ pscoptop: ++ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir)); ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); ++ rv.s = (*handler) (fd1, fs1, ft1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler) (fd2, fs2, ft2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ default: ++ return SIGILL; ++ } ++ ++ /* ++ * Update the fpu CSR register for this operation. ++ * If an exception is required, generate a tidy SIGFPE exception, ++ * without updating the result register. ++ * Note: cause exception bits do not accumulate, they are rewritten ++ * for each op; only the flag/sticky bits accumulate. ++ */ ++ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; ++ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { ++ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ ++ return SIGFPE; ++ } ++ ++ /* ++ * Now we can safely write the result back to the register file. ++ */ ++ switch (rfmt) { ++ case d_fmt: ++ DPTOREG(rv.d, MIPSInst_FD(ir)); ++ break; ++ case s_fmt: ++ SPTOREG(rv.s, MIPSInst_FD(ir)); ++ break; ++ case ps_fmt: ++ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); ++ break; ++ default: ++ return SIGILL; ++ } ++ ++ return 0; ++} ++#endif ++ + static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + mips_instruction ir, void *__user *fault_addr) + { +@@ -1413,7 +1605,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + break; + + default: +- return SIGILL; ++ goto SIGILL_unless_prefx_op; + } + break; + } +@@ -1483,7 +1675,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + goto copcsr; + + default: +- return SIGILL; ++ goto SIGILL_unless_prefx_op; + } + break; + } +@@ -1496,6 +1688,11 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + break; + + default: ++ SIGILL_unless_prefx_op: ++ if (MIPSInst_FUNC(ir) == prefx_op) { ++ /* ignore prefx operation */ ++ break; ++ } + return SIGILL; + } + +@@ -1517,7 +1714,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + unsigned cond; + union { + union ieee754dp d; +- union ieee754sp s; ++ struct { ++ union ieee754sp s; ++#ifdef CONFIG_MACH_LOONGSON ++ union ieee754sp s2; /* for Loongson paired singles */ ++#endif ++ }; + int w; + s64 l; + } rv; /* resulting value */ +@@ -1614,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + case fmov_op: + /* an easy one */ + SPFROMREG(rv.s, MIPSInst_FS(ir)); +- goto copcsr; ++ break; + + /* binary op on handler */ + scopbop: +@@ -1811,7 +2013,7 @@ copcsr: + case fmov_op: + /* an easy one */ + DPFROMREG(rv.d, MIPSInst_FS(ir)); +- goto copcsr; ++ break; + + /* binary op on handler */ + dcopbop: +@@ -1928,6 +2130,83 @@ dcopuop: + break; + } + ++#ifdef CONFIG_MACH_LOONGSON ++ case ps_fmt:{ /* 6 */ ++ /* Support for Loongson paired single fp instructions */ ++ union { ++ union ieee754sp(*b) (union ieee754sp, union ieee754sp); ++ union ieee754sp(*u) (union ieee754sp); ++ } handler; ++ ++ switch (MIPSInst_FUNC(ir)) { ++ /* binary ops */ ++ case fadd_op: ++ handler.b = ieee754sp_add; ++ goto pscopbop; ++ case fsub_op: ++ handler.b = ieee754sp_sub; ++ goto pscopbop; ++ case fmul_op: ++ handler.b = ieee754sp_mul; ++ goto pscopbop; ++ ++ /* unary ops */ ++ case fabs_op: ++ handler.u = ieee754sp_abs; ++ goto pscopuop; ++ case fneg_op: ++ handler.u = ieee754sp_neg; ++ goto pscopuop; ++ case fmov_op: ++ /* an easy one */ ++ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir)); ++ break; ++ ++ pscopbop: /* paired binary op handler */ ++ { ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fs1, ft1; ++ union ieee754sp fs2, ft2; ++ ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir)); ++ rv.s = (*handler.b) (fs1, ft1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler.b) (fs2, ft2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ } ++ pscopuop: /* paired unary op handler */ ++ { ++ struct _ieee754_csr ieee754_csr_save; ++ union ieee754sp fs1; ++ union ieee754sp fs2; ++ ++ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir)); ++ rv.s = (*handler.u) (fs1); ++ ieee754_csr_save = ieee754_csr; ++ rv.s2 = (*handler.u) (fs2); ++ ieee754_csr.cx |= ieee754_csr_save.cx; ++ ieee754_csr.sx |= ieee754_csr_save.sx; ++ goto copcsr; ++ } ++ break; ++ ++ default: ++ if (MIPSInst_FUNC(ir) >= fcmp_op) { ++ /* Loongson fp hardware handles all ++ cases of fp compare insns, so we ++ shouldn't have to */ ++ printk ("Loongson paired-single fp compare" ++ " unimplemented in cp1emu.c\n"); ++ } ++ return SIGILL; ++ } ++ break; ++ } ++#endif ++ + case l_fmt: + + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) +@@ -1999,6 +2278,11 @@ dcopuop: + + DITOREG(rv.l, MIPSInst_FD(ir)); + break; ++#ifdef CONFIG_MACH_LOONGSON ++ case ps_fmt: ++ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir)); ++ break; ++#endif + default: + return SIGILL; + } +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index 300591c..ed272e2 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o + obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o + obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o + obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o ++obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o + obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3.o + obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o + obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o +diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c +new file mode 100644 +index 0000000..b296220 +--- /dev/null ++++ b/arch/mips/pci/fixup-gdium.c +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (C) 2010 yajin ++ * ++ * 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. ++ */ ++ ++#include ++#include ++ ++#include ++/* ++ * http://www.pcidatabase.com ++ * GDIUM has different PCI mapping ++ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI ++ * slog 14 (0x126f/0x0501) -> sm501 ++ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers ++ * plus Single EHCI controller ++ * slot 16 (0x10ec/0x8139) -> Realtek 8139c ++ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller ++ */ ++ ++#undef INT_IRQA ++#undef INT_IRQB ++#undef INT_IRQC ++#undef INT_IRQD ++#define INT_IRQA 36 ++#define INT_IRQB 37 ++#define INT_IRQC 38 ++#define INT_IRQD 39 ++ ++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ int irq = 0; ++ ++ switch (slot) { ++ case 13: ++ irq = INT_IRQC + ((pin - 1) & 3); ++ break; ++ case 14: ++ irq = INT_IRQA; ++ break; ++ case 15: ++#if CONFIG_GDIUM_VERSION > 2 ++ irq = INT_IRQB; ++#else ++ irq = INT_IRQA + ((pin - 1) & 3); ++#endif ++ break; ++ case 16: ++ irq = INT_IRQD; ++ break; ++#if CONFIG_GDIUM_VERSION > 2 ++ case 17: ++ irq = INT_IRQC; ++ break; ++#endif ++ default: ++ pr_info(" strange pci slot number %d on gdium.\n", slot); ++ break; ++ } ++ return irq; ++} ++ ++/* Do platform specific device initialization at pci_enable_device() time */ ++int pcibios_plat_dev_init(struct pci_dev *dev) ++{ ++ return 0; ++} ++ ++/* Fixups for the USB host controllers */ ++static void __init gdium_usb_host_fixup(struct pci_dev *dev) ++{ ++ unsigned int val; ++ pci_read_config_dword(dev, 0xe0, &val); ++#if CONFIG_GDIUM_VERSION > 2 ++ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3); ++#else ++ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5); ++ pci_write_config_dword(dev, 0xe4, 1<<5); ++#endif ++} ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, ++ gdium_usb_host_fixup); ++#if CONFIG_GDIUM_VERSION > 2 ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550, ++ gdium_usb_host_fixup); ++#endif +diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S +index e7567c8..498e42d 100644 +--- a/arch/mips/power/hibernate.S ++++ b/arch/mips/power/hibernate.S +@@ -30,8 +30,10 @@ LEAF(swsusp_arch_suspend) + END(swsusp_arch_suspend) + + LEAF(swsusp_arch_resume) ++#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit 771004298d broke Loongson2. */ + /* Avoid TLB mismatch during and after kernel resume */ + jal local_flush_tlb_all ++#endif + PTR_L t0, restore_pblist + 0: + PTR_L t1, PBE_ADDRESS(t0) /* source */ +diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c +index fc897ba..ac60f6b 100644 +--- a/drivers/cpufreq/loongson2_cpufreq.c ++++ b/drivers/cpufreq/loongson2_cpufreq.c +@@ -161,20 +161,32 @@ static int __init cpufreq_init(void) + /* Register platform stuff */ + ret = platform_driver_register(&platform_driver); + if (ret) +- return ret; ++ goto err_return; + + pr_info("cpufreq: Loongson-2F CPU frequency driver.\n"); + +- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, +- CPUFREQ_TRANSITION_NOTIFIER); ++ ret = cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ if (ret) ++ goto err_platform_driver_unregister; + + ret = cpufreq_register_driver(&loongson2_cpufreq_driver); ++ if (ret) ++ goto err_cpufreq_unregister_notifier; + +- if (!ret && !nowait) { ++ if (!nowait) { + saved_cpu_wait = cpu_wait; + cpu_wait = loongson2_cpu_wait; + } + ++ return 0; ++ ++ err_cpufreq_unregister_notifier: ++ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ err_platform_driver_unregister: ++ platform_driver_unregister(&platform_driver); ++ err_return: + return ret; + } + +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 152b006..767d8de 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -871,6 +871,13 @@ config HID_ZYDACRON + ---help--- + Support for Zydacron remote control. + ++config HID_GDIUM ++ bool "Gdium Fn keys support" if EMBEDDED ++ depends on USB_HID && DEXXON_GDIUM ++ default !EMBEDDED ++ ---help--- ++ Support for Functions keys available on Gdiums. ++ + config HID_SENSOR_HUB + tristate "HID Sensors framework support" + depends on HID && HAS_IOMEM +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 6f19958..2740ff0 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -99,6 +99,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o + wacom-objs := wacom_wac.o wacom_sys.o + obj-$(CONFIG_HID_WACOM) += wacom.o + obj-$(CONFIG_HID_WALTOP) += hid-waltop.o ++obj-$(CONFIG_HID_GDIUM) += hid-gdium.o + obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o + obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o + +diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c +new file mode 100644 +index 0000000..67cc095 +--- /dev/null ++++ b/drivers/hid/hid-gdium.c +@@ -0,0 +1,210 @@ ++/* ++ * hid-gdium -- Gdium laptop function keys ++ * ++ * Arnaud Patard ++ * ++ * Based on hid-apple.c ++ * ++ * 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. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++#define GDIUM_FN_ON 1 ++ ++static int fnmode = GDIUM_FN_ON; ++module_param(fnmode, int, 0644); ++MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)"); ++ ++struct gdium_data { ++ unsigned int fn_on; ++}; ++ ++ ++struct gdium_key_translation { ++ u16 from; ++ u16 to; ++}; ++ ++static struct gdium_key_translation gdium_fn_keys[] = { ++ { KEY_F1, KEY_CAMERA }, ++ { KEY_F2, KEY_CONNECT }, ++ { KEY_F3, KEY_MUTE }, ++ { KEY_F4, KEY_VOLUMEUP}, ++ { KEY_F5, KEY_VOLUMEDOWN }, ++ { KEY_F6, KEY_SWITCHVIDEOMODE }, ++ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */ ++ { KEY_F8, KEY_BRIGHTNESSUP }, ++ { KEY_F9, KEY_BRIGHTNESSDOWN }, ++ { KEY_F10, KEY_SLEEP }, ++ { KEY_F11, KEY_PROG1 }, ++ { KEY_F12, KEY_PROG2 }, ++ { KEY_UP, KEY_PAGEUP }, ++ { KEY_DOWN, KEY_PAGEDOWN }, ++ { KEY_INSERT, KEY_NUMLOCK }, ++ { KEY_DELETE, KEY_SCROLLLOCK }, ++ { KEY_T, KEY_STOPCD }, ++ { KEY_F, KEY_PREVIOUSSONG }, ++ { KEY_H, KEY_NEXTSONG }, ++ { KEY_G, KEY_PLAYPAUSE }, ++ { } ++}; ++ ++static struct gdium_key_translation *gdium_find_translation( ++ struct gdium_key_translation *table, u16 from) ++{ ++ struct gdium_key_translation *trans; ++ ++ /* Look for the translation */ ++ for (trans = table; trans->from; trans++) ++ if (trans->from == from) ++ return trans; ++ return NULL; ++} ++ ++static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input, ++ struct hid_usage *usage, __s32 value) ++{ ++ struct gdium_data *data = hid_get_drvdata(hid); ++ struct gdium_key_translation *trans; ++ int do_translate; ++ ++ if (usage->type != EV_KEY) ++ return 0; ++ ++ if ((usage->code == KEY_FN)) { ++ data->fn_on = !!value; ++ input_event(input, usage->type, usage->code, value); ++ return 1; ++ } ++ ++ if (fnmode) { ++ trans = gdium_find_translation(gdium_fn_keys, usage->code); ++ if (trans) { ++ do_translate = data->fn_on; ++ if (do_translate) { ++ input_event(input, usage->type, trans->to, value); ++ return 1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int gdium_input_event(struct hid_device *hdev, struct hid_field *field, ++ struct hid_usage *usage, __s32 value) ++{ ++ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type) ++ return 0; ++ ++ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value)) ++ return 1; ++ ++ return 0; ++} ++ ++ ++static void gdium_input_setup(struct input_dev *input) ++{ ++ struct gdium_key_translation *trans; ++ ++ set_bit(KEY_NUMLOCK, input->keybit); ++ ++ /* Enable all needed keys */ ++ for (trans = gdium_fn_keys; trans->from; trans++) ++ set_bit(trans->to, input->keybit); ++} ++ ++static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) ++ && ((usage->hid & HID_USAGE) == 0x82)) { ++ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); ++ gdium_input_setup(hi->input); ++ return 1; ++ } ++ return 0; ++} ++ ++static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ struct gdium_data *data; ++ int ret; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) { ++ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n"); ++ return -ENOMEM; ++ } ++ ++ hid_set_drvdata(hdev, data); ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ dev_err(&hdev->dev, "parse failed\n"); ++ goto err_free; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ++ if (ret) { ++ dev_err(&hdev->dev, "hw start failed\n"); ++ goto err_free; ++ } ++ ++ return 0; ++err_free: ++ kfree(data); ++ return ret; ++} ++static void gdium_input_remove(struct hid_device *hdev) ++{ ++ hid_hw_stop(hdev); ++ kfree(hid_get_drvdata(hdev)); ++} ++ ++static const struct hid_device_id gdium_input_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) }, ++ {} ++}; ++MODULE_DEVICE_TABLE(hid, gdium_input_devices); ++ ++static struct hid_driver gdium_input_driver = { ++ .name = "gdium-fnkeys", ++ .id_table = gdium_input_devices, ++ .probe = gdium_input_probe, ++ .remove = gdium_input_remove, ++ .event = gdium_input_event, ++ .input_mapping = gdium_input_mapping, ++}; ++ ++static int gdium_input_init(void) ++{ ++ int ret; ++ ++ ret = hid_register_driver(&gdium_input_driver); ++ if (ret) ++ pr_err("can't register gdium keyboard driver\n"); ++ ++ return ret; ++} ++static void gdium_input_exit(void) ++{ ++ hid_unregister_driver(&gdium_input_driver); ++} ++ ++module_init(gdium_input_init); ++module_exit(gdium_input_exit); ++MODULE_LICENSE("GPL"); ++ +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 7fe5590..3087a7f 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -1025,6 +1025,9 @@ + #define USB_VENDOR_ID_ZYTRONIC 0x14c8 + #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 + ++#define USB_VENDOR_ID_GDIUM 0x04B4 ++#define USB_DEVICE_ID_GDIUM 0xe001 ++ + #define USB_VENDOR_ID_PRIMAX 0x0461 + #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 + +diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c +index 376f2dc..b576801 100644 +--- a/drivers/ide/ide-iops.c ++++ b/drivers/ide/ide-iops.c +@@ -27,6 +27,10 @@ + #include + #include + ++#ifdef CONFIG_LEMOTE_MACH2F ++#include ++#endif ++ + void SELECT_MASK(ide_drive_t *drive, int mask) + { + const struct ide_port_ops *port_ops = drive->hwif->port_ops; +@@ -300,6 +304,11 @@ void ide_check_nien_quirk_list(ide_drive_t *drive) + { + const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; + ++#ifdef CONFIG_LEMOTE_MACH2F ++ if (mips_machtype != MACH_LEMOTE_YL2F89) ++ return; ++#endif ++ + for (list = nien_quirk_list; *list != NULL; list++) + if (strstr(m, *list) != NULL) { + drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; +diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c +index 91077ef..2cfd9ff 100644 +--- a/drivers/mfd/sm501.c ++++ b/drivers/mfd/sm501.c +@@ -58,7 +58,7 @@ struct sm501_gpio { + struct sm501_gpio { + /* no gpio support, empty definition for sm501_devdata. */ + }; +-#endif ++#endif /* CONFIG_MFD_SM501_GPIO */ + + struct sm501_devdata { + spinlock_t reg_lock; +@@ -1124,6 +1124,22 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) + { + return sm->gpio.registered; + } ++ ++void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned ++ char mode) ++{ ++ unsigned long set, reg, offset = gpio; ++ ++ if (offset >= 32) { ++ reg = SM501_GPIO63_32_CONTROL; ++ offset = gpio - 32; ++ } else ++ reg = SM501_GPIO31_0_CONTROL; ++ ++ set = mode ? 1 << offset : 0; ++ ++ sm501_modify_reg(dev, reg, set, 0); ++} + #else + static inline int sm501_register_gpio(struct sm501_devdata *sm) + { +@@ -1143,7 +1159,13 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) + { + return 0; + } +-#endif ++ ++void sm501_configure_gpio(struct device *dev, unsigned int gpio, ++ unsigned char mode) ++{ ++} ++#endif /* CONFIG_MFD_SM501_GPIO */ ++EXPORT_SYMBOL_GPL(sm501_configure_gpio); + + static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, + struct sm501_platdata_gpio_i2c *iic) +@@ -1198,6 +1220,20 @@ static int sm501_register_gpio_i2c(struct sm501_devdata *sm, + return 0; + } + ++/* register sm501 PWM device */ ++static int sm501_register_pwm(struct sm501_devdata *sm) ++{ ++ struct platform_device *pdev; ++ ++ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0); ++ if (!pdev) ++ return -ENOMEM; ++ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC); ++ sm501_create_irq(sm, &pdev->resource[1]); ++ ++ return sm501_register_device(sm, pdev); ++} ++ + /* sm501_dbg_regs + * + * Debug attribute to attach to parent device to show core registers +@@ -1356,6 +1392,8 @@ static int sm501_init_dev(struct sm501_devdata *sm) + sm501_register_uart(sm, idata->devices); + if (idata->devices & SM501_USE_GPIO) + sm501_register_gpio(sm); ++ if (idata->devices & SM501_USE_PWM) ++ sm501_register_pwm(sm); + } + + if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { +@@ -1542,10 +1580,15 @@ static struct sm501_initdata sm501_pci_initdata = { + .devices = SM501_USE_ALL, + + /* Errata AB-3 says that 72MHz is the fastest available +- * for 33MHZ PCI with proper bus-mastering operation */ +- ++ * for 33MHZ PCI with proper bus-mastering operation ++ * For gdium, it works under 84&112M clock freq.*/ ++#ifdef CONFIG_DEXXON_GDIUM ++ .mclk = 84 * MHZ, ++ .m1xclk = 112 * MHZ, ++#else + .mclk = 72 * MHZ, + .m1xclk = 144 * MHZ, ++#endif + }; + + static struct sm501_platdata_fbsub sm501_pdata_fbsub = { +diff --git a/drivers/net/titan_ge.c b/drivers/net/titan_ge.c +new file mode 100644 +index 0000000..dc137bf8 +--- /dev/null ++++ b/drivers/net/titan_ge.c +@@ -0,0 +1,2069 @@ ++/* ++ * drivers/net/titan_ge.c - Driver for Titan ethernet ports ++ * ++ * Copyright (C) 2003 PMC-Sierra Inc. ++ * Author : Manish Lachwani (lachwani@pmc-sierra.com) ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * The MAC unit of the Titan consists of the following: ++ * ++ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO ++ * -> FIFO is where the incoming and outgoing data is placed ++ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes ++ * the data into the FIFO for Rx ++ * -> TMAC is the outgoing MAC interface and RMAC is the incoming. ++ * -> AFX is the address filtering block ++ * -> GMII block to communicate with the PHY ++ * ++ * Rx will look like the following: ++ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory ++ * ++ * Tx will look like the following: ++ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII ++ * ++ * The Titan driver has support for the following performance features: ++ * -> Rx side checksumming ++ * -> Jumbo Frames ++ * -> Interrupt Coalscing ++ * -> Rx NAPI ++ * -> SKB Recycling ++ * -> Transmit/Receive descriptors in SRAM ++ * -> Fast routing for IP forwarding ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* For MII specifc registers, titan_mdio.h should be included */ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "titan_ge.h" ++#include "titan_mdio.h" ++ ++/* Static Function Declarations */ ++static int titan_ge_eth_open(struct net_device *); ++static void titan_ge_eth_stop(struct net_device *); ++static struct net_device_stats *titan_ge_get_stats(struct net_device *); ++static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int, ++ unsigned long, unsigned long, ++ unsigned long); ++static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int, ++ unsigned long, unsigned long); ++ ++static int titan_ge_open(struct net_device *); ++static int titan_ge_start_xmit(struct sk_buff *, struct net_device *); ++static int titan_ge_stop(struct net_device *); ++ ++static unsigned long titan_ge_tx_coal(unsigned long, int); ++ ++static void titan_ge_port_reset(unsigned int); ++static int titan_ge_free_tx_queue(titan_ge_port_info *); ++static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *); ++static int titan_ge_port_start(struct net_device *, titan_ge_port_info *); ++ ++static int titan_ge_return_tx_desc(titan_ge_port_info *, int); ++ ++/* ++ * Some configuration for the FIFO and the XDMA channel needs ++ * to be done only once for all the ports. This flag controls ++ * that ++ */ ++static unsigned long config_done; ++ ++/* ++ * One time out of memory flag ++ */ ++static unsigned int oom_flag; ++ ++static int titan_ge_poll(struct net_device *netdev, int *budget); ++ ++static int titan_ge_receive_queue(struct net_device *, unsigned int); ++ ++static struct platform_device *titan_ge_device[3]; ++ ++/* MAC Address */ ++extern unsigned char titan_ge_mac_addr_base[6]; ++ ++unsigned long titan_ge_base; ++static unsigned long titan_ge_sram; ++ ++static char titan_string[] = "titan"; ++ ++/* ++ * The Titan GE has two alignment requirements: ++ * -> skb->data to be cacheline aligned (32 byte) ++ * -> IP header alignment to 16 bytes ++ * ++ * The latter is not implemented. So, that results in an extra copy on ++ * the Rx. This is a big performance hog. For the former case, the ++ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size ++ * requested is calculated: ++ * ++ * Ethernet Frame Size : 1518 ++ * Ethernet Header : 14 ++ * Future Titan change for IP header alignment : 2 ++ * ++ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header ++ * alignment, we use skb_reserve(). ++ */ ++ ++#define ALIGNED_RX_SKB_ADDR(addr) \ ++ ((((unsigned long)(addr) + (64UL - 1UL)) \ ++ & ~(64UL - 1UL)) - (unsigned long)(addr)) ++ ++#define titan_ge_alloc_skb(__length, __gfp_flags) \ ++({ struct sk_buff *__skb; \ ++ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \ ++ if(__skb) { \ ++ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \ ++ if(__offset) \ ++ skb_reserve(__skb, __offset); \ ++ } \ ++ __skb; \ ++}) ++ ++/* ++ * Configure the GMII block of the Titan based on what the PHY tells us ++ */ ++static void titan_ge_gmii_config(int port_num) ++{ ++ unsigned int reg_data = 0, phy_reg; ++ int err; ++ ++ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); ++ ++ if (err == TITAN_GE_MDIO_ERROR) { ++ printk(KERN_ERR ++ "Could not read PHY control register 0x11 \n"); ++ printk(KERN_ERR ++ "Setting speed to 1000 Mbps and Duplex to Full \n"); ++ ++ return; ++ } ++ ++ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0); ++ ++ if (phy_reg & 0x8000) { ++ if (phy_reg & 0x2000) { ++ /* Full Duplex and 1000 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x201); ++ } else { ++ /* Half Duplex and 1000 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x2201); ++ } ++ } ++ if (phy_reg & 0x4000) { ++ if (phy_reg & 0x2000) { ++ /* Full Duplex and 100 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x100); ++ } else { ++ /* Half Duplex and 100 Mbps */ ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE + ++ (port_num << 12)), 0x2100); ++ } ++ } ++ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL + ++ (port_num << 12)); ++ reg_data |= 0x3; ++ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL + ++ (port_num << 12)), reg_data); ++} ++ ++/* ++ * Enable the TMAC if it is not ++ */ ++static void titan_ge_enable_tx(unsigned int port_num) ++{ ++ unsigned long reg_data; ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); ++ if (!(reg_data & 0x8000)) { ++ printk("TMAC disabled for port %d!! \n", port_num); ++ ++ reg_data |= 0x0001; /* Enable TMAC */ ++ reg_data |= 0x4000; /* CRC Check Enable */ ++ reg_data |= 0x2000; /* Padding enable */ ++ reg_data |= 0x0800; /* CRC Add enable */ ++ reg_data |= 0x0080; /* PAUSE frame */ ++ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ } ++} ++ ++/* ++ * Tx Timeout function ++ */ ++static void titan_ge_tx_timeout(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ printk(KERN_INFO "%s: TX timeout ", netdev->name); ++ printk(KERN_INFO "Resetting card \n"); ++ ++ /* Do the reset outside of interrupt context */ ++ schedule_work(&titan_ge_eth->tx_timeout_task); ++} ++ ++/* ++ * Update the AFX tables for UC and MC for slice 0 only ++ */ ++static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth) ++{ ++ int port = titan_ge_eth->port_num; ++ unsigned int i; ++ volatile unsigned long reg_data = 0; ++ u8 p_addr[6]; ++ ++ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6); ++ ++ /* Set the MAC address here for TMAC and RMAC */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1); ++ /* Configure the eight address filters */ ++ for (i = 0; i < 8; i++) { ++ /* Select each of the eight filters */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 + ++ (port << 12)), i); ++ ++ /* Configure the match */ ++ reg_data = 0x9; /* Forward Enable Bit */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 + ++ (port << 12)), reg_data); ++ ++ /* Finally, AFX Exact Match Address Registers */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ ++ /* VLAN id set to 0 */ ++ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID + ++ (port << 12)), 0); ++ } ++} ++ ++/* ++ * Actual Routine to reset the adapter when the timeout occurred ++ */ ++static void titan_ge_tx_timeout_task(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ int port = titan_ge_eth->port_num; ++ ++ printk("Titan GE: Transmit timed out. Resetting ... \n"); ++ ++ /* Dump debug info */ ++ printk(KERN_ERR "TRTG cause : %x \n", ++ TITAN_GE_READ(0x100c + (port << 12))); ++ ++ /* Fix this for the other ports */ ++ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c)); ++ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040)); ++ printk(KERN_ERR "XDMA GDI ERROR : %x \n", ++ TITAN_GE_READ(0x5008 + (port << 8))); ++ printk(KERN_ERR "CHANNEL ERROR: %x \n", ++ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT ++ + (port << 8))); ++ ++ netif_device_detach(netdev); ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ titan_ge_port_start(netdev, titan_ge_eth); ++ netif_device_attach(netdev); ++} ++ ++/* ++ * Change the MTU of the Ethernet Device ++ */ ++static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned long flags; ++ ++ if ((new_mtu > 9500) || (new_mtu < 64)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ netdev->mtu = new_mtu; ++ ++ /* Now we have to reopen the interface so that SKBs with the new ++ * size will be allocated */ ++ ++ if (netif_running(netdev)) { ++ titan_ge_eth_stop(netdev); ++ ++ if (titan_ge_eth_open(netdev) != TITAN_OK) { ++ printk(KERN_ERR ++ "%s: Fatal error on opening device\n", ++ netdev->name); ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ return -1; ++ } ++ } ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ return 0; ++} ++ ++/* ++ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line ++ * only. Once an interrupt is triggered, figure out the port and then check ++ * the channel. ++ */ ++static irqreturn_t titan_ge_int_handler(int irq, void *dev_id) ++{ ++ struct net_device *netdev = (struct net_device *) dev_id; ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int reg_data; ++ unsigned int eth_int_cause_error = 0, is; ++ unsigned long eth_int_cause1; ++ int err = 0; ++#ifdef CONFIG_SMP ++ unsigned long eth_int_cause2; ++#endif ++ ++ /* Ack the CPU interrupt */ ++ switch (port_num) { ++ case 0: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is); ++#endif ++ break; ++ ++ case 1: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is); ++#endif ++ break; ++ ++ case 2: ++ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4); ++ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is); ++ ++#ifdef CONFIG_SMP ++ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4); ++ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is); ++#endif ++ } ++ ++ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); ++#ifdef CONFIG_SMP ++ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B); ++#endif ++ ++ /* Spurious interrupt */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) { ++#else ++ if (eth_int_cause1 == 0) { ++#endif ++ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT + ++ (port_num << 8)); ++ ++ if (eth_int_cause_error == 0) ++ return IRQ_NONE; ++ } ++ ++ /* Handle Tx first. No need to ack interrupts */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 & 0x20202) || ++ (eth_int_cause2 & 0x20202) ) ++#else ++ if (eth_int_cause1 & 0x20202) ++#endif ++ titan_ge_free_tx_queue(titan_ge_eth); ++ ++ /* Handle the Rx next */ ++#ifdef CONFIG_SMP ++ if ( (eth_int_cause1 & 0x10101) || ++ (eth_int_cause2 & 0x10101)) { ++#else ++ if (eth_int_cause1 & 0x10101) { ++#endif ++ if (netif_rx_schedule_prep(netdev)) { ++ unsigned int ack; ++ ++ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ /* Disable Tx and Rx both */ ++ if (port_num == 0) ++ ack &= ~(0x3); ++ if (port_num == 1) ++ ack &= ~(0x300); ++ ++ if (port_num == 2) ++ ack &= ~(0x30000); ++ ++ /* Interrupts have been disabled */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack); ++ ++ __netif_rx_schedule(netdev); ++ } ++ } ++ ++ /* Handle error interrupts */ ++ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) { ++ printk(KERN_ERR ++ "XDMA Channel Error : %x on port %d\n", ++ eth_int_cause_error, port_num); ++ ++ printk(KERN_ERR ++ "XDMA GDI Hardware error : %x on port %d\n", ++ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num); ++ ++ printk(KERN_ERR ++ "XDMA currently has %d Rx descriptors \n", ++ TITAN_GE_READ(0x5048 + (port_num << 8))); ++ ++ printk(KERN_ERR ++ "XDMA currently has prefetcted %d Rx descriptors \n", ++ TITAN_GE_READ(0x505c + (port_num << 8))); ++ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + ++ (port_num << 8)), eth_int_cause_error); ++ } ++ ++ /* ++ * PHY interrupt to inform abt the changes. Reading the ++ * PHY Status register will clear the interrupt ++ */ ++ if ((!(eth_int_cause1 & 0x30303)) && ++ (eth_int_cause_error == 0)) { ++ err = ++ titan_ge_mdio_read(port_num, ++ TITAN_GE_MDIO_PHY_IS, ®_data); ++ ++ if (reg_data & 0x0400) { ++ /* Link status change */ ++ titan_ge_mdio_read(port_num, ++ TITAN_GE_MDIO_PHY_STATUS, ®_data); ++ if (!(reg_data & 0x0400)) { ++ /* Link is down */ ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ } else { ++ /* Link is up */ ++ netif_carrier_on(netdev); ++ netif_wake_queue(netdev); ++ ++ /* Enable the queue */ ++ titan_ge_enable_tx(port_num); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Multicast and Promiscuous mode set. The ++ * set_multi entry point is called whenever the ++ * multicast address list or the network interface ++ * flags are updated. ++ */ ++static void titan_ge_set_multi(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned long reg_data; ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + ++ (port_num << 12)); ++ ++ if (netdev->flags & IFF_PROMISC) { ++ reg_data |= 0x2; ++ } ++ else if (netdev->flags & IFF_ALLMULTI) { ++ reg_data |= 0x01; ++ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */ ++ } ++ else { ++ reg_data = 0x2; ++ } ++ ++ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 + ++ (port_num << 12)), reg_data); ++ if (reg_data & 0x01) { ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI + ++ (port_num << 12)), 0xffff); ++ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI + ++ (port_num << 12)), 0xffff); ++ } ++} ++ ++/* ++ * Open the network device ++ */ ++static int titan_ge_open(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num; ++ int retval; ++ ++ retval = request_irq(irq, titan_ge_int_handler, ++ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev); ++ ++ if (retval != 0) { ++ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n"); ++ return -1; ++ } ++ ++ netdev->irq = irq; ++ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num); ++ ++ spin_lock_irq(&(titan_ge_eth->lock)); ++ ++ if (titan_ge_eth_open(netdev) != TITAN_OK) { ++ spin_unlock_irq(&(titan_ge_eth->lock)); ++ printk("%s: Error opening interface \n", netdev->name); ++ free_irq(netdev->irq, netdev); ++ return -EBUSY; ++ } ++ ++ spin_unlock_irq(&(titan_ge_eth->lock)); ++ ++ return 0; ++} ++ ++/* ++ * Allocate the SKBs for the Rx ring. Also used ++ * for refilling the queue ++ */ ++static int titan_ge_rx_task(struct net_device *netdev, ++ titan_ge_port_info *titan_ge_port) ++{ ++ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev; ++ volatile titan_ge_rx_desc *rx_desc; ++ struct sk_buff *skb; ++ int rx_used_desc; ++ int count = 0; ++ ++ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) { ++ ++ /* First try to get the skb from the recycler */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC); ++#else ++ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC); ++#endif ++ if (unlikely(!skb)) { ++ /* OOM, set the flag */ ++ printk("OOM \n"); ++ oom_flag = 1; ++ break; ++ } ++ count++; ++ skb->dev = netdev; ++ ++ titan_ge_port->rx_ring_skbs++; ++ ++ rx_used_desc = titan_ge_port->rx_used_desc_q; ++ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]); ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ rx_desc->buffer_addr = dma_map_single(device, skb->data, ++ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE); ++#else ++ rx_desc->buffer_addr = dma_map_single(device, skb->data, ++ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE); ++#endif ++ ++ titan_ge_port->rx_skb[rx_used_desc] = skb; ++ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED; ++ ++ titan_ge_port->rx_used_desc_q = ++ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE; ++ } ++ ++ return count; ++} ++ ++/* ++ * Actual init of the Tital GE port. There is one register for ++ * the channel configuration ++ */ ++static void titan_port_init(struct net_device *netdev, ++ titan_ge_port_info * titan_ge_eth) ++{ ++ unsigned long reg_data; ++ ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ ++ /* First reset the TMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data |= 0x80000000; ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ udelay(30); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data &= ~(0xc0000000); ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ /* Now reset the RMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data |= 0x00080000; ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++ ++ udelay(30); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG); ++ reg_data &= ~(0x000c0000); ++ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data); ++} ++ ++/* ++ * Start the port. All the hardware specific configuration ++ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX ++ * go here ++ */ ++static int titan_ge_port_start(struct net_device *netdev, ++ titan_ge_port_info * titan_port) ++{ ++ volatile unsigned long reg_data, reg_data1; ++ int port_num = titan_port->port_num; ++ int count = 0; ++ unsigned long reg_data_1; ++ ++ if (config_done == 0) { ++ reg_data = TITAN_GE_READ(0x0004); ++ reg_data |= 0x100; ++ TITAN_GE_WRITE(0x0004, reg_data); ++ ++ reg_data &= ~(0x100); ++ TITAN_GE_WRITE(0x0004, reg_data); ++ ++ /* Turn on GMII/MII mode and turn off TBI mode */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1); ++ reg_data |= 0x00000700; ++ reg_data &= ~(0x00800000); /* Fencing */ ++ ++ TITAN_GE_WRITE(0x000c, 0x00001100); ++ ++ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data); ++ ++ /* Set the CPU Resource Limit register */ ++ TITAN_GE_WRITE(0x00f8, 0x8); ++ ++ /* Be conservative when using the BIU buffers */ ++ TITAN_GE_WRITE(0x0068, 0x4); ++ } ++ ++ titan_port->tx_threshold = 0; ++ titan_port->rx_threshold = 0; ++ ++ /* We need to write the descriptors for Tx and Rx */ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)), ++ (unsigned long) titan_port->tx_dma); ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)), ++ (unsigned long) titan_port->rx_dma); ++ ++ if (config_done == 0) { ++ /* Step 1: XDMA config */ ++ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG); ++ reg_data &= ~(0x80000000); /* clear reset */ ++ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */ ++ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */ ++ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */ ++ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */ ++ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data); ++ } ++ ++ /* IR register for the XDMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)); ++ reg_data |= 0x80068000; /* No Rx_OOD */ ++ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data); ++ ++ /* Start the Tx and Rx XDMA controller */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)); ++ reg_data &= 0x4fffffff; /* Clear tx reset */ ++ reg_data &= 0xfff4ffff; /* Clear rx reset */ ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ reg_data |= 0xa0 | 0x30030000; ++#else ++ reg_data |= 0x40 | 0x20030000; ++#endif ++ ++#ifndef CONFIG_SMP ++ reg_data &= ~(0x10); ++ reg_data |= 0x0f; /* All of the packet */ ++#endif ++ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data); ++ ++ /* Rx desc count */ ++ count = titan_ge_rx_task(netdev, titan_port); ++ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count); ++ count = TITAN_GE_READ(0x5048 + (port_num << 8)); ++ ++ udelay(30); ++ ++ /* ++ * Step 2: Configure the SDQPF, i.e. FIFO ++ */ ++ if (config_done == 0) { ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); ++ reg_data = 0x1; ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ reg_data &= ~(0x1); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); ++ reg_data = 0x1; ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ reg_data &= ~(0x1); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL); ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data); ++ } ++ /* ++ * Enable RX FIFO 0, 4 and 8 ++ */ ++ if (port_num == 0) { ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10); ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4844); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x4844, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data); ++ ++ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ reg_data |= (0xff << 10); ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4944); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x4944, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data); ++ ++ } ++ ++ if (port_num == 1) { ++ reg_data = TITAN_GE_READ(0x4870); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (0xff + 1); ++ ++ TITAN_GE_WRITE(0x4870, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4874); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x4874, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4870, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x494c); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x494c, reg_data); ++ reg_data |= (0xff << 10) | (0xff + 1); ++ TITAN_GE_WRITE(0x494c, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x4950); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x4950, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x494c, reg_data); ++ } ++ ++ /* ++ * Titan 1.2 revision does support port #2 ++ */ ++ if (port_num == 2) { ++ /* ++ * Put the descriptors in the SRAM ++ */ ++ reg_data = TITAN_GE_READ(0x48a0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x48a4); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x48a4, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x4958); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ TITAN_GE_WRITE(0x4958, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x495c); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x495c, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ } ++ ++ if (port_num == 2) { ++ reg_data = TITAN_GE_READ(0x48a0); ++ ++ reg_data |= 0x100000; ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ /* ++ * BAV2,BAV and DAV settings for the Rx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x48a4); ++ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1); ++ TITAN_GE_WRITE(0x48a4, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x48a0, reg_data); ++ ++ reg_data = TITAN_GE_READ(0x4958); ++ reg_data |= 0x100000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ reg_data |= (0xff << 10) | (2*(0xff + 1)); ++ TITAN_GE_WRITE(0x4958, reg_data); ++ ++ /* ++ * BAV2, BAV and DAV settings for the Tx FIFO ++ */ ++ reg_data1 = TITAN_GE_READ(0x495c); ++ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10); ++ ++ TITAN_GE_WRITE(0x495c, reg_data1); ++ ++ reg_data &= ~(0x00100000); ++ reg_data |= 0x200000; ++ ++ TITAN_GE_WRITE(0x4958, reg_data); ++ } ++ ++ /* ++ * Step 3: TRTG block enable ++ */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12)); ++ ++ /* ++ * This is the 1.2 revision of the chip. It has fix for the ++ * IP header alignment. Now, the IP header begins at an ++ * aligned address and this wont need an extra copy in the ++ * driver. This performance drawback existed in the previous ++ * versions of the silicon ++ */ ++ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12)); ++ reg_data_1 |= 0x40000000; ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ reg_data_1 |= 0x04000000; ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ mdelay(5); ++ ++ reg_data_1 &= ~(0x04000000); ++ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1); ++ ++ mdelay(5); ++ ++ reg_data |= 0x0001; ++ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data); ++ ++ /* ++ * Step 4: Start the Tx activity ++ */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197); ++#ifdef TITAN_GE_JUMBO_FRAMES ++ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000); ++#endif ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)); ++ reg_data |= 0x0001; /* Enable TMAC */ ++ reg_data |= 0x6c70; /* PAUSE also set */ ++ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ udelay(30); ++ ++ /* Destination Address drop bit */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)); ++ reg_data |= 0x218; /* DA_DROP bit and pause */ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data); ++ ++ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3); ++ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000); ++#endif ++ /* Start the Rx activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); ++ reg_data |= 0x0001; /* RMAC Enable */ ++ reg_data |= 0x0010; /* CRC Check enable */ ++ reg_data |= 0x0040; /* Min Frame check enable */ ++ reg_data |= 0x4400; /* Max Frame check enable */ ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ udelay(30); ++ ++ /* ++ * Enable the Interrupts for Tx and Rx ++ */ ++ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ ++ if (port_num == 0) { ++ reg_data1 |= 0x3; ++#ifdef CONFIG_SMP ++ TITAN_GE_WRITE(0x0038, 0x003); ++#else ++ TITAN_GE_WRITE(0x0038, 0x303); ++#endif ++ } ++ ++ if (port_num == 1) { ++ reg_data1 |= 0x300; ++ } ++ ++ if (port_num == 2) ++ reg_data1 |= 0x30000; ++ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1); ++ TITAN_GE_WRITE(0x003c, 0x300); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */ ++ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */ ++ } ++ ++ /* Priority */ ++ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12)); ++ reg_data &= ~(0x00f00000); ++ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data); ++ ++ /* Step 5: GMII config */ ++ titan_ge_gmii_config(port_num); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(0x1a80, 0); ++ config_done = 1; ++ } ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Function to queue the packet for the Ethernet device ++ */ ++static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth, ++ struct sk_buff * skb) ++{ ++ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev; ++ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q; ++ volatile titan_ge_tx_desc *tx_curr; ++ int port_num = titan_ge_eth->port_num; ++ ++ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]); ++ tx_curr->buffer_addr = ++ dma_map_single(device, skb->data, skb_headlen(skb), ++ DMA_TO_DEVICE); ++ ++ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb; ++ tx_curr->buffer_len = skb_headlen(skb); ++ ++ /* Last descriptor enables interrupt and changes ownership */ ++ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5); ++ ++ /* Kick the XDMA to start the transfer from memory to the FIFO */ ++ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1); ++ ++ /* Current descriptor updated */ ++ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE; ++ ++ /* Prefetch the next descriptor */ ++ prefetch((const void *) ++ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]); ++} ++ ++/* ++ * Actually does the open of the Ethernet device ++ */ ++static int titan_ge_eth_open(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ struct device *device = &titan_ge_device[port_num]->dev; ++ unsigned long reg_data; ++ unsigned int phy_reg; ++ int err = 0; ++ ++ /* Stop the Rx activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data); ++ ++ /* Clear the port interrupts */ ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0); ++ ++ if (config_done == 0) { ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0); ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0); ++ } ++ ++ /* Set the MAC Address */ ++ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); ++ ++ if (config_done == 0) ++ titan_port_init(netdev, titan_ge_eth); ++ ++ titan_ge_update_afx(titan_ge_eth); ++ ++ /* Allocate the Tx ring now */ ++ titan_ge_eth->tx_ring_skbs = 0; ++ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE; ++ ++ /* Allocate space in the SRAM for the descriptors */ ++ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *) ++ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num); ++ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num; ++ ++ if (!titan_ge_eth->tx_desc_area) { ++ printk(KERN_ERR ++ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n", ++ netdev->name, TITAN_TX_RING_BYTES, port_num); ++ return -ENOMEM; ++ } ++ ++ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size); ++ ++ /* Now initialize the Tx descriptor ring */ ++ titan_ge_init_tx_desc_ring(titan_ge_eth, ++ titan_ge_eth->tx_ring_size, ++ (unsigned long) titan_ge_eth->tx_desc_area, ++ (unsigned long) titan_ge_eth->tx_dma); ++ ++ /* Allocate the Rx ring now */ ++ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE; ++ titan_ge_eth->rx_ring_skbs = 0; ++ ++ titan_ge_eth->rx_desc_area = ++ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num); ++ ++ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num; ++ ++ if (!titan_ge_eth->rx_desc_area) { ++ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", ++ netdev->name, TITAN_RX_RING_BYTES); ++ ++ printk(KERN_ERR "%s: Freeing previously allocated TX queues...", ++ netdev->name); ++ ++ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size, ++ (void *) titan_ge_eth->tx_desc_area, ++ titan_ge_eth->tx_dma); ++ ++ return -ENOMEM; ++ } ++ ++ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size); ++ ++ /* Now initialize the Rx ring */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++ if ((titan_ge_init_rx_desc_ring ++ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE, ++ (unsigned long) titan_ge_eth->rx_desc_area, 0, ++ (unsigned long) titan_ge_eth->rx_dma)) == 0) ++#else ++ if ((titan_ge_init_rx_desc_ring ++ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE, ++ (unsigned long) titan_ge_eth->rx_desc_area, 0, ++ (unsigned long) titan_ge_eth->rx_dma)) == 0) ++#endif ++ panic("%s: Error initializing RX Ring\n", netdev->name); ++ ++ /* Fill the Rx ring with the SKBs */ ++ titan_ge_port_start(netdev, titan_ge_eth); ++ ++ /* ++ * Check if Interrupt Coalscing needs to be turned on. The ++ * values specified in the register is multiplied by ++ * (8 x 64 nanoseconds) to determine when an interrupt should ++ * be sent to the CPU. ++ */ ++ ++ if (TITAN_GE_TX_COAL) { ++ titan_ge_eth->tx_int_coal = ++ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num); ++ } ++ ++ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg); ++ if (err == TITAN_GE_MDIO_ERROR) { ++ printk(KERN_ERR ++ "Could not read PHY control register 0x11 \n"); ++ return TITAN_ERROR; ++ } ++ if (!(phy_reg & 0x0400)) { ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ return TITAN_ERROR; ++ } else { ++ netif_carrier_on(netdev); ++ netif_start_queue(netdev); ++ } ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Queue the packet for Tx. Currently no support for zero copy, ++ * checksum offload and Scatter Gather. The chip does support ++ * Scatter Gather only. But, that wont help here since zero copy ++ * requires support for Tx checksumming also. ++ */ ++int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned long flags; ++ struct net_device_stats *stats; ++//printk("titan_ge_start_xmit\n"); ++ ++ stats = &titan_ge_eth->stats; ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <= ++ (skb_shinfo(skb)->nr_frags + 1)) { ++ netif_stop_queue(netdev); ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ printk(KERN_ERR "Tx OOD \n"); ++ return 1; ++ } ++ ++ titan_ge_tx_queue(titan_ge_eth, skb); ++ titan_ge_eth->tx_ring_skbs++; ++ ++ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) { ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ titan_ge_free_tx_queue(titan_ge_eth); ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ } ++ ++ stats->tx_bytes += skb->len; ++ stats->tx_packets++; ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ netdev->trans_start = jiffies; ++ ++ return 0; ++} ++ ++/* ++ * Actually does the Rx. Rx side checksumming supported. ++ */ ++static int titan_ge_rx(struct net_device *netdev, int port_num, ++ titan_ge_port_info * titan_ge_port, ++ titan_ge_packet * packet) ++{ ++ int rx_curr_desc, rx_used_desc; ++ volatile titan_ge_rx_desc *rx_desc; ++ ++ rx_curr_desc = titan_ge_port->rx_curr_desc_q; ++ rx_used_desc = titan_ge_port->rx_used_desc_q; ++ ++ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc) ++ return TITAN_ERROR; ++ ++ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]); ++ ++ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED) ++ return TITAN_ERROR; ++ ++ packet->skb = titan_ge_port->rx_skb[rx_curr_desc]; ++ packet->len = (rx_desc->cmd_sts & 0x7fff); ++ ++ /* ++ * At this point, we dont know if the checksumming ++ * actually helps relieve CPU. So, keep it for ++ * port 0 only ++ */ ++ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16); ++ packet->cmd_sts = rx_desc->cmd_sts; ++ ++ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE; ++ ++ /* Prefetch the next descriptor */ ++ prefetch((const void *) ++ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Free the Tx queue of the used SKBs ++ */ ++static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth) ++{ ++ unsigned long flags; ++ ++ /* Take the lock */ ++ spin_lock_irqsave(&(titan_ge_eth->lock), flags); ++ ++ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0) ++ if (titan_ge_eth->tx_ring_skbs != 1) ++ titan_ge_eth->tx_ring_skbs--; ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Threshold beyond which we do the cleaning of ++ * Tx queue and new allocation for the Rx ++ * queue ++ */ ++#define TX_THRESHOLD 4 ++#define RX_THRESHOLD 10 ++ ++/* ++ * Receive the packets and send it to the kernel. ++ */ ++static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ titan_ge_packet packet; ++ struct net_device_stats *stats; ++ struct sk_buff *skb; ++ unsigned long received_packets = 0; ++ unsigned int ack; ++ ++ stats = &titan_ge_eth->stats; ++ ++ while ((--max) ++ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) { ++ skb = (struct sk_buff *) packet.skb; ++ ++ titan_ge_eth->rx_ring_skbs--; ++ ++ if (--titan_ge_eth->rx_work_limit < 0) ++ break; ++ received_packets++; ++ ++ stats->rx_packets++; ++ stats->rx_bytes += packet.len; ++ ++ if ((packet.cmd_sts & TITAN_GE_RX_PERR) || ++ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) || ++ (packet.cmd_sts & TITAN_GE_RX_TRUNC) || ++ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) { ++ stats->rx_dropped++; ++ dev_kfree_skb_any(skb); ++ ++ continue; ++ } ++ /* ++ * Either support fast path or slow path. Decision ++ * making can really slow down the performance. The ++ * idea is to cut down the number of checks and improve ++ * the fastpath. ++ */ ++ ++ skb_put(skb, packet.len - 2); ++ ++ /* ++ * Increment data pointer by two since thats where ++ * the MAC starts ++ */ ++ skb_reserve(skb, 2); ++ skb->protocol = eth_type_trans(skb, netdev); ++ netif_receive_skb(skb); ++ ++ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) { ++ ack = titan_ge_rx_task(netdev, titan_ge_eth); ++ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack); ++ titan_ge_eth->rx_threshold = 0; ++ } else ++ titan_ge_eth->rx_threshold++; ++ ++ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) { ++ titan_ge_eth->tx_threshold = 0; ++ titan_ge_free_tx_queue(titan_ge_eth); ++ } ++ else ++ titan_ge_eth->tx_threshold++; ++ ++ } ++ return received_packets; ++} ++ ++ ++/* ++ * Enable the Rx side interrupts ++ */ ++static void titan_ge_enable_int(unsigned int port_num, ++ titan_ge_port_info *titan_ge_eth, ++ struct net_device *netdev) ++{ ++ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE); ++ ++ if (port_num == 0) ++ reg_data |= 0x3; ++ if (port_num == 1) ++ reg_data |= 0x300; ++ if (port_num == 2) ++ reg_data |= 0x30000; ++ ++ /* Re-enable interrupts */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data); ++} ++ ++/* ++ * Main function to handle the polling for Rx side NAPI. ++ * Receive interrupts have been disabled at this point. ++ * The poll schedules the transmit followed by receive. ++ */ ++static int titan_ge_poll(struct net_device *netdev, int *budget) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ int port_num = titan_ge_eth->port_num; ++ int work_done = 0; ++ unsigned long flags, status; ++ ++ titan_ge_eth->rx_work_limit = *budget; ++ if (titan_ge_eth->rx_work_limit > netdev->quota) ++ titan_ge_eth->rx_work_limit = netdev->quota; ++ ++ do { ++ /* Do the transmit cleaning work here */ ++ titan_ge_free_tx_queue(titan_ge_eth); ++ ++ /* Ack the Rx interrupts */ ++ if (port_num == 0) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3); ++ if (port_num == 1) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300); ++ if (port_num == 2) ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000); ++ ++ work_done += titan_ge_receive_queue(netdev, 0); ++ ++ /* Out of quota and there is work to be done */ ++ if (titan_ge_eth->rx_work_limit < 0) ++ goto not_done; ++ ++ /* Receive alloc_skb could lead to OOM */ ++ if (oom_flag == 1) { ++ oom_flag = 0; ++ goto oom; ++ } ++ ++ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A); ++ } while (status & 0x30300); ++ ++ /* If we are here, then no more interrupts to process */ ++ goto done; ++ ++not_done: ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ return 1; ++ ++oom: ++ printk(KERN_ERR "OOM \n"); ++ netif_rx_complete(netdev); ++ return 0; ++ ++done: ++ /* ++ * No more packets on the poll list. Turn the interrupts ++ * back on and we should be able to catch the new ++ * packets in the interrupt handler ++ */ ++ if (!work_done) ++ work_done = 1; ++ ++ *budget -= work_done; ++ netdev->quota -= work_done; ++ ++ spin_lock_irqsave(&titan_ge_eth->lock, flags); ++ ++ /* Remove us from the poll list */ ++ netif_rx_complete(netdev); ++ ++ /* Re-enable interrupts */ ++ titan_ge_enable_int(port_num, titan_ge_eth, netdev); ++ ++ spin_unlock_irqrestore(&titan_ge_eth->lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * Close the network device ++ */ ++int titan_ge_stop(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ spin_lock_irq(&(titan_ge_eth->lock)); ++ titan_ge_eth_stop(netdev); ++ free_irq(netdev->irq, netdev); ++ spin_unlock_irq(&titan_ge_eth->lock); ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Free the Tx ring ++ */ ++static void titan_ge_free_tx_rings(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int curr; ++ unsigned long reg_data; ++ ++ /* Stop the Tx DMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)); ++ reg_data |= 0xc0000000; ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)), reg_data); ++ ++ /* Disable the TMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ for (curr = 0; ++ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE); ++ curr++) { ++ if (titan_ge_eth->tx_skb[curr]) { ++ dev_kfree_skb(titan_ge_eth->tx_skb[curr]); ++ titan_ge_eth->tx_ring_skbs--; ++ } ++ } ++ ++ if (titan_ge_eth->tx_ring_skbs != 0) ++ printk ++ ("%s: Error on Tx descriptor free - could not free %d" ++ " descriptors\n", netdev->name, ++ titan_ge_eth->tx_ring_skbs); ++ ++#ifndef TITAN_RX_RING_IN_SRAM ++ dma_free_coherent(&titan_ge_device[port_num]->dev, ++ titan_ge_eth->tx_desc_area_size, ++ (void *) titan_ge_eth->tx_desc_area, ++ titan_ge_eth->tx_dma); ++#endif ++} ++ ++/* ++ * Free the Rx ring ++ */ ++static void titan_ge_free_rx_rings(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ unsigned int curr; ++ unsigned long reg_data; ++ ++ /* Stop the Rx DMA */ ++ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)); ++ reg_data |= 0x000c0000; ++ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + ++ (port_num << 8)), reg_data); ++ ++ /* Disable the RMAC */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x00000001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ for (curr = 0; ++ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE); ++ curr++) { ++ if (titan_ge_eth->rx_skb[curr]) { ++ dev_kfree_skb(titan_ge_eth->rx_skb[curr]); ++ titan_ge_eth->rx_ring_skbs--; ++ } ++ } ++ ++ if (titan_ge_eth->rx_ring_skbs != 0) ++ printk(KERN_ERR ++ "%s: Error in freeing Rx Ring. %d skb's still" ++ " stuck in RX Ring - ignoring them\n", netdev->name, ++ titan_ge_eth->rx_ring_skbs); ++ ++#ifndef TITAN_RX_RING_IN_SRAM ++ dma_free_coherent(&titan_ge_device[port_num]->dev, ++ titan_ge_eth->rx_desc_area_size, ++ (void *) titan_ge_eth->rx_desc_area, ++ titan_ge_eth->rx_dma); ++#endif ++} ++ ++/* ++ * Actually does the stop of the Ethernet device ++ */ ++static void titan_ge_eth_stop(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ netif_stop_queue(netdev); ++ ++ titan_ge_port_reset(titan_ge_eth->port_num); ++ ++ titan_ge_free_tx_rings(netdev); ++ titan_ge_free_rx_rings(netdev); ++ ++ /* Disable the Tx and Rx Interrupts for all channels */ ++ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0); ++} ++ ++/* ++ * Update the MAC address. Note that we have to write the ++ * address in three station registers, 16 bits each. And this ++ * has to be done for TMAC and RMAC ++ */ ++static void titan_ge_update_mac_address(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ unsigned int port_num = titan_ge_eth->port_num; ++ u8 p_addr[6]; ++ ++ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6); ++ memcpy(p_addr, netdev->dev_addr, 6); ++ ++ /* Update the Address Filtering Match tables */ ++ titan_ge_update_afx(titan_ge_eth); ++ ++ printk("Station MAC : %d %d %d %d %d %d \n", ++ p_addr[5], p_addr[4], p_addr[3], ++ p_addr[2], p_addr[1], p_addr[0]); ++ ++ /* Set the MAC address here for TMAC and RMAC */ ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++ ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)), ++ ((p_addr[5] << 8) | p_addr[4])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)), ++ ((p_addr[3] << 8) | p_addr[2])); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)), ++ ((p_addr[1] << 8) | p_addr[0])); ++} ++ ++/* ++ * Set the MAC address of the Ethernet device ++ */ ++static int titan_ge_set_mac_address(struct net_device *dev, void *addr) ++{ ++ titan_ge_port_info *tp = netdev_priv(dev); ++ struct sockaddr *sa = addr; ++ ++ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); ++ ++ spin_lock_irq(&tp->lock); ++ titan_ge_update_mac_address(dev); ++ spin_unlock_irq(&tp->lock); ++ ++ return 0; ++} ++ ++/* ++ * Get the Ethernet device stats ++ */ ++static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev) ++{ ++ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev); ++ ++ return &titan_ge_eth->stats; ++} ++ ++/* ++ * Initialize the Rx descriptor ring for the Titan Ge ++ */ ++static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port, ++ int rx_desc_num, ++ int rx_buff_size, ++ unsigned long rx_desc_base_addr, ++ unsigned long rx_buff_base_addr, ++ unsigned long rx_dma) ++{ ++ volatile titan_ge_rx_desc *rx_desc; ++ unsigned long buffer_addr; ++ int index; ++ unsigned long titan_ge_rx_desc_bus = rx_dma; ++ ++ buffer_addr = rx_buff_base_addr; ++ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr; ++ ++ /* Check alignment */ ++ if (rx_buff_base_addr & 0xF) ++ return 0; ++ ++ /* Check Rx buffer size */ ++ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER)) ++ return 0; ++ ++ /* 64-bit alignment ++ if ((rx_buff_base_addr + rx_buff_size) & 0x7) ++ return 0; */ ++ ++ /* Initialize the Rx desc ring */ ++ for (index = 0; index < rx_desc_num; index++) { ++ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc); ++ rx_desc[index].cmd_sts = 0; ++ rx_desc[index].buffer_addr = buffer_addr; ++ titan_eth_port->rx_skb[index] = NULL; ++ buffer_addr += rx_buff_size; ++ } ++ ++ titan_eth_port->rx_curr_desc_q = 0; ++ titan_eth_port->rx_used_desc_q = 0; ++ ++ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr; ++ titan_eth_port->rx_desc_area_size = ++ rx_desc_num * sizeof(titan_ge_rx_desc); ++ ++ titan_eth_port->rx_dma = rx_dma; ++ ++ return TITAN_OK; ++} ++ ++/* ++ * Initialize the Tx descriptor ring. Descriptors in the SRAM ++ */ ++static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port, ++ int tx_desc_num, ++ unsigned long tx_desc_base_addr, ++ unsigned long tx_dma) ++{ ++ titan_ge_tx_desc *tx_desc; ++ int index; ++ unsigned long titan_ge_tx_desc_bus = tx_dma; ++ ++ if (tx_desc_base_addr & 0xF) ++ return 0; ++ ++ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr; ++ ++ for (index = 0; index < tx_desc_num; index++) { ++ titan_ge_port->tx_dma_array[index] = ++ (dma_addr_t) titan_ge_tx_desc_bus; ++ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc); ++ tx_desc[index].cmd_sts = 0x0000; ++ tx_desc[index].buffer_len = 0; ++ tx_desc[index].buffer_addr = 0x00000000; ++ titan_ge_port->tx_skb[index] = NULL; ++ } ++ ++ titan_ge_port->tx_curr_desc_q = 0; ++ titan_ge_port->tx_used_desc_q = 0; ++ ++ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr; ++ titan_ge_port->tx_desc_area_size = ++ tx_desc_num * sizeof(titan_ge_tx_desc); ++ ++ titan_ge_port->tx_dma = tx_dma; ++ return TITAN_OK; ++} ++ ++/* ++ * Initialize the device as an Ethernet device ++ */ ++static int __init titan_ge_probe(struct device *device) ++{ ++ titan_ge_port_info *titan_ge_eth; ++ struct net_device *netdev; ++ int port = to_platform_device(device)->id; ++ int err; ++ ++ netdev = alloc_etherdev(sizeof(titan_ge_port_info)); ++ if (!netdev) { ++ err = -ENODEV; ++ goto out; ++ } ++ ++ netdev->open = titan_ge_open; ++ netdev->stop = titan_ge_stop; ++ netdev->hard_start_xmit = titan_ge_start_xmit; ++ netdev->get_stats = titan_ge_get_stats; ++ netdev->set_multicast_list = titan_ge_set_multi; ++ netdev->set_mac_address = titan_ge_set_mac_address; ++ ++ /* Tx timeout */ ++ netdev->tx_timeout = titan_ge_tx_timeout; ++ netdev->watchdog_timeo = 2 * HZ; ++ ++ /* Set these to very high values */ ++ netdev->poll = titan_ge_poll; ++ netdev->weight = 64; ++ ++ netdev->tx_queue_len = TITAN_GE_TX_QUEUE; ++ netif_carrier_off(netdev); ++ netdev->base_addr = 0; ++ ++ netdev->change_mtu = titan_ge_change_mtu; ++ ++ titan_ge_eth = netdev_priv(netdev); ++ /* Allocation of memory for the driver structures */ ++ ++ titan_ge_eth->port_num = port; ++ ++ /* Configure the Tx timeout handler */ ++ INIT_WORK(&titan_ge_eth->tx_timeout_task, ++ (void (*)(void *)) titan_ge_tx_timeout_task, netdev); ++ ++ spin_lock_init(&titan_ge_eth->lock); ++ ++ /* set MAC addresses */ ++ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6); ++ netdev->dev_addr[5] += port; ++ ++ err = register_netdev(netdev); ++ ++ if (err) ++ goto out_free_netdev; ++ ++ printk(KERN_NOTICE ++ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", ++ netdev->name, port, netdev->dev_addr[0], ++ netdev->dev_addr[1], netdev->dev_addr[2], ++ netdev->dev_addr[3], netdev->dev_addr[4], ++ netdev->dev_addr[5]); ++ ++ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n"); ++ ++ return 0; ++ ++out_free_netdev: ++ kfree(netdev); ++ ++out: ++ return err; ++} ++ ++static void __devexit titan_device_remove(struct device *device) ++{ ++} ++ ++/* ++ * Reset the Ethernet port ++ */ ++static void titan_ge_port_reset(unsigned int port_num) ++{ ++ unsigned int reg_data; ++ ++ /* Stop the Tx port activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x0001); ++ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ /* Stop the Rx port activity */ ++ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)); ++ reg_data &= ~(0x0001); ++ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + ++ (port_num << 12)), reg_data); ++ ++ return; ++} ++ ++/* ++ * Return the Tx desc after use by the XDMA ++ */ ++static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port) ++{ ++ int tx_desc_used; ++ struct sk_buff *skb; ++ ++ tx_desc_used = titan_ge_eth->tx_used_desc_q; ++ ++ /* return right away */ ++ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q) ++ return TITAN_ERROR; ++ ++ /* Now the critical stuff */ ++ skb = titan_ge_eth->tx_skb[tx_desc_used]; ++ ++ dev_kfree_skb_any(skb); ++ ++ titan_ge_eth->tx_skb[tx_desc_used] = NULL; ++ titan_ge_eth->tx_used_desc_q = ++ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE; ++ ++ return 0; ++} ++ ++/* ++ * Coalescing for the Tx path ++ */ ++static unsigned long titan_ge_tx_coal(unsigned long delay, int port) ++{ ++ unsigned long rx_delay; ++ ++ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING); ++ delay = (delay << 16) | rx_delay; ++ ++ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay); ++ TITAN_GE_WRITE(0x5038, delay); ++ ++ return delay; ++} ++ ++static struct device_driver titan_soc_driver = { ++ .name = titan_string, ++ .bus = &platform_bus_type, ++ .probe = titan_ge_probe, ++ .remove = __devexit_p(titan_device_remove), ++}; ++ ++static void titan_platform_release (struct device *device) ++{ ++ struct platform_device *pldev; ++ ++ /* free device */ ++ pldev = to_platform_device (device); ++ kfree (pldev); ++} ++ ++/* ++ * Register the Titan GE with the kernel ++ */ ++static int __init titan_ge_init_module(void) ++{ ++ struct platform_device *pldev; ++ unsigned int version, device; ++ int i; ++ ++ printk(KERN_NOTICE ++ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n"); ++ ++ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE); ++ if (!titan_ge_base) { ++ printk("Mapping Titan GE failed\n"); ++ goto out; ++ } ++ ++ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID); ++ version = (device & 0x000f0000) >> 16; ++ device &= 0x0000ffff; ++ ++ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version); ++ ++#ifdef TITAN_RX_RING_IN_SRAM ++ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE, ++ TITAN_SRAM_SIZE); ++ if (!titan_ge_sram) { ++ printk("Mapping Titan SRAM failed\n"); ++ goto out_unmap_ge; ++ } ++#endif ++ ++ if (driver_register(&titan_soc_driver)) { ++ printk(KERN_ERR "Driver registration failed\n"); ++ goto out_unmap_sram; ++ } ++ ++ for (i = 0; i < 3; i++) { ++ titan_ge_device[i] = NULL; ++ ++ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) ++ continue; ++ ++ memset (pldev, 0, sizeof (*pldev)); ++ pldev->name = titan_string; ++ pldev->id = i; ++ pldev->dev.release = titan_platform_release; ++ titan_ge_device[i] = pldev; ++ ++ if (platform_device_register (pldev)) { ++ kfree (pldev); ++ titan_ge_device[i] = NULL; ++ continue; ++ } ++ ++ if (!pldev->dev.driver) { ++ /* ++ * The driver was not bound to this device, there was ++ * no hardware at this address. Unregister it, as the ++ * release fuction will take care of freeing the ++ * allocated structure ++ */ ++ titan_ge_device[i] = NULL; ++ platform_device_unregister (pldev); ++ } ++ } ++ ++ return 0; ++ ++out_unmap_sram: ++ iounmap((void *)titan_ge_sram); ++ ++out_unmap_ge: ++ iounmap((void *)titan_ge_base); ++ ++out: ++ return -ENOMEM; ++} ++ ++/* ++ * Unregister the Titan GE from the kernel ++ */ ++static void __exit titan_ge_cleanup_module(void) ++{ ++ int i; ++ ++ driver_unregister(&titan_soc_driver); ++ ++ for (i = 0; i < 3; i++) { ++ if (titan_ge_device[i]) { ++ platform_device_unregister (titan_ge_device[i]); ++ titan_ge_device[i] = NULL; ++ } ++ } ++ ++ iounmap((void *)titan_ge_sram); ++ iounmap((void *)titan_ge_base); ++} ++ ++MODULE_AUTHOR("Manish Lachwani "); ++MODULE_DESCRIPTION("Titan GE Ethernet driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(titan_ge_init_module); ++module_exit(titan_ge_cleanup_module); +diff --git a/drivers/net/titan_ge.h b/drivers/net/titan_ge.h +new file mode 100644 +index 0000000..3719f78 +--- /dev/null ++++ b/drivers/net/titan_ge.h +@@ -0,0 +1,415 @@ ++#ifndef _TITAN_GE_H_ ++#define _TITAN_GE_H_ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * These functions should be later moved to a more generic location since there ++ * will be others accessing it also ++ */ ++ ++/* ++ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in ++ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5 ++ * register. ++ */ ++ ++#define TITAN_GE_BASE 0xfe000000UL ++#define TITAN_GE_SIZE 0x10000UL ++ ++extern unsigned long titan_ge_base; ++ ++#define TITAN_GE_WRITE(offset, data) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) = (data) ++ ++#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset)) ++ ++#ifndef msec_delay ++#define msec_delay(x) do { if(in_interrupt()) { \ ++ /* Don't mdelay in interrupt context! */ \ ++ BUG(); \ ++ } else { \ ++ set_current_state(TASK_UNINTERRUPTIBLE); \ ++ schedule_timeout((x * HZ)/1000); \ ++ } } while(0) ++#endif ++ ++#define TITAN_GE_PORT_0 ++ ++#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4) ++#define TITAN_SRAM_SIZE 0x2000UL ++ ++/* ++ * We may need these constants ++ */ ++#define TITAN_BIT0 0x00000001 ++#define TITAN_BIT1 0x00000002 ++#define TITAN_BIT2 0x00000004 ++#define TITAN_BIT3 0x00000008 ++#define TITAN_BIT4 0x00000010 ++#define TITAN_BIT5 0x00000020 ++#define TITAN_BIT6 0x00000040 ++#define TITAN_BIT7 0x00000080 ++#define TITAN_BIT8 0x00000100 ++#define TITAN_BIT9 0x00000200 ++#define TITAN_BIT10 0x00000400 ++#define TITAN_BIT11 0x00000800 ++#define TITAN_BIT12 0x00001000 ++#define TITAN_BIT13 0x00002000 ++#define TITAN_BIT14 0x00004000 ++#define TITAN_BIT15 0x00008000 ++#define TITAN_BIT16 0x00010000 ++#define TITAN_BIT17 0x00020000 ++#define TITAN_BIT18 0x00040000 ++#define TITAN_BIT19 0x00080000 ++#define TITAN_BIT20 0x00100000 ++#define TITAN_BIT21 0x00200000 ++#define TITAN_BIT22 0x00400000 ++#define TITAN_BIT23 0x00800000 ++#define TITAN_BIT24 0x01000000 ++#define TITAN_BIT25 0x02000000 ++#define TITAN_BIT26 0x04000000 ++#define TITAN_BIT27 0x08000000 ++#define TITAN_BIT28 0x10000000 ++#define TITAN_BIT29 0x20000000 ++#define TITAN_BIT30 0x40000000 ++#define TITAN_BIT31 0x80000000 ++ ++/* Flow Control */ ++#define TITAN_GE_FC_NONE 0x0 ++#define TITAN_GE_FC_FULL 0x1 ++#define TITAN_GE_FC_TX_PAUSE 0x2 ++#define TITAN_GE_FC_RX_PAUSE 0x3 ++ ++/* Duplex Settings */ ++#define TITAN_GE_FULL_DUPLEX 0x1 ++#define TITAN_GE_HALF_DUPLEX 0x2 ++ ++/* Speed settings */ ++#define TITAN_GE_SPEED_1000 0x1 ++#define TITAN_GE_SPEED_100 0x2 ++#define TITAN_GE_SPEED_10 0x3 ++ ++/* Debugging info only */ ++#undef TITAN_DEBUG ++ ++/* Keep the rings in the Titan's SSRAM */ ++#define TITAN_RX_RING_IN_SRAM ++ ++#ifdef CONFIG_64BIT ++#define TITAN_GE_IE_MASK 0xfffffffffb001b64 ++#define TITAN_GE_IE_STATUS 0xfffffffffb001b60 ++#else ++#define TITAN_GE_IE_MASK 0xfb001b64 ++#define TITAN_GE_IE_STATUS 0xfb001b60 ++#endif ++ ++/* Support for Jumbo Frames */ ++#undef TITAN_GE_JUMBO_FRAMES ++ ++/* Rx buffer size */ ++#ifdef TITAN_GE_JUMBO_FRAMES ++#define TITAN_GE_JUMBO_BUFSIZE 9080 ++#else ++#define TITAN_GE_STD_BUFSIZE 1580 ++#endif ++ ++/* ++ * Tx and Rx Interrupt Coalescing parameter. These values are ++ * for 1 Ghz processor. Rx coalescing can be taken care of ++ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing ++ * is not adaptive. Hence, these values need to be adjusted ++ * based on load, CPU speed etc. ++ */ ++#define TITAN_GE_RX_COAL 150 ++#define TITAN_GE_TX_COAL 300 ++ ++#if defined(__BIG_ENDIAN) ++ ++/* Define the Rx descriptor */ ++typedef struct eth_rx_desc { ++ u32 reserved; /* Unused */ ++ u32 buffer_addr; /* CPU buffer address */ ++ u32 cmd_sts; /* Command and Status */ ++ u32 buffer; /* XDMA buffer address */ ++} titan_ge_rx_desc; ++ ++/* Define the Tx descriptor */ ++typedef struct eth_tx_desc { ++ u16 cmd_sts; /* Command, Status and Buffer count */ ++ u16 buffer_len; /* Length of the buffer */ ++ u32 buffer_addr; /* Physical address of the buffer */ ++} titan_ge_tx_desc; ++ ++#elif defined(__LITTLE_ENDIAN) ++ ++/* Define the Rx descriptor */ ++typedef struct eth_rx_desc { ++ u32 buffer_addr; /* CPU buffer address */ ++ u32 reserved; /* Unused */ ++ u32 buffer; /* XDMA buffer address */ ++ u32 cmd_sts; /* Command and Status */ ++} titan_ge_rx_desc; ++ ++/* Define the Tx descriptor */ ++typedef struct eth_tx_desc { ++ u32 buffer_addr; /* Physical address of the buffer */ ++ u16 buffer_len; /* Length of the buffer */ ++ u16 cmd_sts; /* Command, Status and Buffer count */ ++} titan_ge_tx_desc; ++#endif ++ ++/* Default Tx Queue Size */ ++#define TITAN_GE_TX_QUEUE 128 ++#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc)) ++ ++/* Default Rx Queue Size */ ++#define TITAN_GE_RX_QUEUE 64 ++#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc)) ++ ++/* Packet Structure */ ++typedef struct _pkt_info { ++ unsigned int len; ++ unsigned int cmd_sts; ++ unsigned int buffer; ++ struct sk_buff *skb; ++ unsigned int checksum; ++} titan_ge_packet; ++ ++ ++#define PHYS_CNT 3 ++ ++/* Titan Port specific data structure */ ++typedef struct _eth_port_ctrl { ++ unsigned int port_num; ++ u8 port_mac_addr[6]; ++ ++ /* Rx descriptor pointers */ ++ int rx_curr_desc_q, rx_used_desc_q; ++ ++ /* Tx descriptor pointers */ ++ int tx_curr_desc_q, tx_used_desc_q; ++ ++ /* Rx descriptor area */ ++ volatile titan_ge_rx_desc *rx_desc_area; ++ unsigned int rx_desc_area_size; ++ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE]; ++ ++ /* Tx Descriptor area */ ++ volatile titan_ge_tx_desc *tx_desc_area; ++ unsigned int tx_desc_area_size; ++ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE]; ++ ++ /* Timeout task */ ++ struct work_struct tx_timeout_task; ++ ++ /* DMA structures and handles */ ++ dma_addr_t tx_dma; ++ dma_addr_t rx_dma; ++ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE]; ++ ++ /* Device lock */ ++ spinlock_t lock; ++ ++ unsigned int tx_ring_skbs; ++ unsigned int rx_ring_size; ++ unsigned int tx_ring_size; ++ unsigned int rx_ring_skbs; ++ ++ struct net_device_stats stats; ++ ++ /* Tx and Rx coalescing */ ++ unsigned long rx_int_coal; ++ unsigned long tx_int_coal; ++ ++ /* Threshold for replenishing the Rx and Tx rings */ ++ unsigned int tx_threshold; ++ unsigned int rx_threshold; ++ ++ /* NAPI work limit */ ++ unsigned int rx_work_limit; ++} titan_ge_port_info; ++ ++/* Titan specific constants */ ++#define TITAN_ETH_PORT_IRQ 3 ++ ++/* Max Rx buffer */ ++#define TITAN_GE_MAX_RX_BUFFER 65536 ++ ++/* Tx and Rx Error */ ++#define TITAN_GE_ERROR ++ ++/* Rx Descriptor Command and Status */ ++ ++#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */ ++#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */ ++#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */ ++#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */ ++#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */ ++#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */ ++#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */ ++#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */ ++#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */ ++#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */ ++ ++/* Tx Descriptor Command */ ++#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */ ++#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */ ++ ++/* Return Status */ ++#define TITAN_OK 0x1 /* Good Status */ ++#define TITAN_ERROR 0x2 /* Error Status */ ++ ++/* MIB specific register offset */ ++#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */ ++#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */ ++#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */ ++#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */ ++#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */ ++ ++/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */ ++#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040 ++#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050 ++#define TITAN_GE_MSTATX_RXFRAMES 0x0060 ++#define TITAN_GE_MSTATX_RXOCTETS 0x0070 ++#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080 ++#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090 ++#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0 ++#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0 ++#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0 ++#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0 ++#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0 ++#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0 ++#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100 ++#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110 ++#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120 ++#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130 ++#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140 ++#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150 ++#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160 ++#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170 ++#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180 ++#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190 ++#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0 ++#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0 ++#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0 ++#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0 ++#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0 ++#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0 ++#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200 ++#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210 ++#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220 ++#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230 ++#define TITAN_GE_MSTATX_HASHFILTERED 0x0240 ++#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250 ++#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260 ++#define TITAN_GE_MSTATX_TXOCTETS 0x0270 ++#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280 ++#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290 ++#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0 ++#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0 ++#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0 ++#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0 ++#define TITAN_GE_MSTATX_TXMACERROR 0x02E0 ++#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0 ++#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300 ++#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310 ++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320 ++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330 ++#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340 ++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350 ++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360 ++#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370 ++#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380 ++#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390 ++#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0 ++#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0 ++#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0 ++#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0 ++#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0 ++#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0 ++#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400 ++#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410 ++#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420 ++#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430 ++#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440 ++ ++/* Interrupt specific defines */ ++#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */ ++#define TITAN_GE_RESET 0x0004 /* Reset reg */ ++#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */ ++#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */ ++#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */ ++#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/ ++#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/ ++#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */ ++#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */ ++#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/ ++#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */ ++#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/ ++#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */ ++#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */ ++#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */ ++#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */ ++#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */ ++#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */ ++#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */ ++#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */ ++ ++/* Rx MAC defines */ ++#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */ ++#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */ ++#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */ ++#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */ ++#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */ ++#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */ ++#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */ ++ ++/* Tx MAC defines */ ++#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */ ++#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */ ++#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */ ++#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */ ++#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */ ++#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */ ++#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */ ++#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */ ++#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */ ++#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */ ++ ++/* GMII register */ ++#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */ ++#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */ ++#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */ ++ ++/* Tx and Rx XDMA defines */ ++#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */ ++#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */ ++#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */ ++#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */ ++#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */ ++#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */ ++#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */ ++#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */ ++ ++/* AFX (Address Filter Exact) register offsets for Slice 0 */ ++#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/ ++#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/ ++#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */ ++#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */ ++#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */ ++#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */ ++#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */ ++#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */ ++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */ ++ ++/* Traffic Groomer block */ ++#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */ ++ ++#endif /* _TITAN_GE_H_ */ ++ +diff --git a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c +new file mode 100644 +index 0000000..8a8785b +--- /dev/null ++++ b/drivers/net/titan_mdio.c +@@ -0,0 +1,217 @@ ++/* ++ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports ++ * ++ * Copyright (C) 2003 PMC-Sierra Inc. ++ * Author : Manish Lachwani (lachwani@pmc-sierra.com) ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY ++ * on the Titan. No support for the TBI as yet. ++ * ++ */ ++ ++#include "titan_mdio.h" ++ ++#define MDIO_DEBUG ++ ++/* ++ * Local constants ++ */ ++#define MAX_CLKA 1023 ++#define MAX_PHY_DEV 31 ++#define MAX_PHY_REG 31 ++#define WRITEADDRS_OPCODE 0x0 ++#define READ_OPCODE 0x2 ++#define WRITE_OPCODE 0x1 ++#define MAX_MDIO_POLL 100 ++ ++/* ++ * Titan MDIO and SCMB registers ++ */ ++#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */ ++#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */ ++#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */ ++#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */ ++#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */ ++#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */ ++ ++/* ++ * Function to poll the MDIO ++ */ ++static int titan_ge_mdio_poll(void) ++{ ++ int i, val; ++ ++ for (i = 0; i < MAX_MDIO_POLL; i++) { ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ ++ if (!(val & 0x8000)) ++ return TITAN_GE_MDIO_GOOD; ++ } ++ ++ return TITAN_GE_MDIO_ERROR; ++} ++ ++ ++/* ++ * Initialize and configure the MDIO ++ */ ++int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio) ++{ ++ unsigned long val; ++ ++ /* Reset the SCMB and program into MDIO mode*/ ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000); ++ ++ /* CLK A */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA); ++ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val); ++ ++ /* Preamble Suppresion */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ /* MDIO mode */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Set the PHY address in indirect mode ++ */ ++int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr) ++{ ++ volatile unsigned long val; ++ ++ /* Setup the PHY device */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ /* Write the new address */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Read the MDIO register. This is what the individual parametes mean: ++ * ++ * dev_addr : PHY ID ++ * reg_addr : register offset ++ * ++ * See the spec for the Titan MAC. We operate in the Direct Mode. ++ */ ++ ++#define MAX_RETRIES 2 ++ ++int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata) ++{ ++ volatile unsigned long val; ++ int retries = 0; ++ ++ /* Setup the PHY device */ ++ ++again: ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ val |= 0x4000; ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ udelay(30); ++ ++ /* Issue the read command */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ udelay(30); ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA); ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); ++ ++ udelay(30); ++ ++ if (val & 0x2) { ++ if (retries == MAX_RETRIES) ++ return TITAN_GE_MDIO_ERROR; ++ else { ++ retries++; ++ goto again; ++ } ++ } ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ ++/* ++ * Write to the MDIO register ++ * ++ * dev_addr : PHY ID ++ * reg_addr : register that needs to be written to ++ * ++ */ ++int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data) ++{ ++ volatile unsigned long val; ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ /* Setup the PHY device */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS); ++ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00)); ++ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f)); ++ val |= 0x4000; ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val); ++ ++ udelay(30); ++ ++ /* Setup the data to write */ ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data); ++ ++ udelay(30); ++ ++ /* Issue the write command */ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND); ++ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300)); ++ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val); ++ ++ udelay(30); ++ ++ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD) ++ return TITAN_GE_MDIO_ERROR; ++ ++ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS); ++ if (val & 0x2) ++ return TITAN_GE_MDIO_ERROR; ++ ++ return TITAN_GE_MDIO_GOOD; ++} ++ +diff --git a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h +new file mode 100644 +index 0000000..5d23344 +--- /dev/null ++++ b/drivers/net/titan_mdio.h +@@ -0,0 +1,56 @@ ++/* ++ * MDIO used to interact with the PHY when using GMII/MII ++ */ ++#ifndef _TITAN_MDIO_H ++#define _TITAN_MDIO_H ++ ++#include ++#include ++#include ++#include "titan_ge.h" ++ ++ ++#define TITAN_GE_MDIO_ERROR (-9000) ++#define TITAN_GE_MDIO_GOOD 0 ++ ++#define TITAN_GE_MDIO_BASE titan_ge_base ++ ++#define TITAN_GE_MDIO_READ(offset) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) ++ ++#define TITAN_GE_MDIO_WRITE(offset, data) \ ++ *(volatile u32 *)(titan_ge_base + (offset)) = (data) ++ ++ ++/* GMII specific registers */ ++#define TITAN_GE_MARVEL_PHY_ID 0x00 ++#define TITAN_PHY_AUTONEG_ADV 0x04 ++#define TITAN_PHY_LP_ABILITY 0x05 ++#define TITAN_GE_MDIO_MII_CTRL 0x09 ++#define TITAN_GE_MDIO_MII_EXTENDED 0x0f ++#define TITAN_GE_MDIO_PHY_CTRL 0x10 ++#define TITAN_GE_MDIO_PHY_STATUS 0x11 ++#define TITAN_GE_MDIO_PHY_IE 0x12 ++#define TITAN_GE_MDIO_PHY_IS 0x13 ++#define TITAN_GE_MDIO_PHY_LED 0x18 ++#define TITAN_GE_MDIO_PHY_LED_OVER 0x19 ++#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */ ++ ++/* ++ * MDIO Config Structure ++ */ ++typedef struct { ++ unsigned int clka; ++ int mdio_spre; ++ int mdio_mode; ++} titan_ge_mdio_config; ++ ++/* ++ * Function Prototypes ++ */ ++int titan_ge_mdio_setup(titan_ge_mdio_config *); ++int titan_ge_mdio_inaddrs(int, int); ++int titan_ge_mdio_read(int, int, unsigned int *); ++int titan_ge_mdio_write(int, int, unsigned int); ++ ++#endif /* _TITAN_MDIO_H */ +diff --git a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c +index 3411671..4d252c1 100644 +--- a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c ++++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c +@@ -22,6 +22,10 @@ + + static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) + { ++#ifdef CONFIG_LEMOTE_MACH2F ++ /* Allow users to activate rfkill through only the /sys interface */ ++ return 1; ++#else + u8 gpio; + + gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); +@@ -29,6 +33,7 @@ static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) + gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); + + return gpio & priv->rfkill_mask; ++#endif + } + + void rtl8187_rfkill_init(struct ieee80211_hw *hw) +diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig +index 09fde58..eacabd1 100644 +--- a/drivers/platform/Kconfig ++++ b/drivers/platform/Kconfig +@@ -4,5 +4,8 @@ endif + if GOLDFISH + source "drivers/platform/goldfish/Kconfig" + endif ++if MIPS ++source "drivers/platform/mips/Kconfig" ++endif + + source "drivers/platform/chrome/Kconfig" +diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile +index 3656b7b..ca26925 100644 +--- a/drivers/platform/Makefile ++++ b/drivers/platform/Makefile +@@ -3,6 +3,7 @@ + # + + obj-$(CONFIG_X86) += x86/ ++obj-$(CONFIG_MIPS) += mips/ + obj-$(CONFIG_OLPC) += olpc/ + obj-$(CONFIG_GOLDFISH) += goldfish/ + obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ +diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig +new file mode 100644 +index 0000000..722d690 +--- /dev/null ++++ b/drivers/platform/mips/Kconfig +@@ -0,0 +1,60 @@ ++# ++# MIPS Platform Specific Drivers ++# ++ ++menuconfig MIPS_PLATFORM_DEVICES ++ bool "MIPS Platform Specific Device Drivers" ++ default y ++ help ++ Say Y here to get to see options for device drivers of various ++ MIPS platforms, including vendor-specific netbook/laptop/pc extension ++ drivers. This option alone does not add any kernel code. ++ ++ If you say N, all options in this submenu will be skipped and disabled. ++ ++if MIPS_PLATFORM_DEVICES ++ ++config LEMOTE_YEELOONG2F ++ tristate "Lemote YeeLoong Laptop" ++ depends on LEMOTE_MACH2F ++ select BACKLIGHT_LCD_SUPPORT ++ select LCD_CLASS_DEVICE ++ select BACKLIGHT_CLASS_DEVICE ++ select POWER_SUPPLY ++ select HWMON ++ select VIDEO_OUTPUT_CONTROL ++ select INPUT_SPARSEKMAP ++ select INPUT_EVDEV ++ depends on INPUT ++ default m ++ help ++ YeeLoong netbook is a mini laptop made by Lemote, which is basically ++ compatible to FuLoong2F mini PC, but it has an extra Embedded ++ Controller(kb3310b) for battery, hotkey, backlight, temperature and ++ fan management. ++ ++config LEMOTE_LYNLOONG2F ++ tristate "Lemote LynLoong PC" ++ depends on LEMOTE_MACH2F ++ select BACKLIGHT_LCD_SUPPORT ++ select BACKLIGHT_CLASS_DEVICE ++ select VIDEO_OUTPUT_CONTROL ++ default m ++ help ++ LynLoong PC is an AllINONE machine made by Lemote, which is basically ++ compatible to FuLoong2F Mini PC, the only difference is that it has a ++ size-fixed screen: 1360x768 with sisfb video driver. and also, it has ++ its own specific suspend support. ++ ++config GDIUM_LAPTOP ++ tristate "GDIUM laptop extras" ++ depends on DEXXON_GDIUM ++ select POWER_SUPPLY ++ select I2C ++ select INPUT_POLLDEV ++ default m ++ help ++ This mini-driver drives the ST7 chipset present in the Gdium laptops. ++ This gives battery support, wlan rfkill. ++ ++endif # MIPS_PLATFORM_DEVICES +diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile +new file mode 100644 +index 0000000..f013e78 +--- /dev/null ++++ b/drivers/platform/mips/Makefile +@@ -0,0 +1,9 @@ ++# ++# Makefile for MIPS Platform-Specific Drivers ++# ++ ++obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o # yeeloong_ecrom.o ++CFLAGS_yeeloong_laptop.o = -I$(srctree)/arch/mips/loongson/lemote-2f ++ ++obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o ++obj-$(CONFIG_GDIUM_LAPTOP) += gdium_laptop.o +diff --git a/drivers/platform/mips/gdium_laptop.c b/drivers/platform/mips/gdium_laptop.c +new file mode 100644 +index 0000000..41a65ad +--- /dev/null ++++ b/drivers/platform/mips/gdium_laptop.c +@@ -0,0 +1,927 @@ ++/* ++ * gdium_laptop -- Gdium laptop extras ++ * ++ * Arnaud Patard ++ * ++ * 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. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* For input device */ ++#define SCAN_INTERVAL 150 ++ ++/* For battery status */ ++#define BAT_SCAN_INTERVAL 500 ++ ++#define EC_FIRM_VERSION 0 ++ ++#if CONFIG_GDIUM_VERSION > 2 ++#define EC_REG_BASE 1 ++#else ++#define EC_REG_BASE 0 ++#endif ++ ++#define EC_STATUS (EC_REG_BASE+0) ++#define EC_STATUS_LID (1<<0) ++#define EC_STATUS_PWRBUT (1<<1) ++#define EC_STATUS_BATID (1<<2) /* this bit has no real meaning on v2. */ ++ /* Same as EC_STATUS_ADAPT */ ++ /* but on v3 it's BATID which mean bat present */ ++#define EC_STATUS_SYS_POWER (1<<3) ++#define EC_STATUS_WLAN (1<<4) ++#define EC_STATUS_ADAPT (1<<5) ++ ++#define EC_CTRL (EC_REG_BASE+1) ++#define EC_CTRL_DDR_CLK (1<<0) ++#define EC_CTRL_CHARGE_LED (1<<1) ++#define EC_CTRL_BEEP (1<<2) ++#define EC_CTRL_SUSB (1<<3) /* memory power */ ++#define EC_CTRL_TRICKLE (1<<4) ++#define EC_CTRL_WLAN_EN (1<<5) ++#define EC_CTRL_SUSC (1<<6) /* main power */ ++#define EC_CTRL_CHARGE_EN (1<<7) ++ ++#define EC_BAT_LOW (EC_REG_BASE+2) ++#define EC_BAT_HIGH (EC_REG_BASE+3) ++ ++#define EC_SIGN (EC_REG_BASE+4) ++#define EC_SIGN_OS 0xAE /* write 0xae to control pm stuff */ ++#define EC_SIGN_EC 0x00 /* write 0x00 to let the st7 manage pm stuff */ ++ ++#if 0 ++#define EC_TEST (EC_REG_BASE+5) /* Depending on firmware version this register */ ++ /* may be the programmation register so don't play */ ++ /* with it */ ++#endif ++ ++#define BAT_VOLT_PRESENT 500000 /* Min voltage to consider battery present uV */ ++#define BAT_MIN 7000000 /* Min battery voltage in uV */ ++#define BAT_MIN_MV 7000 /* Min battery voltage in mV */ ++#define BAT_TRICKLE_EN 8000000 /* Charging at 1.4A before 8.0V and then charging at 0.25A */ ++#define BAT_MAX 7950000 /* Max battery voltage ~8V in V */ ++#define BAT_MAX_MV 7950 /* Max battery voltage ~8V in V */ ++#define BAT_READ_ERROR 300000 /* battery read error of 0.3V */ ++#define BAT_READ_ERROR_MV 300 /* battery read error of 0.3V */ ++ ++#define SM502_WLAN_ON (224+16)/* SM502 GPIO16 may be used on gdium v2 (v3?) as wlan_on */ ++ /* when R422 is connected */ ++ ++static unsigned char verbose; ++static unsigned char gpio16; ++static unsigned char ec; ++module_param(verbose, byte, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(verbose, "Add some debugging messages"); ++module_param(gpio16, byte, S_IRUGO); ++MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502"); ++module_param(ec, byte, S_IRUGO); ++MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)"); ++ ++struct gdium_laptop_data { ++ struct i2c_client *client; ++ struct input_polled_dev *input_polldev; ++ struct dentry *debugfs; ++ struct mutex mutex; ++ struct platform_device *bat_pdev; ++ struct power_supply gdium_ac; ++ struct power_supply gdium_battery; ++ struct workqueue_struct *workqueue; ++ struct delayed_work work; ++ char charge_cmd; ++ /* important registers value */ ++ char status; ++ char ctrl; ++ /* mV */ ++ int battery_level; ++ char version; ++}; ++ ++/**********************************************************************/ ++/* Low level I2C functions */ ++/* All are supposed to be called with mutex held */ ++/**********************************************************************/ ++/* ++ * Return battery voltage in mV ++ * >= 0 battery voltage ++ * < 0 error ++ */ ++static s32 ec_read_battery(struct i2c_client *client) ++{ ++ unsigned char bat_low, bat_high; ++ s32 data; ++ unsigned int ret; ++ ++ /* ++ * a = battery high ++ * b = battery low ++ * bat = a << 2 | b & 0x03; ++ * battery voltage = (bat / 1024) * 5 * 2 ++ */ ++ data = i2c_smbus_read_byte_data(client, EC_BAT_LOW); ++ if (data < 0) { ++ dev_err(&client->dev, "ec_read_bat: read bat_low failed\n"); ++ return data; ++ } ++ bat_low = data & 0xff; ++ if (verbose) ++ dev_info(&client->dev, "bat_low %x\n", bat_low); ++ ++ data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH); ++ if (data < 0) { ++ dev_err(&client->dev, "ec_read_bat: read bat_high failed\n"); ++ return data; ++ } ++ bat_high = data & 0xff; ++ if (verbose) ++ dev_info(&client->dev, "bat_high %x\n", bat_high); ++ ++ ret = (bat_high << 2) | (bat_low & 3); ++ /* ++ * mV ++ */ ++ ret = (ret * 5 * 2) * 1000 / 1024; ++ ++ return ret; ++} ++ ++static s32 ec_read_version(struct i2c_client *client) ++{ ++#if CONFIG_GDIUM_VERSION > 2 ++ return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION); ++#else ++ return 0; ++#endif ++} ++ ++static s32 ec_read_status(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_STATUS); ++} ++ ++static s32 ec_read_ctrl(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_CTRL); ++} ++ ++static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue) ++{ ++ return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue); ++} ++ ++static s32 ec_read_sign(struct i2c_client *client) ++{ ++ return i2c_smbus_read_byte_data(client, EC_SIGN); ++} ++ ++static s32 ec_write_sign(struct i2c_client *client, unsigned char sign) ++{ ++ unsigned char value; ++ s32 ret; ++ ++ ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign); ++ if (ret < 0) { ++ dev_err(&client->dev, "ec_set_control: write failed\n"); ++ return ret; ++ } ++ ++ value = ec_read_sign(client); ++ if (value != sign) { ++ dev_err(&client->dev, "Failed to set control to %s\n", ++ sign == EC_SIGN_OS ? "OS" : "EC"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++#if 0 ++static int ec_power_off(struct i2c_client *client) ++{ ++ char value; ++ int ret; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) { ++ dev_err(&client->dev, "ec_power_off: read failed\n"); ++ return value; ++ } ++ value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC); ++ ret = ec_write_ctrl(client, value); ++ if (ret < 0) { ++ dev_err(&client->dev, "ec_power_off: write failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++static s32 ec_wlan_status(struct i2c_client *client) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ return (value & EC_CTRL_WLAN_EN) ? 1 : 0; ++} ++ ++static s32 ec_wlan_en(struct i2c_client *client, int on) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ value &= ~EC_CTRL_WLAN_EN; ++ if (on) ++ value |= EC_CTRL_WLAN_EN; ++ ++ return ec_write_ctrl(client, value&0xff); ++} ++ ++#if 0 ++static s32 ec_led_status(struct i2c_client *client) ++{ ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ return (value & EC_CTRL_CHARGE_LED) ? 1 : 0; ++} ++#endif ++ ++/* Changing the charging led status has never worked */ ++static s32 ec_led_en(struct i2c_client *client, int on) ++{ ++#if 0 ++ s32 value; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ value &= ~EC_CTRL_CHARGE_LED; ++ if (on) ++ value |= EC_CTRL_CHARGE_LED; ++ return ec_write_ctrl(client, value&0xff); ++#else ++ return 0; ++#endif ++} ++ ++static s32 ec_charge_en(struct i2c_client *client, int on, int trickle) ++{ ++ s32 value; ++ s32 set = 0; ++ ++ value = ec_read_ctrl(client); ++ if (value < 0) ++ return value; ++ ++ if (on) ++ set |= EC_CTRL_CHARGE_EN; ++ if (trickle) ++ set |= EC_CTRL_TRICKLE; ++ ++ /* Be clever : don't change values if you don't need to */ ++ if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set) ++ return 0; ++ ++ value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE); ++ value |= set; ++ ec_led_en(client, on); ++ return ec_write_ctrl(client, (unsigned char)(value&0xff)); ++ ++} ++ ++/**********************************************************************/ ++/* Input functions */ ++/**********************************************************************/ ++struct gdium_keys { ++ int last_state; ++ int key_code; ++ int mask; ++ int type; ++}; ++ ++static struct gdium_keys gkeys[] = { ++ { ++ .key_code = KEY_WLAN, ++ .mask = EC_STATUS_WLAN, ++ .type = EV_KEY, ++ }, ++ { ++ .key_code = KEY_POWER, ++ .mask = EC_STATUS_PWRBUT, ++ .type = EV_KEY, /*EV_PWR,*/ ++ }, ++ { ++ .key_code = SW_LID, ++ .mask = EC_STATUS_LID, ++ .type = EV_SW, ++ }, ++}; ++ ++static void gdium_laptop_keys_poll(struct input_polled_dev *dev) ++{ ++ int state, i; ++ struct gdium_laptop_data *data = dev->private; ++ struct i2c_client *client = data->client; ++ struct input_dev *input = dev->input; ++ s32 status; ++ ++ mutex_lock(&data->mutex); ++ status = ec_read_status(client); ++ mutex_unlock(&data->mutex); ++ ++ if (status < 0) { ++ /* ++ * Don't know exactly which version of the firmware ++ * has this bug but when the power button is pressed ++ * there are i2c read errors :( ++ */ ++ if ((data->version >= 0x13) && !gkeys[1].last_state) { ++ input_event(input, EV_KEY, KEY_POWER, 1); ++ input_sync(input); ++ gkeys[1].last_state = 1; ++ } ++ return; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(gkeys); i++) { ++ state = status & gkeys[i].mask; ++ if (state != gkeys[i].last_state) { ++ gkeys[i].last_state = state; ++ /* for power key, we want power & key press/release event */ ++ if (gkeys[i].type == EV_PWR) { ++ input_event(input, EV_KEY, gkeys[i].key_code, !!state); ++ input_sync(input); ++ } ++ /* Disable wifi on key press but not key release */ ++ /* ++ * On firmware >= 0x13 the EC_STATUS_WLAN has it's ++ * original meaning of Wifi status and no more the ++ * wifi button status so we have to ignore the event ++ * on theses versions ++ */ ++ if (state && (gkeys[i].key_code == KEY_WLAN) && (data->version < 0x13)) { ++ mutex_lock(&data->mutex); ++ ec_wlan_en(client, !ec_wlan_status(client)); ++ if (gpio16) ++ gpio_set_value(SM502_WLAN_ON, !ec_wlan_status(client)); ++ mutex_unlock(&data->mutex); ++ } ++ ++ input_event(input, gkeys[i].type, gkeys[i].key_code, !!state); ++ input_sync(input); ++ } ++ } ++} ++ ++static int gdium_laptop_input_init(struct gdium_laptop_data *data) ++{ ++ struct i2c_client *client = data->client; ++ struct input_dev *input; ++ int ret, i; ++ ++ data->input_polldev = input_allocate_polled_device(); ++ if (!data->input_polldev) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ input = data->input_polldev->input; ++ input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW); ++ data->input_polldev->poll = gdium_laptop_keys_poll; ++ data->input_polldev->poll_interval = SCAN_INTERVAL; ++ data->input_polldev->private = data; ++ input->name = "gdium-keys"; ++ input->dev.parent = &client->dev; ++ ++ input->id.bustype = BUS_HOST; ++ input->id.vendor = 0x0001; ++ input->id.product = 0x0001; ++ input->id.version = 0x0100; ++ ++ for (i = 0; i < ARRAY_SIZE(gkeys); i++) ++ input_set_capability(input, gkeys[i].type, gkeys[i].key_code); ++ ++ ret = input_register_polled_device(data->input_polldev); ++ if (ret) { ++ dev_err(&client->dev, "Unable to register button device\n"); ++ goto err_poll_dev; ++ } ++ ++ return 0; ++ ++err_poll_dev: ++ input_free_polled_device(data->input_polldev); ++err: ++ return ret; ++} ++ ++static void gdium_laptop_input_exit(struct gdium_laptop_data *data) ++{ ++ input_unregister_polled_device(data->input_polldev); ++ input_free_polled_device(data->input_polldev); ++} ++ ++/**********************************************************************/ ++/* Battery management */ ++/**********************************************************************/ ++static int gdium_ac_get_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ char status; ++ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_ac); ++ int ret = 0; ++ ++ if (!data) { ++ pr_err("gdium-ac: gdium_laptop_data not found\n"); ++ return -EINVAL; ++ } ++ ++ status = data->status; ++ switch (psp) { ++ case POWER_SUPPLY_PROP_ONLINE: ++ val->intval = !!(status & EC_STATUS_ADAPT); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#undef RET ++#define RET (val->intval) ++ ++static int gdium_battery_get_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ char status, ctrl; ++ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_battery); ++ int percentage_capacity = 0, charge_now = 0, time_to_empty = 0; ++ int ret = 0, tmp; ++ ++ if (!data) { ++ pr_err("gdium-battery: gdium_laptop_data not found\n"); ++ return -EINVAL; ++ } ++ ++ status = data->status; ++ ctrl = data->ctrl; ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ++ /* uAh */ ++ RET = 5000000; ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ++ /* This formula is gotten by gnuplot with the statistic data */ ++ time_to_empty = (data->battery_level - BAT_MIN_MV + BAT_READ_ERROR_MV) * 113 - 29870; ++ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) { ++ /* seconds */ ++ RET = time_to_empty / 10; ++ break; ++ } ++ /* fall through */ ++ case POWER_SUPPLY_PROP_CHARGE_NOW: ++ case POWER_SUPPLY_PROP_CAPACITY: { ++ tmp = data->battery_level * 1000; ++ /* > BAT_MIN to avoid negative values */ ++ percentage_capacity = 0; ++ if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN)) ++ percentage_capacity = (tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN); ++ ++ if (percentage_capacity > 100) ++ percentage_capacity = 100; ++ ++ if (psp == POWER_SUPPLY_PROP_CAPACITY) { ++ RET = percentage_capacity; ++ break; ++ } ++ charge_now = 50000 * percentage_capacity; ++ if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) { ++ /* uAh */ ++ RET = charge_now; ++ break; ++ } ++ } /* fall through */ ++ case POWER_SUPPLY_PROP_STATUS: { ++ if (status & EC_STATUS_ADAPT) ++ if (ctrl & EC_CTRL_CHARGE_EN) ++ RET = POWER_SUPPLY_STATUS_CHARGING; ++ else ++ RET = POWER_SUPPLY_STATUS_NOT_CHARGING; ++ else ++ RET = POWER_SUPPLY_STATUS_DISCHARGING; ++ ++ if (psp == POWER_SUPPLY_PROP_STATUS) ++ break; ++ /* mAh -> µA */ ++ switch (RET) { ++ case POWER_SUPPLY_STATUS_CHARGING: ++ RET = -(data->charge_cmd == 2) ? 1400000 : 250000; ++ break; ++ case POWER_SUPPLY_STATUS_DISCHARGING: ++ RET = charge_now / time_to_empty * 36000; ++ break; ++ case POWER_SUPPLY_STATUS_NOT_CHARGING: ++ default: ++ RET = 0; ++ break; ++ } ++ } break; ++ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: ++ RET = BAT_MAX+BAT_READ_ERROR; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: ++ RET = BAT_MIN-BAT_READ_ERROR; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ /* mV -> uV */ ++ RET = data->battery_level * 1000; ++ break; ++ case POWER_SUPPLY_PROP_PRESENT: ++#if CONFIG_GDIUM_VERSION > 2 ++ RET = !!(status & EC_STATUS_BATID); ++#else ++ RET = !!(data->battery_level > BAT_VOLT_PRESENT); ++#endif ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: ++ tmp = data->battery_level * 1000; ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ if (status & EC_STATUS_BATID) { ++ if (tmp >= BAT_MAX) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; ++ if (tmp >= BAT_MAX+BAT_READ_ERROR) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; ++ } else if (tmp <= BAT_MIN+BAT_READ_ERROR) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; ++ if (tmp <= BAT_MIN) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; ++ } else ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; ++ } ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_TYPE: ++ if (ctrl & EC_CTRL_TRICKLE) ++ RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; ++ else if (ctrl & EC_CTRL_CHARGE_EN) ++ RET = POWER_SUPPLY_CHARGE_TYPE_FAST; ++ else ++ RET = POWER_SUPPLY_CHARGE_TYPE_NONE; ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_MAX: ++ /* 1.4A ? */ ++ RET = 1400000; ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++#undef RET ++ ++static enum power_supply_property gdium_ac_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++}; ++ ++static enum power_supply_property gdium_battery_props[] = { ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_NOW, ++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, ++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_CURRENT_MAX, ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_CAPACITY_LEVEL, ++ POWER_SUPPLY_PROP_CHARGE_TYPE, ++}; ++ ++static void gdium_laptop_battery_work(struct work_struct *work) ++{ ++ struct gdium_laptop_data *data = container_of(work, struct gdium_laptop_data, work.work); ++ struct i2c_client *client; ++ int ret; ++ char old_status, old_charge_cmd; ++ char present; ++ s32 status; ++ ++ mutex_lock(&data->mutex); ++ client = data->client; ++ status = ec_read_status(client); ++ ret = ec_read_battery(client); ++ ++ if ((status < 0) || (ret < 0)) ++ goto i2c_read_error; ++ ++ old_status = data->status; ++ old_charge_cmd = data->charge_cmd; ++ data->status = status; ++ ++ /* ++ * Charge only if : ++ * - battery present ++ * - ac adapter plugged in ++ * - battery not fully charged ++ */ ++#if CONFIG_GDIUM_VERSION > 2 ++ present = !!(data->status & EC_STATUS_BATID); ++#else ++ present = !!(ret > BAT_VOLT_PRESENT); ++#endif ++ data->battery_level = 0; ++ if (present) { ++ data->battery_level = (unsigned int)ret; ++ if (data->status & EC_STATUS_ADAPT) ++ data->battery_level -= BAT_READ_ERROR_MV; ++ } ++ ++ data->charge_cmd = 0; ++ if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level <= BAT_MAX_MV)) ++ data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3; ++ ++ ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1); ++ ++ /* ++ * data->ctrl must be set _after_ calling ec_charge_en as this will change the ++ * control register content ++ */ ++ data->ctrl = ec_read_ctrl(client); ++ ++ if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) { ++ power_supply_changed(&data->gdium_ac); ++ /* Send charging/discharging state change */ ++ power_supply_changed(&data->gdium_battery); ++ } else if ((data->status & EC_STATUS_ADAPT) && ++ ((old_charge_cmd&2) != (data->charge_cmd&2))) ++ power_supply_changed(&data->gdium_battery); ++ ++i2c_read_error: ++ mutex_unlock(&data->mutex); ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++} ++ ++static int gdium_laptop_battery_init(struct gdium_laptop_data *data) ++{ ++ int ret; ++ ++ data->bat_pdev = platform_device_register_simple("gdium-battery", 0, NULL, 0); ++ if (IS_ERR(data->bat_pdev)) ++ return PTR_ERR(data->bat_pdev); ++ ++ data->gdium_battery.name = data->bat_pdev->name; ++ data->gdium_battery.properties = gdium_battery_props; ++ data->gdium_battery.num_properties = ARRAY_SIZE(gdium_battery_props); ++ data->gdium_battery.get_property = gdium_battery_get_props; ++ data->gdium_battery.use_for_apm = 1; ++ ++ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery); ++ if (ret) ++ goto err_platform; ++ ++ data->gdium_ac.name = "gdium-ac"; ++ data->gdium_ac.type = POWER_SUPPLY_TYPE_MAINS; ++ data->gdium_ac.properties = gdium_ac_props; ++ data->gdium_ac.num_properties = ARRAY_SIZE(gdium_ac_props); ++ data->gdium_ac.get_property = gdium_ac_get_props; ++/* data->gdium_ac.use_for_apm_ac = 1, */ ++ ++ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac); ++ if (ret) ++ goto err_battery; ++ ++ if (!ec) { ++ INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work); ++ data->workqueue = create_singlethread_workqueue("gdium-battery-work"); ++ if (!data->workqueue) { ++ ret = -ESRCH; ++ goto err_work; ++ } ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++ } ++ ++ return 0; ++ ++err_work: ++err_battery: ++ power_supply_unregister(&data->gdium_battery); ++err_platform: ++ platform_device_unregister(data->bat_pdev); ++ ++ return ret; ++} ++static void gdium_laptop_battery_exit(struct gdium_laptop_data *data) ++{ ++ if (!ec) { ++ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); ++ destroy_workqueue(data->workqueue); ++ } ++ power_supply_unregister(&data->gdium_battery); ++ power_supply_unregister(&data->gdium_ac); ++ platform_device_unregister(data->bat_pdev); ++} ++ ++/* Debug fs */ ++static int gdium_laptop_regs_show(struct seq_file *s, void *p) ++{ ++ struct gdium_laptop_data *data = s->private; ++ struct i2c_client *client = data->client; ++ ++ mutex_lock(&data->mutex); ++ seq_printf(s, "Version : 0x%02x\n", (unsigned char)ec_read_version(client)); ++ seq_printf(s, "Status : 0x%02x\n", (unsigned char)ec_read_status(client)); ++ seq_printf(s, "Ctrl : 0x%02x\n", (unsigned char)ec_read_ctrl(client)); ++ seq_printf(s, "Sign : 0x%02x\n", (unsigned char)ec_read_sign(client)); ++ seq_printf(s, "Bat Lo : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_LOW)); ++ seq_printf(s, "Bat Hi : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH)); ++ seq_printf(s, "Battery : %d uV\n", (unsigned int)ec_read_battery(client) * 1000); ++ seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", data->charge_cmd & 1 ? "T" : " "); ++ ++ mutex_unlock(&data->mutex); ++ return 0; ++} ++ ++static int gdium_laptop_regs_open(struct inode *inode, ++ struct file *file) ++{ ++ return single_open(file, gdium_laptop_regs_show, inode->i_private); ++} ++ ++static const struct file_operations gdium_laptop_regs_fops = { ++ .open = gdium_laptop_regs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++ ++static int gdium_laptop_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ struct gdium_laptop_data *data; ++ int ret; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&client->dev, ++ "%s: no smbus_byte support !\n", __func__); ++ return -ENODEV; ++ } ++ ++ data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(client, data); ++ data->client = client; ++ mutex_init(&data->mutex); ++ ++ ret = ec_read_version(client); ++ if (ret < 0) ++ goto err_alloc; ++ ++ data->version = (unsigned char)ret; ++ ++ ret = gdium_laptop_input_init(data); ++ if (ret) ++ goto err_alloc; ++ ++ ret = gdium_laptop_battery_init(data); ++ if (ret) ++ goto err_input; ++ ++ ++ if (!ec) { ++ ret = ec_write_sign(client, EC_SIGN_OS); ++ if (ret) ++ goto err_sign; ++ } ++ ++ if (gpio16) { ++ ret = gpio_request(SM502_WLAN_ON, "wlan-on"); ++ if (ret < 0) ++ goto err_sign; ++ gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client)); ++ gpio_direction_output(SM502_WLAN_ON, 1); ++ } ++ ++ dev_info(&client->dev, "Found firmware 0x%02x\n", data->version); ++ data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO, ++ NULL, data, &gdium_laptop_regs_fops); ++ ++ return 0; ++ ++err_sign: ++ gdium_laptop_battery_exit(data); ++err_input: ++ gdium_laptop_input_exit(data); ++err_alloc: ++ kfree(data); ++ return ret; ++} ++ ++static int gdium_laptop_remove(struct i2c_client *client) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (gpio16) ++ gpio_free(SM502_WLAN_ON); ++ ec_write_sign(client, EC_SIGN_EC); ++ if (data->debugfs) ++ debugfs_remove(data->debugfs); ++ ++ gdium_laptop_battery_exit(data); ++ gdium_laptop_input_exit(data); ++ ++ kfree(data); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (!ec) ++ cancel_rearming_delayed_workqueue(data->workqueue, &data->work); ++ return 0; ++} ++ ++static int gdium_laptop_resume(struct i2c_client *client) ++{ ++ struct gdium_laptop_data *data = i2c_get_clientdata(client); ++ ++ if (!ec) ++ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL)); ++ return 0; ++} ++#else ++#define gdium_laptop_suspend NULL ++#define gdium_laptop_resume NULL ++#endif ++static const struct i2c_device_id gdium_id[] = { ++ { "gdium-laptop" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(i2c, gdium_id); ++ ++static struct i2c_driver gdium_laptop_driver = { ++ .driver = { ++ .name = "gdium-laptop", ++ .owner = THIS_MODULE, ++ }, ++ .probe = gdium_laptop_probe, ++ .remove = gdium_laptop_remove, ++ .shutdown = gdium_laptop_remove, ++ .suspend = gdium_laptop_suspend, ++ .resume = gdium_laptop_resume, ++ .id_table = gdium_id, ++}; ++ ++static int __init gdium_laptop_init(void) ++{ ++ return i2c_add_driver(&gdium_laptop_driver); ++} ++ ++static void __exit gdium_laptop_exit(void) ++{ ++ i2c_del_driver(&gdium_laptop_driver); ++} ++ ++module_init(gdium_laptop_init); ++module_exit(gdium_laptop_exit); ++ ++MODULE_AUTHOR("Arnaud Patard "); ++MODULE_DESCRIPTION("Gdium laptop extras"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/lynloong_pc.c b/drivers/platform/mips/lynloong_pc.c +new file mode 100644 +index 0000000..68f29e4 +--- /dev/null ++++ b/drivers/platform/mips/lynloong_pc.c +@@ -0,0 +1,515 @@ ++/* ++ * Driver for LynLoong PC extras ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin , Xiang Yu ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include /* for backlight subdriver */ ++#include ++#include /* for video output subdriver */ ++#include /* for suspend support */ ++ ++#include ++#include ++ ++#include ++ ++static u32 gpio_base, mfgpt_base; ++ ++static void set_gpio_reg_high(int gpio, int reg) ++{ ++ u32 val; ++ ++ val = inl(gpio_base + reg); ++ val |= (1 << gpio); ++ val &= ~(1 << (16 + gpio)); ++ outl(val, gpio_base + reg); ++ mmiowb(); ++} ++ ++static void set_gpio_reg_low(int gpio, int reg) ++{ ++ u32 val; ++ ++ val = inl(gpio_base + reg); ++ val |= (1 << (16 + gpio)); ++ val &= ~(1 << gpio); ++ outl(val, gpio_base + reg); ++ mmiowb(); ++} ++ ++static void set_gpio_output_low(int gpio) ++{ ++ set_gpio_reg_high(gpio, GPIOL_OUT_EN); ++ set_gpio_reg_low(gpio, GPIOL_OUT_VAL); ++} ++ ++static void set_gpio_output_high(int gpio) ++{ ++ set_gpio_reg_high(gpio, GPIOL_OUT_EN); ++ set_gpio_reg_high(gpio, GPIOL_OUT_VAL); ++} ++ ++/* backlight subdriver */ ++ ++#define MAX_BRIGHTNESS 100 ++#define DEFAULT_BRIGHTNESS 50 ++#define MIN_BRIGHTNESS 0 ++static unsigned int level; ++ ++DEFINE_SPINLOCK(backlight_lock); ++/* Tune the brightness */ ++static void setup_mfgpt2(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&backlight_lock, flags); ++ ++ /* Set MFGPT2 comparator 1,2 */ ++ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1); ++ outw(MAX_BRIGHTNESS, MFGPT2_CMP2); ++ /* Clear MFGPT2 UP COUNTER */ ++ outw(0, MFGPT2_CNT); ++ /* Enable counter, compare mode, 32k */ ++ outw(0x8280, MFGPT2_SETUP); ++ ++ spin_unlock_irqrestore(&backlight_lock, flags); ++} ++ ++static int lynloong_set_brightness(struct backlight_device *bd) ++{ ++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && ++ bd->props.power == FB_BLANK_UNBLANK) ? ++ bd->props.brightness : 0; ++ ++ if (level > MAX_BRIGHTNESS) ++ level = MAX_BRIGHTNESS; ++ else if (level < MIN_BRIGHTNESS) ++ level = MIN_BRIGHTNESS; ++ ++ setup_mfgpt2(); ++ ++ return 0; ++} ++ ++static int lynloong_get_brightness(struct backlight_device *bd) ++{ ++ return level; ++} ++ ++static struct backlight_ops backlight_ops = { ++ .get_brightness = lynloong_get_brightness, ++ .update_status = lynloong_set_brightness, ++}; ++ ++static struct backlight_device *lynloong_backlight_dev; ++ ++static int lynloong_backlight_init(void) ++{ ++ int ret; ++ u32 hi; ++ struct backlight_properties props; ++ ++ /* Get gpio_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); ++ /* Get mfgpt_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base); ++ /* Get gpio_base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base); ++ ++ /* Select for mfgpt */ ++ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL); ++ /* Enable brightness controlling */ ++ set_gpio_output_high(7); ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.max_brightness = MAX_BRIGHTNESS; ++ props.type = BACKLIGHT_PLATFORM; ++ lynloong_backlight_dev = backlight_device_register("backlight0", NULL, ++ NULL, &backlight_ops, &props); ++ ++ if (IS_ERR(lynloong_backlight_dev)) { ++ ret = PTR_ERR(lynloong_backlight_dev); ++ return ret; ++ } ++ ++ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS; ++ backlight_update_status(lynloong_backlight_dev); ++ ++ return 0; ++} ++ ++static void lynloong_backlight_exit(void) ++{ ++ if (lynloong_backlight_dev) { ++ backlight_device_unregister(lynloong_backlight_dev); ++ lynloong_backlight_dev = NULL; ++ } ++ /* Disable brightness controlling */ ++ set_gpio_output_low(7); ++} ++ ++/* video output driver */ ++static int vo_status = 1; ++ ++static int lcd_video_output_get(struct output_device *od) ++{ ++ return vo_status; ++} ++ ++static int lcd_video_output_set(struct output_device *od) ++{ ++ int i; ++ unsigned long status; ++ ++ status = !!od->request_state; ++ ++ if (status == 0) { ++ /* Set the current status as off */ ++ vo_status = 0; ++ /* Turn off the backlight */ ++ set_gpio_output_low(11); ++ for (i = 0; i < 0x500; i++) ++ delay(); ++ /* Turn off the LCD */ ++ set_gpio_output_high(8); ++ } else { ++ /* Turn on the LCD */ ++ set_gpio_output_low(8); ++ for (i = 0; i < 0x500; i++) ++ delay(); ++ /* Turn on the backlight */ ++ set_gpio_output_high(11); ++ /* Set the current status as on */ ++ vo_status = 1; ++ } ++ ++ return 0; ++} ++ ++static struct output_properties lcd_output_properties = { ++ .set_state = lcd_video_output_set, ++ .get_status = lcd_video_output_get, ++}; ++ ++static struct output_device *lcd_output_dev; ++ ++static void lynloong_lcd_vo_set(int status) ++{ ++ lcd_output_dev->request_state = status; ++ lcd_video_output_set(lcd_output_dev); ++} ++ ++static int lynloong_vo_init(void) ++{ ++ int ret; ++ ++ /* Register video output device: lcd */ ++ lcd_output_dev = video_output_register("LCD", NULL, NULL, ++ &lcd_output_properties); ++ ++ if (IS_ERR(lcd_output_dev)) { ++ ret = PTR_ERR(lcd_output_dev); ++ lcd_output_dev = NULL; ++ return ret; ++ } ++ /* Ensure LCD is on by default */ ++ lynloong_lcd_vo_set(1); ++ ++ return 0; ++} ++ ++static void lynloong_vo_exit(void) ++{ ++ if (lcd_output_dev) { ++ video_output_unregister(lcd_output_dev); ++ lcd_output_dev = NULL; ++ } ++} ++ ++/* suspend support */ ++ ++#ifdef CONFIG_PM ++ ++static u32 smb_base; ++ ++/* I2C operations */ ++ ++static int i2c_wait(void) ++{ ++ char c; ++ int i; ++ ++ udelay(1000); ++ for (i = 0; i < 20; i++) { ++ c = inb(smb_base | SMB_STS); ++ if (c & (SMB_STS_BER | SMB_STS_NEGACK)) ++ return -1; ++ if (c & SMB_STS_SDAST) ++ return 0; ++ udelay(100); ++ } ++ return -2; ++} ++ ++static void i2c_read_single(int addr, int regNo, char *value) ++{ ++ unsigned char c; ++ ++ /* Start condition */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ ++ /* Send slave address */ ++ outb(addr & 0xfe, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Send register index */ ++ outb(regNo, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Start condition again */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ ++ /* Send salve address again */ ++ outb(1 | addr, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Acknowledge smbus */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1); ++ ++ /* Read data */ ++ *value = inb(smb_base | SMB_SDA); ++ ++ /* Stop condition */ ++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); ++ i2c_wait(); ++} ++ ++static void i2c_write_single(int addr, int regNo, char value) ++{ ++ unsigned char c; ++ ++ /* Start condition */ ++ c = inb(smb_base | SMB_CTRL1); ++ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1); ++ i2c_wait(); ++ /* Send slave address */ ++ outb(addr & 0xfe, smb_base | SMB_SDA); ++ i2c_wait();; ++ ++ /* Send register index */ ++ outb(regNo, smb_base | SMB_SDA); ++ i2c_wait(); ++ ++ /* Write data */ ++ outb(value, smb_base | SMB_SDA); ++ i2c_wait(); ++ /* Stop condition */ ++ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1); ++ i2c_wait(); ++} ++ ++static void stop_clock(int clk_reg, int clk_sel) ++{ ++ u8 value; ++ ++ i2c_read_single(0xd3, clk_reg, &value); ++ value &= ~(1 << clk_sel); ++ i2c_write_single(0xd2, clk_reg, value); ++} ++ ++static void enable_clock(int clk_reg, int clk_sel) ++{ ++ u8 value; ++ ++ i2c_read_single(0xd3, clk_reg, &value); ++ value |= (1 << clk_sel); ++ i2c_write_single(0xd2, clk_reg, value); ++} ++ ++static char cached_clk_freq; ++static char cached_pci_fixed_freq; ++ ++static void decrease_clk_freq(void) ++{ ++ char value; ++ ++ i2c_read_single(0xd3, 1, &value); ++ cached_clk_freq = value; ++ ++ /* Select frequency by software */ ++ value |= (1 << 1); ++ /* CPU, 3V66, PCI : 100, 66, 33(1) */ ++ value |= (1 << 2); ++ i2c_write_single(0xd2, 1, value); ++ ++ /* Cache the pci frequency */ ++ i2c_read_single(0xd3, 14, &value); ++ cached_pci_fixed_freq = value; ++ ++ /* Enable PCI fix mode */ ++ value |= (1 << 5); ++ /* 3V66, PCI : 64MHz, 32MHz */ ++ value |= (1 << 3); ++ i2c_write_single(0xd2, 14, value); ++ ++} ++ ++static void resume_clk_freq(void) ++{ ++ i2c_write_single(0xd2, 1, cached_clk_freq); ++ i2c_write_single(0xd2, 14, cached_pci_fixed_freq); ++} ++ ++static void stop_clocks(void) ++{ ++ /* CPU Clock Register */ ++ stop_clock(2, 5); /* not used */ ++ stop_clock(2, 6); /* not used */ ++ stop_clock(2, 7); /* not used */ ++ ++ /* PCI Clock Register */ ++ stop_clock(3, 1); /* 8100 */ ++ stop_clock(3, 5); /* SIS */ ++ stop_clock(3, 0); /* not used */ ++ stop_clock(3, 6); /* not used */ ++ ++ /* PCI 48M Clock Register */ ++ stop_clock(4, 6); /* USB grounding */ ++ stop_clock(4, 5); /* REF(5536_14M) */ ++ ++ /* 3V66 Control Register */ ++ stop_clock(5, 0); /* VCH_CLK..., grounding */ ++} ++ ++static void enable_clocks(void) ++{ ++ enable_clock(3, 1); /* 8100 */ ++ enable_clock(3, 5); /* SIS */ ++ ++ enable_clock(4, 6); ++ enable_clock(4, 5); /* REF(5536_14M) */ ++ ++ enable_clock(5, 0); /* VCH_CLOCK, grounding */ ++} ++ ++static int lynloong_suspend(struct device *dev) ++{ ++ /* Disable AMP */ ++ set_gpio_output_high(6); ++ /* Turn off LCD */ ++ lynloong_lcd_vo_set(0); ++ ++ /* Stop the clocks of some devices */ ++ stop_clocks(); ++ ++ /* Decrease the external clock frequency */ ++ decrease_clk_freq(); ++ ++ return 0; ++} ++ ++static int lynloong_resume(struct device *dev) ++{ ++ /* Turn on the LCD */ ++ lynloong_lcd_vo_set(1); ++ ++ /* Resume clock frequency, enable the relative clocks */ ++ resume_clk_freq(); ++ enable_clocks(); ++ ++ /* Enable AMP */ ++ set_gpio_output_low(6); ++ ++ return 0; ++} ++ ++static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend, ++ lynloong_resume); ++#endif /* !CONFIG_PM */ ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "lynloong_pc", ++ }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "lynloong_pc", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &lynloong_pm_ops, ++#endif ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int __init lynloong_init(void) ++{ ++ int ret; ++ ++ pr_info("LynLoong platform specific driver loaded.\n"); ++ ++ /* Register platform stuff */ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) { ++ pr_err("Failed to register LynLoong platform driver.\n"); ++ return ret; ++ } ++ ++ ret = lynloong_backlight_init(); ++ if (ret) { ++ pr_err("Failed to register LynLoong backlight driver.\n"); ++ return ret; ++ } ++ ++ ret = lynloong_vo_init(); ++ if (ret) { ++ pr_err("Failed to register LynLoong backlight driver.\n"); ++ lynloong_vo_exit(); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit lynloong_exit(void) ++{ ++ lynloong_vo_exit(); ++ lynloong_backlight_exit(); ++ platform_driver_unregister(&platform_driver); ++ ++ pr_info("LynLoong platform specific driver unloaded.\n"); ++} ++ ++module_init(lynloong_init); ++module_exit(lynloong_exit); ++ ++MODULE_AUTHOR("Wu Zhangjin ; Xiang Yu "); ++MODULE_DESCRIPTION("LynLoong PC driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/yeeloong_ecrom.c b/drivers/platform/mips/yeeloong_ecrom.c +new file mode 100644 +index 0000000..1bfe4cf +--- /dev/null ++++ b/drivers/platform/mips/yeeloong_ecrom.c +@@ -0,0 +1,944 @@ ++/* ++ * Driver for flushing/dumping ROM of EC on YeeLoong laptop ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: liujl ++ * ++ * NOTE : ++ * The EC resources accessing and programming are supported. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define EC_MISC_DEV "ec_misc" ++#define EC_IOC_MAGIC 'E' ++ ++/* ec registers range */ ++#define EC_MAX_REGADDR 0xFFFF ++#define EC_MIN_REGADDR 0xF000 ++#define EC_RAM_ADDR 0xF800 ++ ++/* version burned address */ ++#define VER_ADDR 0xf7a1 ++#define VER_MAX_SIZE 7 ++#define EC_ROM_MAX_SIZE 0x10000 ++ ++/* ec internal register */ ++#define REG_POWER_MODE 0xF710 ++#define FLAG_NORMAL_MODE 0x00 ++#define FLAG_IDLE_MODE 0x01 ++#define FLAG_RESET_MODE 0x02 ++ ++/* ec update program flag */ ++#define PROGRAM_FLAG_NONE 0x00 ++#define PROGRAM_FLAG_IE 0x01 ++#define PROGRAM_FLAG_ROM 0x02 ++ ++/* XBI relative registers */ ++#define REG_XBISEG0 0xFEA0 ++#define REG_XBISEG1 0xFEA1 ++#define REG_XBIRSV2 0xFEA2 ++#define REG_XBIRSV3 0xFEA3 ++#define REG_XBIRSV4 0xFEA4 ++#define REG_XBICFG 0xFEA5 ++#define REG_XBICS 0xFEA6 ++#define REG_XBIWE 0xFEA7 ++#define REG_XBISPIA0 0xFEA8 ++#define REG_XBISPIA1 0xFEA9 ++#define REG_XBISPIA2 0xFEAA ++#define REG_XBISPIDAT 0xFEAB ++#define REG_XBISPICMD 0xFEAC ++#define REG_XBISPICFG 0xFEAD ++#define REG_XBISPIDATR 0xFEAE ++#define REG_XBISPICFG2 0xFEAF ++ ++/* commands definition for REG_XBISPICMD */ ++#define SPICMD_WRITE_STATUS 0x01 ++#define SPICMD_BYTE_PROGRAM 0x02 ++#define SPICMD_READ_BYTE 0x03 ++#define SPICMD_WRITE_DISABLE 0x04 ++#define SPICMD_READ_STATUS 0x05 ++#define SPICMD_WRITE_ENABLE 0x06 ++#define SPICMD_HIGH_SPEED_READ 0x0B ++#define SPICMD_POWER_DOWN 0xB9 ++#define SPICMD_SST_EWSR 0x50 ++#define SPICMD_SST_SEC_ERASE 0x20 ++#define SPICMD_SST_BLK_ERASE 0x52 ++#define SPICMD_SST_CHIP_ERASE 0x60 ++#define SPICMD_FRDO 0x3B ++#define SPICMD_SEC_ERASE 0xD7 ++#define SPICMD_BLK_ERASE 0xD8 ++#define SPICMD_CHIP_ERASE 0xC7 ++ ++/* bits definition for REG_XBISPICFG */ ++#define SPICFG_AUTO_CHECK 0x01 ++#define SPICFG_SPI_BUSY 0x02 ++#define SPICFG_DUMMY_READ 0x04 ++#define SPICFG_EN_SPICMD 0x08 ++#define SPICFG_LOW_SPICS 0x10 ++#define SPICFG_EN_SHORT_READ 0x20 ++#define SPICFG_EN_OFFSET_READ 0x40 ++#define SPICFG_EN_FAST_READ 0x80 ++ ++/* watchdog timer registers */ ++#define REG_WDTCFG 0xfe80 ++#define REG_WDTPF 0xfe81 ++#define REG_WDT 0xfe82 ++ ++/* lpc configure register */ ++#define REG_LPCCFG 0xfe95 ++ ++/* 8051 reg */ ++#define REG_PXCFG 0xff14 ++ ++/* Fan register in KB3310 */ ++#define REG_ECFAN_SPEED_LEVEL 0xf4e4 ++#define REG_ECFAN_SWITCH 0xf4d2 ++ ++/* the ec flash rom id number */ ++#define EC_ROM_PRODUCT_ID_SPANSION 0x01 ++#define EC_ROM_PRODUCT_ID_MXIC 0xC2 ++#define EC_ROM_PRODUCT_ID_AMIC 0x37 ++#define EC_ROM_PRODUCT_ID_EONIC 0x1C ++ ++/* misc ioctl operations */ ++#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int) ++#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int) ++#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int) ++#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int) ++#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int) ++ ++/* start address for programming of EC content or IE */ ++/* ec running code start address */ ++#define EC_START_ADDR 0x00000000 ++/* ec information element storing address */ ++#define IE_START_ADDR 0x00020000 ++ ++/* EC state */ ++#define EC_STATE_IDLE 0x00 /* ec in idle state */ ++#define EC_STATE_BUSY 0x01 /* ec in busy state */ ++ ++/* timeout value for programming */ ++#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */ ++/* command checkout timeout including cmd to port or state flag check */ ++#define EC_CMD_TIMEOUT 0x1000 ++#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */ ++#define EC_MAX_DELAY_UNIT (10) /* every time for polling */ ++#define SPI_FINISH_WAIT_TIME 10 ++/* EC content max size */ ++#define EC_CONTENT_MAX_SIZE (64 * 1024) ++#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR) ++ ++/* the register operation access struct */ ++struct ec_reg { ++ u32 addr; /* the address of kb3310 registers */ ++ u8 val; /* the register value */ ++}; ++ ++struct ec_info { ++ u32 start_addr; ++ u32 size; ++ u8 *buf; ++}; ++ ++/* open for using rom protection action */ ++#define EC_ROM_PROTECTION ++ ++/* enable the chip reset mode */ ++static int ec_init_reset_mode(void) ++{ ++ int timeout; ++ unsigned char status = 0; ++ int ret = 0; ++ ++ /* make chip goto reset mode */ ++ ret = ec_query_seq(CMD_INIT_RESET_MODE); ++ if (ret < 0) { ++ printk(KERN_ERR "ec init reset mode failed.\n"); ++ goto out; ++ } ++ ++ /* make the action take active */ ++ timeout = EC_CMD_TIMEOUT; ++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; ++ while (timeout--) { ++ if (status) { ++ udelay(EC_REG_DELAY); ++ break; ++ } ++ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE; ++ udelay(EC_REG_DELAY); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR "ec rom fixup : can't check reset status.\n"); ++ ret = -EINVAL; ++ } else ++ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout, ++ EC_CMD_TIMEOUT - timeout, status); ++ ++ /* set MCU to reset mode */ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_PXCFG); ++ status |= (1 << 0); ++ ec_write(REG_PXCFG, status); ++ udelay(EC_REG_DELAY); ++ ++ /* disable FWH/LPC */ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_LPCCFG); ++ status &= ~(1 << 7); ++ ec_write(REG_LPCCFG, status); ++ udelay(EC_REG_DELAY); ++ ++ printk(KERN_INFO "entering reset mode ok..............\n"); ++ ++ out: ++ return ret; ++} ++ ++/* make ec exit from reset mode */ ++static void ec_exit_reset_mode(void) ++{ ++ unsigned char regval; ++ ++ udelay(EC_REG_DELAY); ++ regval = ec_read(REG_LPCCFG); ++ regval |= (1 << 7); ++ ec_write(REG_LPCCFG, regval); ++ regval = ec_read(REG_PXCFG); ++ regval &= ~(1 << 0); ++ ec_write(REG_PXCFG, regval); ++ printk(KERN_INFO "exit reset mode ok..................\n"); ++ ++ return; ++} ++ ++/* make ec disable WDD */ ++static void ec_disable_WDD(void) ++{ ++ unsigned char status; ++ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_WDTCFG); ++ ec_write(REG_WDTPF, 0x03); ++ ec_write(REG_WDTCFG, (status & 0x80) | 0x48); ++ printk(KERN_INFO "Disable WDD ok..................\n"); ++ ++ return; ++} ++ ++/* make ec enable WDD */ ++static void ec_enable_WDD(void) ++{ ++ unsigned char status; ++ ++ udelay(EC_REG_DELAY); ++ status = ec_read(REG_WDTCFG); ++ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */ ++ ec_write(REG_WDTCFG, (status & 0x80) | 0x03); ++ printk(KERN_INFO "Enable WDD ok..................\n"); ++ ++ return; ++} ++ ++/* make ec goto idle mode */ ++static int ec_init_idle_mode(void) ++{ ++ int timeout; ++ unsigned char status = 0; ++ int ret = 0; ++ ++ ec_query_seq(CMD_INIT_IDLE_MODE); ++ ++ /* make the action take active */ ++ timeout = EC_CMD_TIMEOUT; ++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; ++ while (timeout--) { ++ if (status) { ++ udelay(EC_REG_DELAY); ++ break; ++ } ++ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE; ++ udelay(EC_REG_DELAY); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR "ec rom fixup : can't check out the status.\n"); ++ ret = -EINVAL; ++ } else ++ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout, ++ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE)); ++ ++ printk(KERN_INFO "entering idle mode ok...................\n"); ++ ++ return ret; ++} ++ ++/* make ec exit from idle mode */ ++static int ec_exit_idle_mode(void) ++{ ++ ++ ec_query_seq(CMD_EXIT_IDLE_MODE); ++ ++ printk(KERN_INFO "exit idle mode ok...................\n"); ++ ++ return 0; ++} ++ ++static int ec_instruction_cycle(void) ++{ ++ unsigned long timeout; ++ int ret = 0; ++ ++ timeout = EC_FLASH_TIMEOUT; ++ while (timeout-- >= 0) { ++ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY)) ++ break; ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ return ret; ++} ++ ++/* To see if the ec is in busy state or not. */ ++static inline int ec_flash_busy(unsigned long timeout) ++{ ++ /* assurance the first command be going to rom */ ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++#if 1 ++ timeout = timeout / EC_MAX_DELAY_UNIT; ++ while (timeout-- > 0) { ++ /* check the rom's status of busy flag */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) ++ return EC_STATE_IDLE; ++ udelay(EC_MAX_DELAY_UNIT); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_FLASH_BUSY : timeout for check rom flag.\n"); ++ return EC_STATE_BUSY; ++ } ++#else ++ /* check the rom's status of busy flag */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (ec_instruction_cycle() < 0) ++ return EC_STATE_BUSY; ++ ++ timeout = timeout / EC_MAX_DELAY_UNIT; ++ while (timeout-- > 0) { ++ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00) ++ return EC_STATE_IDLE; ++ udelay(EC_MAX_DELAY_UNIT); ++ } ++ if (timeout <= 0) { ++ printk(KERN_ERR ++ "EC_FLASH_BUSY : timeout for check rom flag.\n"); ++ return EC_STATE_BUSY; ++ } ++#endif ++ ++ return EC_STATE_IDLE; ++} ++ ++static int rom_instruction_cycle(unsigned char cmd) ++{ ++ unsigned long timeout = 0; ++ ++ switch (cmd) { ++ case SPICMD_READ_STATUS: ++ case SPICMD_WRITE_ENABLE: ++ case SPICMD_WRITE_DISABLE: ++ case SPICMD_READ_BYTE: ++ case SPICMD_HIGH_SPEED_READ: ++ timeout = 0; ++ break; ++ case SPICMD_WRITE_STATUS: ++ timeout = 300 * 1000; ++ break; ++ case SPICMD_BYTE_PROGRAM: ++ timeout = 5 * 1000; ++ break; ++ case SPICMD_SST_SEC_ERASE: ++ case SPICMD_SEC_ERASE: ++ timeout = 1000 * 1000; ++ break; ++ case SPICMD_SST_BLK_ERASE: ++ case SPICMD_BLK_ERASE: ++ timeout = 3 * 1000 * 1000; ++ break; ++ case SPICMD_SST_CHIP_ERASE: ++ case SPICMD_CHIP_ERASE: ++ timeout = 20 * 1000 * 1000; ++ break; ++ default: ++ timeout = EC_SPICMD_STANDARD_TIMEOUT; ++ } ++ if (timeout == 0) ++ return ec_instruction_cycle(); ++ if (timeout < EC_SPICMD_STANDARD_TIMEOUT) ++ timeout = EC_SPICMD_STANDARD_TIMEOUT; ++ ++ return ec_flash_busy(timeout); ++} ++ ++/* delay for start/stop action */ ++static void delay_spi(int n) ++{ ++ while (n--) ++ inb(EC_IO_PORT_HIGH); ++} ++ ++/* start the action to spi rom function */ ++static void ec_start_spi(void) ++{ ++ unsigned char val; ++ ++ delay_spi(SPI_FINISH_WAIT_TIME); ++ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK; ++ ec_write(REG_XBISPICFG, val); ++ delay_spi(SPI_FINISH_WAIT_TIME); ++} ++ ++/* stop the action to spi rom function */ ++static void ec_stop_spi(void) ++{ ++ unsigned char val; ++ ++ delay_spi(SPI_FINISH_WAIT_TIME); ++ val = ++ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK)); ++ ec_write(REG_XBISPICFG, val); ++ delay_spi(SPI_FINISH_WAIT_TIME); ++} ++ ++/* read one byte from xbi interface */ ++static int ec_read_byte(unsigned int addr, unsigned char *byte) ++{ ++ int ret = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* write the address */ ++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); ++ /* start action */ ++ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ); ++ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ *byte = ec_read(REG_XBISPIDAT); ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* write one byte to ec rom */ ++static int ec_write_byte(unsigned int addr, unsigned char byte) ++{ ++ int ret = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* write the address */ ++ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0); ++ ec_write(REG_XBISPIDAT, byte); ++ /* start action */ ++ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM); ++ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* unprotect SPI ROM */ ++/* EC_ROM_unprotect function code */ ++static int EC_ROM_unprotect(void) ++{ ++ unsigned char status; ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); ++ return 1; ++ } ++ ++ /* unprotect the status register of rom */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n"); ++ return 1; ++ } ++ status = ec_read(REG_XBISPIDAT); ++ ec_write(REG_XBISPIDAT, status & 0x02); ++ if (ec_instruction_cycle() < 0) { ++ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n"); ++ return 1; ++ } ++ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); ++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n"); ++ return 1; ++ } ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* erase one block or chip or sector as needed */ ++static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr) ++{ ++ unsigned char status; ++ int ret = 0, i = 0; ++ int unprotect_count = 3; ++ int check_flag = 0; ++ ++ /* enable spicmd writing. */ ++ ec_start_spi(); ++ ++#ifdef EC_ROM_PROTECTION ++ /* added for re-check SPICMD_READ_STATUS */ ++ while (unprotect_count-- > 0) { ++ if (EC_ROM_unprotect()) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* first time:500ms --> 5.5sec -->10.5sec */ ++ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++) ++ udelay(50000); ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) ++ == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); ++ } else { ++ status = ec_read(REG_XBISPIDAT); ++ printk(KERN_INFO "Read unprotect status : 0x%x\n", ++ status); ++ if ((status & 0x1C) == 0x00) { ++ printk(KERN_INFO ++ "Read unprotect status OK1 : 0x%x\n", ++ status & 0x1C); ++ check_flag = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!check_flag) { ++ printk(KERN_INFO "SPI ROM unprotect fail.\n"); ++ return 1; ++ } ++#endif ++ ++ /* block address fill */ ++ if (erase_cmd == SPICMD_BLK_ERASE) { ++ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16); ++ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8); ++ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0); ++ } ++ ++ /* erase the whole chip first */ ++ ec_write(REG_XBISPICMD, erase_cmd); ++ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) { ++ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ out: ++ /* disable spicmd writing. */ ++ ec_stop_spi(); ++ ++ return ret; ++} ++ ++/* update the whole rom content with H/W mode ++ * PLEASE USING ec_unit_erase() FIRSTLY ++ */ ++static int ec_program_rom(struct ec_info *info, int flag) ++{ ++ unsigned int addr = 0; ++ unsigned long size = 0; ++ unsigned char *ptr = NULL; ++ unsigned char data; ++ unsigned char val = 0; ++ int ret = 0; ++ int i, j; ++ unsigned char status; ++ ++ /* modify for program serial No. ++ * set IE_START_ADDR & use idle mode, ++ * disable WDD ++ */ ++ if (flag == PROGRAM_FLAG_ROM) { ++ ret = ec_init_reset_mode(); ++ addr = info->start_addr + EC_START_ADDR; ++ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n"); ++ } else if (flag == PROGRAM_FLAG_IE) { ++ ret = ec_init_idle_mode(); ++ ec_disable_WDD(); ++ addr = info->start_addr + IE_START_ADDR; ++ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n"); ++ } else { ++ return 0; ++ } ++ ++ if (ret < 0) { ++ if (flag == PROGRAM_FLAG_IE) ++ ec_enable_WDD(); ++ return ret; ++ } ++ ++ size = info->size; ++ ptr = info->buf; ++ printk(KERN_INFO "starting update ec ROM..............\n"); ++ ++ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr); ++ if (ret) { ++ printk(KERN_ERR "program ec : erase block failed.\n"); ++ goto out; ++ } ++ printk(KERN_ERR "program ec : erase block OK.\n"); ++ ++ i = 0; ++ while (i < size) { ++ data = *(ptr + i); ++ ec_write_byte(addr, data); ++ ec_read_byte(addr, &val); ++ if (val != data) { ++ ec_write_byte(addr, data); ++ ec_read_byte(addr, &val); ++ if (val != data) { ++ printk(KERN_INFO ++ "EC : Second flash program failed at:\t"); ++ printk(KERN_INFO ++ "addr : 0x%x, source : 0x%x, dest: 0x%x\n", ++ addr, data, val); ++ printk(KERN_INFO "This should not happen... STOP\n"); ++ break; ++ } ++ } ++ i++; ++ addr++; ++ } ++ ++#ifdef EC_ROM_PROTECTION ++ /* we should start spi access firstly */ ++ ec_start_spi(); ++ ++ /* enable write spi flash */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n"); ++ goto out1; ++ } ++ ++ /* protect the status register of rom */ ++ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS); ++ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n"); ++ goto out1; ++ } ++ status = ec_read(REG_XBISPIDAT); ++ ++ ec_write(REG_XBISPIDAT, status | 0x1C); ++ if (ec_instruction_cycle() < 0) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : write status value failed.\n"); ++ goto out1; ++ } ++ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS); ++ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n"); ++ goto out1; ++ } ++#endif ++ ++ /* disable the write action to spi rom */ ++ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE); ++ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) { ++ printk(KERN_ERR ++ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n"); ++ goto out1; ++ } ++ ++ out1: ++ /* we should stop spi access firstly */ ++ ec_stop_spi(); ++ out: ++ /* for security */ ++ for (j = 0; j < 2000; j++) ++ udelay(1000); ++ ++ /* modify for program serial No. ++ * after program No exit idle mode ++ * and enable WDD ++ */ ++ if (flag == PROGRAM_FLAG_ROM) { ++ /* exit from the reset mode */ ++ ec_exit_reset_mode(); ++ } else { ++ /* ec exit from idle mode */ ++ ret = ec_exit_idle_mode(); ++ ec_enable_WDD(); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* ioctl */ ++static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd, ++ u_long arg) ++{ ++ struct ec_info ecinfo; ++ void __user *ptr = (void __user *)arg; ++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); ++ int ret = 0; ++ ++ switch (cmd) { ++ case IOCTL_RDREG: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg read : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_MAX_REGADDR) ++ || (ecreg->addr < EC_MIN_REGADDR)) { ++ printk(KERN_ERR ++ "reg read : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ecreg->val = ec_read(ecreg->addr); ++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg read : copy to user error.\n"); ++ return -EFAULT; ++ } ++ break; ++ case IOCTL_WRREG: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "reg write : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_MAX_REGADDR) ++ || (ecreg->addr < EC_MIN_REGADDR)) { ++ printk(KERN_ERR ++ "reg write : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ec_write(ecreg->addr, ecreg->val); ++ break; ++ case IOCTL_READ_EC: ++ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "spi read : copy from user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecreg->addr > EC_RAM_ADDR) ++ && (ecreg->addr < EC_MAX_REGADDR)) { ++ printk(KERN_ERR ++ "spi read : out of register address range.\n"); ++ return -EINVAL; ++ } ++ ec_read_byte(ecreg->addr, &(ecreg->val)); ++ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg)); ++ if (ret) { ++ printk(KERN_ERR "spi read : copy to user error.\n"); ++ return -EFAULT; ++ } ++ break; ++ case IOCTL_PROGRAM_IE: ++ ecinfo.start_addr = EC_START_ADDR; ++ ecinfo.size = EC_CONTENT_MAX_SIZE; ++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); ++ if (ecinfo.buf == NULL) { ++ printk(KERN_ERR "program ie : kmalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size); ++ if (ret) { ++ printk(KERN_ERR "program ie : copy from user error.\n"); ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ return -EFAULT; ++ } ++ ++ /* use ec_program_rom to write serial No */ ++ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE); ++ ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ break; ++ case IOCTL_PROGRAM_EC: ++ ecinfo.start_addr = EC_START_ADDR; ++ if (get_user((ecinfo.size), (u32 *) ptr)) { ++ printk(KERN_ERR "program ec : get user error.\n"); ++ return -EFAULT; ++ } ++ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) { ++ printk(KERN_ERR "program ec : size out of limited.\n"); ++ return -EINVAL; ++ } ++ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL); ++ if (ecinfo.buf == NULL) { ++ printk(KERN_ERR "program ec : kmalloc failed.\n"); ++ return -ENOMEM; ++ } ++ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size); ++ if (ret) { ++ printk(KERN_ERR "program ec : copy from user error.\n"); ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ return -EFAULT; ++ } ++ ++ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM); ++ ++ kfree(ecinfo.buf); ++ ecinfo.buf = NULL; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static long misc_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg); ++} ++ ++static int misc_open(struct inode *inode, struct file *filp) ++{ ++ struct ec_reg *ecreg = NULL; ++ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL); ++ if (ecreg) ++ filp->private_data = ecreg; ++ ++ return ecreg ? 0 : -ENOMEM; ++} ++ ++static int misc_release(struct inode *inode, struct file *filp) ++{ ++ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data); ++ ++ filp->private_data = NULL; ++ kfree(ecreg); ++ ++ return 0; ++} ++ ++static const struct file_operations ecmisc_fops = { ++ .open = misc_open, ++ .release = misc_release, ++ .read = NULL, ++ .write = NULL, ++#ifdef CONFIG_64BIT ++ .compat_ioctl = misc_compat_ioctl, ++#else ++ .ioctl = misc_ioctl, ++#endif ++}; ++ ++static struct miscdevice ecmisc_device = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = EC_MISC_DEV, ++ .fops = &ecmisc_fops ++}; ++ ++static int __init ecmisc_init(void) ++{ ++ int ret; ++ ++ printk(KERN_INFO "EC misc device init.\n"); ++ ret = misc_register(&ecmisc_device); ++ ++ return ret; ++} ++ ++static void __exit ecmisc_exit(void) ++{ ++ printk(KERN_INFO "EC misc device exit.\n"); ++ misc_deregister(&ecmisc_device); ++} ++ ++module_init(ecmisc_init); ++module_exit(ecmisc_exit); ++ ++MODULE_AUTHOR("liujl "); ++MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c +new file mode 100644 +index 0000000..32a2bdb +--- /dev/null ++++ b/drivers/platform/mips/yeeloong_laptop.c +@@ -0,0 +1,1360 @@ ++/* ++ * Driver for YeeLoong laptop extras ++ * ++ * Copyright (C) 2009 Lemote Inc. ++ * Author: Wu Zhangjin , Liu Junliang ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include /* for backlight subdriver */ ++#include ++#include /* for hwmon subdriver */ ++#include ++#include /* for video output subdriver */ ++#include /* for lcd output subdriver */ ++#include /* for hotkey subdriver */ ++#include ++#include ++#include ++#include /* for AC & Battery subdriver */ ++#include /* for register_reboot_notifier */ ++#include /* for register_pm_notifier */ ++ ++#include ++ ++#include /* for loongson_cmdline */ ++#include ++ ++#define ON 1 ++#define OFF 0 ++#define EVENT_START EVENT_LID ++ ++/* common function */ ++#define EC_VER_LEN 64 ++ ++static int ec_version_before(char *version) ++{ ++ char *p, ec_ver[EC_VER_LEN]; ++ ++ p = strstr(loongson_cmdline, "EC_VER="); ++ if (!p) ++ memset(ec_ver, 0, EC_VER_LEN); ++ else { ++ strncpy(ec_ver, p, EC_VER_LEN); ++ p = strstr(ec_ver, " "); ++ if (p) ++ *p = '\0'; ++ } ++ ++ return (strncasecmp(ec_ver, version, 64) < 0); ++} ++ ++/* backlight subdriver */ ++#define MIN_BRIGHTNESS 1 ++#define MAX_BRIGHTNESS 8 ++ ++static int yeeloong_set_brightness(struct backlight_device *bd) ++{ ++ unsigned char level; ++ static unsigned char old_level; ++ ++ level = (bd->props.fb_blank == FB_BLANK_UNBLANK && ++ bd->props.power == FB_BLANK_UNBLANK) ? ++ bd->props.brightness : 0; ++ ++ level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS); ++ ++ /* Avoid to modify the brightness when EC is tuning it */ ++ if (old_level != level) { ++ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level) ++ ec_write(REG_DISPLAY_BRIGHTNESS, level); ++ old_level = level; ++ } ++ ++ return 0; ++} ++ ++static int yeeloong_get_brightness(struct backlight_device *bd) ++{ ++ return ec_read(REG_DISPLAY_BRIGHTNESS); ++} ++ ++static struct backlight_ops backlight_ops = { ++ .get_brightness = yeeloong_get_brightness, ++ .update_status = yeeloong_set_brightness, ++}; ++ ++static struct backlight_device *yeeloong_backlight_dev; ++ ++static int yeeloong_backlight_init(void) ++{ ++ int ret; ++ struct backlight_properties props; ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.max_brightness = MAX_BRIGHTNESS; ++ props.type = BACKLIGHT_PLATFORM; ++ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL, ++ NULL, &backlight_ops, &props); ++ ++ if (IS_ERR(yeeloong_backlight_dev)) { ++ ret = PTR_ERR(yeeloong_backlight_dev); ++ yeeloong_backlight_dev = NULL; ++ return ret; ++ } ++ ++ yeeloong_backlight_dev->props.brightness = ++ yeeloong_get_brightness(yeeloong_backlight_dev); ++ backlight_update_status(yeeloong_backlight_dev); ++ ++ return 0; ++} ++ ++static void yeeloong_backlight_exit(void) ++{ ++ if (yeeloong_backlight_dev) { ++ backlight_device_unregister(yeeloong_backlight_dev); ++ yeeloong_backlight_dev = NULL; ++ } ++} ++ ++/* AC & Battery subdriver */ ++ ++static struct power_supply yeeloong_ac, yeeloong_bat; ++ ++#define RET (val->intval) ++ ++#define BAT_CAP_CRITICAL 5 ++#define BAT_CAP_HIGH 95 ++ ++#define get_bat(type) \ ++ ec_read(REG_BAT_##type) ++ ++#define get_bat_l(type) \ ++ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW)) ++ ++static int yeeloong_get_ac_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ if (psp == POWER_SUPPLY_PROP_ONLINE) ++ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN); ++ ++ return 0; ++} ++ ++static enum power_supply_property yeeloong_ac_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++}; ++ ++static struct power_supply yeeloong_ac = { ++ .name = "yeeloong-ac", ++ .type = POWER_SUPPLY_TYPE_MAINS, ++ .properties = yeeloong_ac_props, ++ .num_properties = ARRAY_SIZE(yeeloong_ac_props), ++ .get_property = yeeloong_get_ac_props, ++}; ++ ++static inline bool is_bat_in(void) ++{ ++ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN); ++} ++ ++static int get_bat_temp(void) ++{ ++ return get_bat_l(TEMPERATURE) * 10; ++} ++ ++static int get_bat_current(void) ++{ ++ return -(s16)get_bat_l(CURRENT); ++} ++ ++static int get_bat_voltage(void) ++{ ++ return get_bat_l(VOLTAGE); ++} ++ ++static char *get_manufacturer(void) ++{ ++ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO"; ++} ++ ++static int get_relative_cap(void) ++{ ++ /* ++ * When the relative capacity becomes 2, the hardware is observed to ++ * have been turned off forcely. so, we must tune it be suitable to ++ * make the software do related actions. ++ */ ++ int tmp = get_bat_l(RELATIVE_CAP); ++ ++ if (tmp <= (BAT_CAP_CRITICAL * 2)) ++ tmp -= 3; ++ ++ return tmp; ++} ++ ++static int yeeloong_get_bat_props(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ switch (psp) { ++ /* Fixed information */ ++ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: ++ /* mV -> µV */ ++ RET = get_bat_l(DESIGN_VOL) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: ++ /* mAh->µAh */ ++ RET = get_bat_l(DESIGN_CAP) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ /* µAh */ ++ RET = get_bat_l(FULLCHG_CAP) * 1000; ++ break; ++ case POWER_SUPPLY_PROP_MANUFACTURER: ++ val->strval = get_manufacturer(); ++ break; ++ /* Dynamic information */ ++ case POWER_SUPPLY_PROP_PRESENT: ++ RET = is_bat_in(); ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ /* mA -> µA */ ++ RET = is_bat_in() ? get_bat_current() * 1000 : 0; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ /* mV -> µV */ ++ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0; ++ break; ++ case POWER_SUPPLY_PROP_TEMP: ++ /* Celcius */ ++ RET = is_bat_in() ? get_bat_temp() : 0; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY: ++ RET = is_bat_in() ? get_relative_cap() : 0; ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: { ++ int status; ++ ++ if (!is_bat_in()) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ break; ++ } ++ ++ status = get_bat(STATUS); ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; ++ ++ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; ++ break; ++ } ++ ++ if (status & BIT_BAT_STATUS_FULL) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL; ++ else { ++ int curr_cap = get_relative_cap(); ++ ++ if (status & BIT_BAT_STATUS_LOW) { ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW; ++ if (curr_cap <= BAT_CAP_CRITICAL) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; ++ } else if (curr_cap >= BAT_CAP_HIGH) ++ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; ++ } ++ } break; ++ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: ++ /* seconds */ ++ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0; ++ break; ++ case POWER_SUPPLY_PROP_STATUS: { ++ int charge = get_bat(CHARGE); ++ ++ RET = POWER_SUPPLY_STATUS_UNKNOWN; ++ if (charge & FLAG_BAT_CHARGE_DISCHARGE) ++ RET = POWER_SUPPLY_STATUS_DISCHARGING; ++ else if (charge & FLAG_BAT_CHARGE_CHARGE) ++ RET = POWER_SUPPLY_STATUS_CHARGING; ++ } break; ++ case POWER_SUPPLY_PROP_HEALTH: { ++ int status; ++ ++ if (!is_bat_in()) { ++ RET = POWER_SUPPLY_HEALTH_UNKNOWN; ++ break; ++ } ++ ++ status = get_bat(STATUS); ++ RET = POWER_SUPPLY_HEALTH_GOOD; ++ ++ if (status & (BIT_BAT_STATUS_DESTROY | ++ BIT_BAT_STATUS_LOW)) ++ RET = POWER_SUPPLY_HEALTH_DEAD; ++ if (get_bat(CHARGE_STATUS) & ++ BIT_BAT_CHARGE_STATUS_OVERTEMP) ++ RET = POWER_SUPPLY_HEALTH_OVERHEAT; ++ } break; ++ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */ ++ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10; ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++#undef RET ++ ++static enum power_supply_property yeeloong_bat_props[] = { ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL, ++ POWER_SUPPLY_PROP_CHARGE_NOW, ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_HEALTH, ++ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_CAPACITY_LEVEL, ++ POWER_SUPPLY_PROP_TEMP, ++ POWER_SUPPLY_PROP_MANUFACTURER, ++}; ++ ++static struct power_supply yeeloong_bat = { ++ .name = "yeeloong-bat", ++ .type = POWER_SUPPLY_TYPE_BATTERY, ++ .properties = yeeloong_bat_props, ++ .num_properties = ARRAY_SIZE(yeeloong_bat_props), ++ .get_property = yeeloong_get_bat_props, ++}; ++ ++static int ac_bat_initialized; ++ ++static int yeeloong_bat_init(void) ++{ ++ int ret; ++ ++ ret = power_supply_register(NULL, &yeeloong_ac); ++ if (ret) ++ return ret; ++ ret = power_supply_register(NULL, &yeeloong_bat); ++ if (ret) { ++ power_supply_unregister(&yeeloong_ac); ++ return ret; ++ } ++ ac_bat_initialized = 1; ++ ++ return 0; ++} ++ ++static void yeeloong_bat_exit(void) ++{ ++ ac_bat_initialized = 0; ++ ++ power_supply_unregister(&yeeloong_ac); ++ power_supply_unregister(&yeeloong_bat); ++} ++/* hwmon subdriver */ ++ ++#define MIN_FAN_SPEED 0 ++#define MAX_FAN_SPEED 3 ++ ++#define get_fan(type) \ ++ ec_read(REG_FAN_##type) ++ ++#define set_fan(type, val) \ ++ ec_write(REG_FAN_##type, val) ++ ++static inline int get_fan_speed_level(void) ++{ ++ return get_fan(SPEED_LEVEL); ++} ++static inline void set_fan_speed_level(int speed) ++{ ++ set_fan(SPEED_LEVEL, speed); ++} ++ ++static inline int get_fan_mode(void) ++{ ++ return get_fan(AUTO_MAN_SWITCH); ++} ++static inline void set_fan_mode(int mode) ++{ ++ set_fan(AUTO_MAN_SWITCH, mode); ++} ++ ++/* ++ * 3 different modes: Full speed(0); manual mode(1); auto mode(2) ++ */ ++static int get_fan_pwm_enable(void) ++{ ++ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 : ++ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1; ++} ++ ++static void set_fan_pwm_enable(int mode) ++{ ++ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL); ++ if (mode == 0) ++ set_fan_speed_level(MAX_FAN_SPEED); ++} ++ ++static int get_fan_pwm(void) ++{ ++ return get_fan_speed_level(); ++} ++ ++static void set_fan_pwm(int value) ++{ ++ if (get_fan_mode() != BIT_FAN_MANUAL) ++ return; ++ ++ value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED); ++ ++ /* We must ensure the fan is on */ ++ if (value > 0) ++ set_fan(CONTROL, ON); ++ ++ set_fan_speed_level(value); ++} ++ ++static inline int get_fan_speed(void) ++{ ++ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW); ++} ++ ++static int get_fan_rpm(void) ++{ ++ return FAN_SPEED_DIVIDER / get_fan_speed(); ++} ++ ++static int get_cpu_temp(void) ++{ ++ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000; ++} ++ ++static int get_cpu_temp_max(void) ++{ ++ return 60 * 1000; ++} ++ ++static int get_bat_temp_alarm(void) ++{ ++ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP); ++} ++ ++static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long value; ++ ++ if (!count) ++ return 0; ++ ++ ret = kstrtoul(buf, 10, &value); ++ if (ret) ++ return ret; ++ ++ set(value); ++ ++ return count; ++} ++ ++static ssize_t show_sys_hwmon(int (*get) (void), char *buf) ++{ ++ return sprintf(buf, "%d\n", get()); ++} ++ ++#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \ ++ static ssize_t show_##_name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++ { \ ++ return show_sys_hwmon(_set, buf); \ ++ } \ ++ static ssize_t store_##_name(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++ { \ ++ return store_sys_hwmon(_get, buf, count); \ ++ } \ ++ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0); ++ ++CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL); ++CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm); ++CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable, ++ set_fan_pwm_enable); ++CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL); ++CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL); ++CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL); ++CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL); ++CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL); ++CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL); ++ ++static ssize_t ++show_name(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "yeeloong\n"); ++} ++ ++static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); ++ ++static struct attribute *hwmon_attributes[] = { ++ &sensor_dev_attr_pwm1.dev_attr.attr, ++ &sensor_dev_attr_pwm1_enable.dev_attr.attr, ++ &sensor_dev_attr_fan1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ &sensor_dev_attr_temp1_max.dev_attr.attr, ++ &sensor_dev_attr_temp2_input.dev_attr.attr, ++ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, ++ &sensor_dev_attr_curr1_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_name.dev_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group hwmon_attribute_group = { ++ .attrs = hwmon_attributes ++}; ++ ++static struct device *yeeloong_hwmon_dev; ++ ++static int yeeloong_hwmon_init(void) ++{ ++ int ret; ++ ++ yeeloong_hwmon_dev = hwmon_device_register(NULL); ++ if (IS_ERR(yeeloong_hwmon_dev)) { ++ yeeloong_hwmon_dev = NULL; ++ return PTR_ERR(yeeloong_hwmon_dev); ++ } ++ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj, ++ &hwmon_attribute_group); ++ if (ret) { ++ hwmon_device_unregister(yeeloong_hwmon_dev); ++ yeeloong_hwmon_dev = NULL; ++ return ret; ++ } ++ /* ensure fan is set to auto mode */ ++ set_fan_pwm_enable(2); ++ ++ return 0; ++} ++ ++static void yeeloong_hwmon_exit(void) ++{ ++ if (yeeloong_hwmon_dev) { ++ sysfs_remove_group(&yeeloong_hwmon_dev->kobj, ++ &hwmon_attribute_group); ++ hwmon_device_unregister(yeeloong_hwmon_dev); ++ yeeloong_hwmon_dev = NULL; ++ } ++} ++ ++/* video output subdriver */ ++ ++#define LCD 0 ++#define CRT 1 ++#define VOD_NUM 2 /* The total number of video output device*/ ++ ++static struct output_device *vod[VOD_NUM]; ++ ++static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT}; ++ ++static int get_vo_dev(struct output_device *od) ++{ ++ int i, dev; ++ ++ dev = -1; ++ for (i = 0; i < VOD_NUM; i++) ++ if (od == vod[i]) ++ dev = i; ++ ++ return dev; ++} ++ ++static int vo_get_status(int dev) ++{ ++ return ec_read(vor[dev]); ++} ++ ++static int yeeloong_vo_get_status(struct output_device *od) ++{ ++ int vd; ++ ++ vd = get_vo_dev(od); ++ if (vd != -1) ++ return vo_get_status(vd); ++ ++ return -ENODEV; ++} ++ ++static void vo_set_state(int dev, int state) ++{ ++ int addr; ++ unsigned long value; ++ ++ switch (dev) { ++ case LCD: ++ addr = 0x31; ++ break; ++ case CRT: ++ addr = 0x21; ++ break; ++ default: ++ /* return directly if the wrong video output device */ ++ return; ++ } ++ ++ outb(addr, 0x3c4); ++ value = inb(0x3c5); ++ ++ switch (dev) { ++ case LCD: ++ value |= (state ? 0x03 : 0x02); ++ break; ++ case CRT: ++ if (state) ++ clear_bit(7, &value); ++ else ++ set_bit(7, &value); ++ break; ++ default: ++ break; ++ } ++ ++ outb(addr, 0x3c4); ++ outb(value, 0x3c5); ++ ++ if (dev == LCD) ++ ec_write(REG_BACKLIGHT_CTRL, state); ++} ++ ++static int yeeloong_vo_set_state(struct output_device *od) ++{ ++ int vd; ++ ++ vd = get_vo_dev(od); ++ if (vd == -1) ++ return -ENODEV; ++ ++ if (vd == CRT && !vo_get_status(vd)) ++ return 0; ++ ++ vo_set_state(vd, !!od->request_state); ++ ++ return 0; ++} ++ ++static struct output_properties vop = { ++ .set_state = yeeloong_vo_set_state, ++ .get_status = yeeloong_vo_get_status, ++}; ++ ++static int yeeloong_vo_init(void) ++{ ++ int ret, i; ++ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; ++ ++ /* Register video output device: lcd, crt */ ++ for (i = 0; i < VOD_NUM; i++) { ++ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop); ++ if (IS_ERR(vod[i])) { ++ if (i != 0) ++ video_output_unregister(vod[i-1]); ++ ret = PTR_ERR(vod[i]); ++ vod[i] = NULL; ++ return ret; ++ } ++ } ++ /* Ensure LCD is on by default */ ++ vo_set_state(LCD, ON); ++ ++ /* ++ * Turn off CRT by default, and will be enabled when the CRT ++ * connectting event reported by SCI ++ */ ++ vo_set_state(CRT, OFF); ++ ++ return 0; ++} ++ ++static void yeeloong_vo_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < VOD_NUM; i++) { ++ if (vod[i]) { ++ video_output_unregister(vod[i]); ++ vod[i] = NULL; ++ } ++ } ++} ++ ++/* lcd subdriver */ ++ ++struct lcd_device *lcd[VOD_NUM]; ++ ++static int get_lcd_dev(struct lcd_device *ld) ++{ ++ int i, dev; ++ ++ dev = -1; ++ for (i = 0; i < VOD_NUM; i++) ++ if (ld == lcd[i]) ++ dev = i; ++ ++ return dev; ++} ++ ++static int yeeloong_lcd_set_power(struct lcd_device *ld, int power) ++{ ++ int dev = get_lcd_dev(ld); ++ ++ if (power == FB_BLANK_UNBLANK) ++ vo_set_state(dev, ON); ++ if (power == FB_BLANK_POWERDOWN) ++ vo_set_state(dev, OFF); ++ ++ return 0; ++} ++ ++static int yeeloong_lcd_get_power(struct lcd_device *ld) ++{ ++ return vo_get_status(get_lcd_dev(ld)); ++} ++ ++static struct lcd_ops lcd_ops = { ++ .set_power = yeeloong_lcd_set_power, ++ .get_power = yeeloong_lcd_get_power, ++}; ++ ++static int yeeloong_lcd_init(void) ++{ ++ int ret, i; ++ char dev_name[VOD_NUM][4] = {"LCD", "CRT"}; ++ ++ /* Register video output device: lcd, crt */ ++ for (i = 0; i < VOD_NUM; i++) { ++ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops); ++ if (IS_ERR(lcd[i])) { ++ if (i != 0) ++ lcd_device_unregister(lcd[i-1]); ++ ret = PTR_ERR(lcd[i]); ++ lcd[i] = NULL; ++ return ret; ++ } ++ } ++#if 0 ++ /* This has been done by the vide output driver */ ++ ++ /* Ensure LCD is on by default */ ++ vo_set_state(LCD, ON); ++ ++ /* ++ * Turn off CRT by default, and will be enabled when the CRT ++ * connectting event reported by SCI ++ */ ++ vo_set_state(CRT, OFF); ++#endif ++ return 0; ++} ++ ++static void yeeloong_lcd_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < VOD_NUM; i++) { ++ if (lcd[i]) { ++ lcd_device_unregister(lcd[i]); ++ lcd[i] = NULL; ++ } ++ } ++} ++ ++/* hotkey subdriver */ ++ ++static struct input_dev *yeeloong_hotkey_dev; ++ ++static atomic_t reboot_flag, sleep_flag; ++#define in_sleep() (&sleep_flag) ++#define in_reboot() (&reboot_flag) ++ ++static const struct key_entry yeeloong_keymap[] = { ++ {KE_SW, EVENT_LID, { SW_LID } }, ++ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */ ++ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */ ++ {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */ ++ {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */ ++ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */ ++ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */ ++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */ ++ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */ ++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */ ++ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */ ++ {KE_END, 0} ++}; ++ ++static int is_fake_event(u16 keycode) ++{ ++ switch (keycode) { ++ case KEY_SLEEP: ++ case SW_LID: ++ return atomic_read(in_sleep()) | atomic_read(in_reboot()); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct key_entry *get_event_key_entry(int event, int status) ++{ ++ struct key_entry *ke; ++ static int old_brightness_status = -1; ++ static int old_volume_status = -1; ++ ++ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event); ++ if (!ke) ++ return NULL; ++ ++ switch (event) { ++ case EVENT_DISPLAY_BRIGHTNESS: ++ /* current status > old one, means up */ ++ if ((status < old_brightness_status) || (0 == status)) ++ ke++; ++ old_brightness_status = status; ++ break; ++ case EVENT_AUDIO_VOLUME: ++ if ((status < old_volume_status) || (0 == status)) ++ ke++; ++ old_volume_status = status; ++ break; ++ default: ++ break; ++ } ++ ++ return ke; ++} ++ ++static int report_lid_switch(int status) ++{ ++ static int old_status; ++ ++ /* ++ * LID is a switch button, so, two continuous same status should be ++ * ignored ++ */ ++ if (old_status != status) { ++ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status); ++ input_sync(yeeloong_hotkey_dev); ++ } ++ old_status = status; ++ ++ return status; ++} ++ ++static int crt_detect_handler(int status) ++{ ++ /* ++ * When CRT is inserted, enable its output and disable the LCD output, ++ * otherwise, do reversely. ++ */ ++ vo_set_state(CRT, status); ++ vo_set_state(LCD, !status); ++ ++ return status; ++} ++ ++static int displaytoggle_handler(int status) ++{ ++ /* EC(>=PQ1D26) does this job for us, we can not do it again, ++ * otherwise, the brightness will not resume to the normal level! */ ++ if (ec_version_before("EC_VER=PQ1D26")) ++ vo_set_state(LCD, status); ++ ++ return status; ++} ++ ++static int mypow(int x, int y) ++{ ++ int i, j = x; ++ ++ for (i = 1; i < y; i++) ++ j *= j; ++ ++ return j; ++} ++ ++static int switchvideomode_handler(int status) ++{ ++ /* Default status: CRT|LCD = 0|1 = 1 */ ++ static int bin_state = 1; ++ int i; ++ ++ /* ++ * Only enable switch video output button ++ * when CRT is connected ++ */ ++ if (!vo_get_status(CRT)) ++ return 0; ++ /* ++ * 2. no CRT connected: LCD on, CRT off ++ * 3. BOTH on ++ * 0. BOTH off ++ * 1. LCD off, CRT on ++ */ ++ ++ bin_state++; ++ if (bin_state > mypow(2, VOD_NUM) - 1) ++ bin_state = 0; ++ ++ for (i = 0; i < VOD_NUM; i++) ++ vo_set_state(i, bin_state & (1 << i)); ++ ++ return bin_state; ++} ++ ++static int camera_handler(int status) ++{ ++ int value; ++ ++ value = ec_read(REG_CAMERA_CONTROL); ++ ec_write(REG_CAMERA_CONTROL, value | (1 << 1)); ++ ++ return status; ++} ++ ++static int usb2_handler(int status) ++{ ++ pr_emerg("USB2 Over Current occurred\n"); ++ ++ return status; ++} ++ ++static int usb0_handler(int status) ++{ ++ pr_emerg("USB0 Over Current occurred\n"); ++ ++ return status; ++} ++ ++static int ac_bat_handler(int status) ++{ ++ if (ac_bat_initialized) { ++ power_supply_changed(&yeeloong_ac); ++ power_supply_changed(&yeeloong_bat); ++ } ++ ++ return status; ++} ++ ++struct sci_event { ++ int reg; ++ sci_handler handler; ++}; ++ ++static const struct sci_event se[] = { ++ [EVENT_AC_BAT] = {0, ac_bat_handler}, ++ [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL}, ++ [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL}, ++ [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler}, ++ [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler}, ++ [EVENT_BLACK_SCREEN] = {REG_DISPLAY_LCD, displaytoggle_handler}, ++ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL}, ++ [EVENT_LID] = {REG_LID_DETECT, NULL}, ++ [EVENT_DISPLAY_TOGGLE] = {0, switchvideomode_handler}, ++ [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler}, ++ [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler}, ++ [EVENT_WLAN] = {REG_WLAN, NULL}, ++}; ++ ++static void do_event_action(int event) ++{ ++ int status = -1; ++ struct key_entry *ke; ++ struct sci_event *sep; ++ ++ sep = (struct sci_event *)&se[event]; ++ ++ if (sep->reg != 0) ++ status = ec_read(sep->reg); ++ ++ if (status == -1) { ++ /* ec_read hasn't been called, status is invalid */ ++ return; ++ } ++ ++ if (sep->handler != NULL) ++ status = sep->handler(status); ++ ++ pr_debug("%s: event: %d status: %d\n", __func__, event, status); ++ ++ /* Report current key to user-space */ ++ ke = get_event_key_entry(event, status); ++ ++ /* ++ * Ignore the LID and SLEEP event when we are already in sleep or ++ * reboot state, this will avoid the recursive pm operations. but note: ++ * the report_lid_switch() called in arch/mips/loongson/lemote-2f/pm.c ++ * is necessary, because it is used to wake the system from sleep ++ * state. In the future, perhaps SW_LID should works like SLEEP, no ++ * need to function as a SWITCH, just report the state when the LID is ++ * closed is enough, this event can tell the software to "SLEEP", no ++ * need to tell the softwares when we are resuming from "SLEEP". ++ */ ++ if (ke && !is_fake_event(ke->keycode)) { ++ if (ke->keycode == SW_LID) ++ report_lid_switch(status); ++ else ++ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1, ++ true); ++ } ++} ++ ++/* ++ * SCI(system control interrupt) main interrupt routine ++ * ++ * We will do the query and get event number together so the interrupt routine ++ * should be longer than 120us now at least 3ms elpase for it. ++ */ ++static irqreturn_t sci_irq_handler(int irq, void *dev_id) ++{ ++ int ret, event; ++ ++ if (SCI_IRQ_NUM != irq) ++ return IRQ_NONE; ++ ++ /* Query the event number */ ++ ret = ec_query_event_num(); ++ if (ret < 0) ++ return IRQ_NONE; ++ ++ event = ec_get_event_num(); ++ if (event < EVENT_START || event > EVENT_END) ++ return IRQ_NONE; ++ ++ /* Execute corresponding actions */ ++ do_event_action(event); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Config and init some msr and gpio register properly. ++ */ ++static int sci_irq_init(void) ++{ ++ u32 hi, lo; ++ u32 gpio_base; ++ unsigned long flags; ++ int ret; ++ ++ /* Get gpio base */ ++ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); ++ gpio_base = lo & 0xff00; ++ ++ /* Filter the former kb3310 interrupt for security */ ++ ret = ec_query_event_num(); ++ if (ret) ++ return ret; ++ ++ /* For filtering next number interrupt */ ++ udelay(10000); ++ ++ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN ++ * gpio : ++ * input, pull-up, no-invert, event-count and value 0, ++ * no-filter, no edge mode ++ * gpio27 map to Virtual gpio0 ++ * msr : ++ * no primary and lpc ++ * Unrestricted Z input to IG10 from Virtual gpio 0. ++ */ ++ local_irq_save(flags); ++ _rdmsr(0x80000024, &hi, &lo); ++ lo &= ~(1 << 10); ++ _wrmsr(0x80000024, hi, lo); ++ _rdmsr(0x80000025, &hi, &lo); ++ lo &= ~(1 << 10); ++ _wrmsr(0x80000025, hi, lo); ++ _rdmsr(0x80000023, &hi, &lo); ++ lo |= (0x0a << 0); ++ _wrmsr(0x80000023, hi, lo); ++ local_irq_restore(flags); ++ ++ /* Set gpio27 as sci interrupt ++ * ++ * input, pull-up, no-fliter, no-negedge, invert ++ * the sci event is just about 120us ++ */ ++ asm(".set noreorder\n"); ++ /* input enable */ ++ outl(0x00000800, (gpio_base | 0xA0)); ++ /* revert the input */ ++ outl(0x00000800, (gpio_base | 0xA4)); ++ /* event-int enable */ ++ outl(0x00000800, (gpio_base | 0xB8)); ++ asm(".set reorder\n"); ++ ++ return 0; ++} ++ ++static int notify_reboot(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ switch (event) { ++ case SYS_RESTART: ++ case SYS_HALT: ++ case SYS_POWER_OFF: ++ atomic_set(in_reboot(), 1); ++ break; ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static int notify_pm(struct notifier_block *nb, unsigned long event, void *buf) ++{ ++ switch (event) { ++ case PM_HIBERNATION_PREPARE: ++ case PM_SUSPEND_PREPARE: ++ atomic_inc(in_sleep()); ++ break; ++ case PM_POST_HIBERNATION: ++ case PM_POST_SUSPEND: ++ case PM_RESTORE_PREPARE: /* do we need this ?? */ ++ atomic_dec(in_sleep()); ++ break; ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event, ++ atomic_read(in_sleep())); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block reboot_notifier = { ++ .notifier_call = notify_reboot, ++}; ++ ++static struct notifier_block pm_notifier = { ++ .notifier_call = notify_pm, ++}; ++ ++static int yeeloong_hotkey_init(void) ++{ ++ int ret = 0; ++ ++ ret = register_reboot_notifier(&reboot_notifier); ++ if (ret) { ++ pr_err("Can't register reboot notifier\n"); ++ goto end; ++ } ++ ++ ret = register_pm_notifier(&pm_notifier); ++ if (ret) { ++ pr_err("Can't register pm notifier\n"); ++ goto free_reboot_notifier; ++ } ++ ++ ret = sci_irq_init(); ++ if (ret) { ++ pr_err("Can't init SCI interrupt\n"); ++ goto free_pm_notifier; ++ } ++ ++ ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler, ++ IRQF_ONESHOT, "sci", NULL); ++ if (ret) { ++ pr_err("Can't thread SCI interrupt handler\n"); ++ goto free_pm_notifier; ++ } ++ ++ yeeloong_hotkey_dev = input_allocate_device(); ++ ++ if (!yeeloong_hotkey_dev) { ++ ret = -ENOMEM; ++ goto free_irq; ++ } ++ ++ yeeloong_hotkey_dev->name = "HotKeys"; ++ yeeloong_hotkey_dev->phys = "button/input0"; ++ yeeloong_hotkey_dev->id.bustype = BUS_HOST; ++ yeeloong_hotkey_dev->dev.parent = NULL; ++ ++ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL); ++ if (ret) { ++ pr_err("Failed to setup input device keymap\n"); ++ goto free_dev; ++ } ++ ++ ret = input_register_device(yeeloong_hotkey_dev); ++ if (ret) ++ goto free_keymap; ++ ++ /* Update the current status of LID */ ++ report_lid_switch(ON); ++ ++#ifdef CONFIG_LOONGSON_SUSPEND ++ /* Install the real yeeloong_report_lid_status for pm.c */ ++ yeeloong_report_lid_status = report_lid_switch; ++#endif ++ return 0; ++ ++free_keymap: ++ sparse_keymap_free(yeeloong_hotkey_dev); ++free_dev: ++ input_free_device(yeeloong_hotkey_dev); ++free_irq: ++ free_irq(SCI_IRQ_NUM, NULL); ++free_pm_notifier: ++ unregister_pm_notifier(&pm_notifier); ++free_reboot_notifier: ++ unregister_reboot_notifier(&reboot_notifier); ++end: ++ return ret; ++} ++ ++static void yeeloong_hotkey_exit(void) ++{ ++ /* Free irq */ ++ free_irq(SCI_IRQ_NUM, NULL); ++ ++#ifdef CONFIG_LOONGSON_SUSPEND ++ /* Uninstall yeeloong_report_lid_status for pm.c */ ++ if (yeeloong_report_lid_status == report_lid_switch) ++ yeeloong_report_lid_status = NULL; ++#endif ++ ++ if (yeeloong_hotkey_dev) { ++ sparse_keymap_free(yeeloong_hotkey_dev); ++ input_unregister_device(yeeloong_hotkey_dev); ++ yeeloong_hotkey_dev = NULL; ++ } ++} ++ ++#ifdef CONFIG_PM ++static void usb_ports_set(int status) ++{ ++ status = !!status; ++ ++ ec_write(REG_USB0_FLAG, status); ++ ec_write(REG_USB1_FLAG, status); ++ ec_write(REG_USB2_FLAG, status); ++} ++ ++static int yeeloong_suspend(struct device *dev) ++ ++{ ++ if (ec_version_before("EC_VER=PQ1D27")) ++ vo_set_state(LCD, OFF); ++ vo_set_state(CRT, OFF); ++ usb_ports_set(OFF); ++ ++ return 0; ++} ++ ++static int yeeloong_resume(struct device *dev) ++{ ++ int ret; ++ ++ if (ec_version_before("EC_VER=PQ1D27")) ++ vo_set_state(LCD, ON); ++ vo_set_state(CRT, ON); ++ usb_ports_set(ON); ++ ++ ret = sci_irq_init(); ++ if (ret) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend, ++ yeeloong_resume); ++#endif ++ ++static struct platform_device_id platform_device_ids[] = { ++ { ++ .name = "yeeloong_laptop", ++ }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(platform, platform_device_ids); ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "yeeloong_laptop", ++ .owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .pm = &yeeloong_pm_ops, ++#endif ++ }, ++ .id_table = platform_device_ids, ++}; ++ ++static int __init yeeloong_init(void) ++{ ++ int ret; ++ ++ pr_info("YeeLoong Laptop platform specific driver loaded.\n"); ++ ++ /* Register platform stuff */ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) { ++ pr_err("Failed to register YeeLoong platform driver.\n"); ++ return ret; ++ } ++ ++#define yeeloong_init_drv(drv, alias) do { \ ++ pr_info("Registered YeeLoong " alias " driver.\n"); \ ++ ret = yeeloong_ ## drv ## _init(); \ ++ if (ret) { \ ++ pr_err("Failed to register YeeLoong " alias " driver.\n"); \ ++ yeeloong_ ## drv ## _exit(); \ ++ return ret; \ ++ } \ ++} while (0) ++ ++ yeeloong_init_drv(backlight, "backlight"); ++ yeeloong_init_drv(bat, "battery and AC"); ++ yeeloong_init_drv(hwmon, "hardware monitor"); ++ yeeloong_init_drv(vo, "video output"); ++ yeeloong_init_drv(lcd, "lcd output"); ++ yeeloong_init_drv(hotkey, "hotkey input"); ++ ++ return 0; ++} ++ ++static void __exit yeeloong_exit(void) ++{ ++ yeeloong_hotkey_exit(); ++ yeeloong_lcd_exit(); ++ yeeloong_vo_exit(); ++ yeeloong_hwmon_exit(); ++ yeeloong_bat_exit(); ++ yeeloong_backlight_exit(); ++ platform_driver_unregister(&platform_driver); ++ ++ pr_info("YeeLoong platform specific driver unloaded.\n"); ++} ++ ++module_init(yeeloong_init); ++module_exit(yeeloong_exit); ++ ++MODULE_AUTHOR("Wu Zhangjin ; Liu Junliang "); ++MODULE_DESCRIPTION("YeeLoong laptop driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index b5b5c3d..f908003 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -727,6 +727,7 @@ comment "Platform RTC drivers" + config RTC_DRV_CMOS + tristate "PC-style 'CMOS'" + depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 ++ depends on !DEXXON_GDIUM + default y if X86 + help + Say "yes" here to get direct support for the real time clock +diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +index f940056..a9bb1db 100644 +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -450,6 +450,26 @@ void usb_amd_dev_put(void) + } + EXPORT_SYMBOL_GPL(usb_amd_dev_put); + ++#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) \ ++ || defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) ++static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) ++{ ++ u16 cmd; ++ return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); ++} ++ ++#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) ++#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) ++ ++static int mmio_resource_enabled(struct pci_dev *pdev, int idx) ++{ ++ return pci_resource_start(pdev, idx) && mmio_enabled(pdev); ++} ++#endif ++ ++#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE) + /* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. +@@ -531,15 +551,6 @@ reset_needed: + } + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + +-static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) +-{ +- u16 cmd; +- return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); +-} +- +-#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) +-#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) +- + static void quirk_usb_handoff_uhci(struct pci_dev *pdev) + { + unsigned long base = 0; +@@ -557,12 +568,11 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev) + if (base) + uhci_check_and_reset_hc(pdev, base); + } ++#else ++#define quirk_usb_handoff_uhci(x) do { } while (0) ++#endif /* CONFIG_USB_UHCI_HCD* */ + +-static int mmio_resource_enabled(struct pci_dev *pdev, int idx) +-{ +- return pci_resource_start(pdev, idx) && mmio_enabled(pdev); +-} +- ++#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + static void quirk_usb_handoff_ohci(struct pci_dev *pdev) + { + void __iomem *base; +@@ -641,7 +651,11 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev) + /* Now the controller is safely in SUSPEND and nothing can wake it up */ + iounmap(base); + } ++#else ++#define quirk_usb_handoff_ohci(x) do { } while(0) ++#endif /* CONFIG_USB_OHCI_HCD* */ + ++#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) + static const struct dmi_system_id ehci_dmi_nohandoff_table[] = { + { + /* Pegatron Lucid (ExoPC) */ +@@ -816,6 +830,9 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev) + + iounmap(base); + } ++#else ++#define quirk_usb_disable_ehci(x) do { } while (0) ++#endif /* CONFIG_USB_EHCI_HCD* */ + + /* + * handshake - spin reading a register until handshake completes +@@ -956,6 +973,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) + } + EXPORT_SYMBOL_GPL(usb_disable_xhci_ports); + ++#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE) + /** + * PCI Quirks for xHCI. + * +@@ -1064,6 +1082,9 @@ hc_init: + + iounmap(base); + } ++#else ++#define quirk_usb_handoff_xhci(x) do { } while (0) ++#endif /* CONFIG_USB_UHCI_HCD* */ + + static void quirk_usb_early_handoff(struct pci_dev *pdev) + { +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index f0c0c53..84dff90 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -79,6 +79,9 @@ static void option_instat_callback(struct urb *urb); + #define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 + #define OPTION_PRODUCT_GTM380_MODEM 0x7201 + ++#define HUAWO_VENDOR_ID 0x21F5 ++#define HUAWO_PRODUCT_E1621 0x2008 ++ + #define HUAWEI_VENDOR_ID 0x12D1 + #define HUAWEI_PRODUCT_E173 0x140C + #define HUAWEI_PRODUCT_E1750 0x1406 +@@ -633,6 +636,7 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, + { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, ++ { USB_DEVICE(HUAWO_VENDOR_ID, HUAWO_PRODUCT_E1621) }, /* QUANTA 6500 chips, Unicom extensive use of this card */ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) }, +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 8bf495f..f6a15b6 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -36,6 +36,12 @@ config VGASTATE + tristate + default n + ++config VIDEO_OUTPUT_CONTROL ++ tristate "Lowlevel video output switch controls" ++ help ++ This framework adds support for low-level control of the video ++ output switch. ++ + config VIDEOMODE_HELPERS + bool + +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 9ad3c17..3d869d9 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -7,6 +7,8 @@ obj-y += backlight/ + + obj-y += fbdev/ + ++#video output switch sysfs driver ++obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o + obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o + ifeq ($(CONFIG_OF),y) + obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o +diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig +index b3dd417..452035ad 100644 +--- a/drivers/video/fbdev/Kconfig ++++ b/drivers/video/fbdev/Kconfig +@@ -2450,6 +2450,19 @@ config FB_SIMPLE + Configuration re: surface address, size, and format must be provided + through device tree, or plain old platform data. + ++config FB_SM712 ++ tristate "Silicon Motion SM712 framebuffer support" ++ depends on FB && PCI ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ Frame buffer driver for the Silicon Motion SM712 chip. ++ ++ This driver is also available as a module. The module will be ++ called sm712fb. If you want to compile it as a module, say M ++ here and read . ++ + source "drivers/video/fbdev/omap/Kconfig" + source "drivers/video/fbdev/omap2/Kconfig" + source "drivers/video/fbdev/exynos/Kconfig" +diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile +index 1979aff..9b694f9 100644 +--- a/drivers/video/fbdev/Makefile ++++ b/drivers/video/fbdev/Makefile +@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o + obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o + obj-$(CONFIG_FB_PS3) += ps3fb.o + obj-$(CONFIG_FB_SM501) += sm501fb.o ++obj-$(CONFIG_FB_SM712) += sm712fb/ + obj-$(CONFIG_FB_UDL) += udlfb.o + obj-$(CONFIG_FB_SMSCUFX) += smscufx.o + obj-$(CONFIG_FB_XILINX) += xilinxfb.o +diff --git a/drivers/video/fbdev/sm712fb/Makefile b/drivers/video/fbdev/sm712fb/Makefile +new file mode 100644 +index 0000000..9bf3519 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_FB_SM712) += sm712fb.o ++ ++sm712fb-objs := sm712fb_drv.o sm712fb_accel.o +diff --git a/drivers/video/fbdev/sm712fb/TODO b/drivers/video/fbdev/sm712fb/TODO +new file mode 100644 +index 0000000..dcfd4e7 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/TODO +@@ -0,0 +1,7 @@ ++TODO: ++- Dual head support ++- refine the code, convert more registers magic numbers to macros ++- Does it really works on Big Endian machines? ++ ++Please send any patches to Greg Kroah-Hartman and ++Tom Li . +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.c b/drivers/video/fbdev/sm712fb/sm712fb_accel.c +new file mode 100644 +index 0000000..12fce1f +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.c +@@ -0,0 +1,246 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#include ++#include ++#include ++ ++#include "sm712fb_drv.h" ++#include "sm712fb_accel.h" ++ ++static inline u32 bytes_to_dword(const u8 *bytes, int length) ++{ ++ u32 dword = 0; ++ ++ switch (length) { ++ case 4: ++#ifdef __BIG_ENDIAN ++ dword += bytes[3]; ++#else ++ dword += bytes[3] << 24; ++#endif ++ case 3: ++#ifdef __BIG_ENDIAN ++ dword += bytes[2] << 8; ++#else ++ dword += bytes[2] << 16; ++#endif ++ case 2: ++#ifdef __BIG_ENDIAN ++ dword += bytes[1] << 16; ++#else ++ dword += bytes[1] << 8; ++#endif ++ case 1: ++#ifdef __BIG_ENDIAN ++ dword += bytes[0] << 24; ++#else ++ dword += bytes[0]; ++#endif ++ } ++ return dword; ++} ++ ++int sm712fb_init_accel(struct sm712fb_info *fb) ++{ ++ u8 reg; ++ ++ /* reset the 2D engine */ ++ sm712_write_seq(fb, 0x21, sm712_read_seq(fb, 0x21) & 0xf8); ++ reg = sm712_read_seq(fb, 0x15); ++ sm712_write_seq(fb, 0x15, reg | 0x30); ++ sm712_write_seq(fb, 0x15, reg); ++ ++ if (sm712fb_wait(fb) != 0) ++ return -1; ++ ++ sm712_write_dpr(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0)); ++ ++ /* same width for DPR_PITCH and DPR_SRC_WINDOW */ ++ sm712_write_dpr(fb, DPR_PITCH, ++ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); ++ sm712_write_dpr(fb, DPR_SRC_WINDOW, ++ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres)); ++ ++ sm712_write_dpr(fb, DPR_BYTE_BIT_MASK, 0xffffffff); ++ sm712_write_dpr(fb, DPR_COLOR_COMPARE_MASK, 0); ++ sm712_write_dpr(fb, DPR_COLOR_COMPARE, 0); ++ sm712_write_dpr(fb, DPR_SRC_BASE, 0); ++ sm712_write_dpr(fb, DPR_DST_BASE, 0); ++ sm712_read_dpr(fb, DPR_DST_BASE); ++ ++ return 0; ++} ++ ++int sm712fb_wait(struct sm712fb_info *fb) ++{ ++ int i; ++ u8 reg; ++ ++ for (i = 0; i < 10000; i++) { ++ reg = sm712_read_seq(fb, SCR_DE_STATUS); ++ if ((reg & SCR_DE_STATUS_MASK) == SCR_DE_ENGINE_IDLE) ++ return 0; ++ udelay(1); ++ } ++ return -EBUSY; ++} ++ ++void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ++{ ++ u32 width = rect->width, height = rect->height; ++ u32 dx = rect->dx, dy = rect->dy; ++ u32 color; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((rect->dx >= info->var.xres_virtual) || ++ (rect->dy >= info->var.yres_virtual)) ++ return; ++ ++ if (info->fix.visual == FB_VISUAL_TRUECOLOR || ++ info->fix.visual == FB_VISUAL_DIRECTCOLOR) ++ color = ((u32 *) (info->pseudo_palette))[rect->color]; ++ else ++ color = rect->color; ++ ++ sm712_write_dpr(sfb, DPR_FG_COLOR, color); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | ++ (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} ++ ++void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) ++{ ++ u32 sx = area->sx, sy = area->sy; ++ u32 dx = area->dx, dy = area->dy; ++ u32 height = area->height, width = area->width; ++ u32 direction; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((sx >= info->var.xres_virtual) || (sy >= info->var.yres_virtual)) ++ return; ++ ++ if (sy < dy || (sy == dy && sx <= dx)) { ++ sx += width - 1; ++ dx += width - 1; ++ sy += height - 1; ++ dy += height - 1; ++ direction = DE_CTRL_RTOL; ++ } else ++ direction = 0; ++ ++ sm712_write_dpr(sfb, DPR_SRC_COORDS, DPR_COORDS(sx, sy)); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_DE_CTRL, ++ DE_CTRL_START | DE_CTRL_ROP_ENABLE | direction | ++ (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} ++ ++void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image) ++{ ++ u32 dx = image->dx, dy = image->dy; ++ u32 width = image->width, height = image->height; ++ u32 fg_color, bg_color; ++ ++ struct sm712fb_info *sfb = info->par; ++ ++ u32 imgidx = 0; ++ u32 line = image->width >> 3; ++ ++ int i, j; ++ u32 total_bytes, total_dwords, remain_bytes; ++ ++ if (unlikely(info->state != FBINFO_STATE_RUNNING)) ++ return; ++ if ((image->dx >= info->var.xres_virtual) || ++ (image->dy >= info->var.yres_virtual)) ++ return; ++ ++ if (unlikely(image->depth != 1)) { ++ /* unsupported depth, fallback to draw Tux */ ++ cfb_imageblit(info, image); ++ return; ++ } ++ ++ if (info->fix.visual == FB_VISUAL_TRUECOLOR || ++ info->fix.visual == FB_VISUAL_DIRECTCOLOR) { ++ fg_color = ((u32 *) (info->pseudo_palette))[image->fg_color]; ++ bg_color = ((u32 *) (info->pseudo_palette))[image->bg_color]; ++ } else { ++ fg_color = image->fg_color; ++ bg_color = image->bg_color; ++ } ++ ++ /* total bytes we need to write */ ++ total_bytes = (width + 7) / 8; ++ ++ /* split the bytes into dwords and remainder bytes */ ++ total_dwords = (total_bytes & ~3) / 4; ++ remain_bytes = total_bytes & 3; ++ ++ sm712_write_dpr(sfb, DPR_SRC_COORDS, 0); ++ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); ++ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height)); ++ sm712_write_dpr(sfb, DPR_FG_COLOR, fg_color); ++ sm712_write_dpr(sfb, DPR_BG_COLOR, bg_color); ++ ++ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | ++ (DE_CTRL_COMMAND_HOST_WRITE << DE_CTRL_COMMAND_SHIFT) | ++ (DE_CTRL_HOST_MONO << DE_CTRL_HOST_SHIFT) | ++ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); ++ ++ for (i = 0; i < height; i++) { ++ /* cast bytes data into dwords and write to the dataport */ ++ for (j = 0; j < total_dwords; j++) { ++ sm712_write_dataport(sfb, ++ bytes_to_dword(&image-> ++ data[imgidx] + ++ j * 4, 4)); ++ } ++ ++ if (remain_bytes) { ++ sm712_write_dataport(sfb, ++ bytes_to_dword(&image-> ++ data[imgidx] + ++ (total_dwords * 4), ++ remain_bytes)); ++ } ++ imgidx += line; ++ } ++ sm712_read_dpr(sfb, DPR_DE_CTRL); ++ sm712fb_wait(sfb); ++} +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.h b/drivers/video/fbdev/sm712fb/sm712fb_accel.h +new file mode 100644 +index 0000000..6f79177 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.h +@@ -0,0 +1,33 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#ifndef _SM712FB_ACCEL_H ++#define _SM712FB_ACCEL_H ++ ++int sm712fb_init_accel(struct sm712fb_info *fb); ++int sm712fb_wait(struct sm712fb_info *fb); ++void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); ++void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area); ++void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image); ++ ++#endif +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.c b/drivers/video/fbdev/sm712fb/sm712fb_drv.c +new file mode 100644 +index 0000000..7f7cd4f +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.c +@@ -0,0 +1,1022 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PM ++#include ++#endif ++ ++#include "sm712fb_drv.h" ++#include "sm712fb_accel.h" ++#include "sm712fb_modedb.h" ++ ++static struct fb_var_screeninfo sm712fb_var = { ++ .xres = 1024, ++ .yres = 600, ++ .xres_virtual = 1024, ++ .yres_virtual = 600, ++ .bits_per_pixel = 16, ++ .red = {16, 8, 0}, ++ .green = {8, 8, 0}, ++ .blue = {0, 8, 0}, ++ .activate = FB_ACTIVATE_NOW, ++ .height = -1, ++ .width = -1, ++ .vmode = FB_VMODE_NONINTERLACED, ++ .nonstd = 0, ++ .accel_flags = FB_ACCELF_TEXT, ++}; ++ ++static struct fb_fix_screeninfo sm712fb_fix = { ++ .id = "smXXXfb", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .line_length = 800 * 3, ++ .accel = FB_ACCEL_SMI_LYNX, ++ .type_aux = 0, ++ .xpanstep = 0, ++ .ypanstep = 0, ++ .ywrapstep = 0, ++}; ++ ++struct vesa_mode { ++ char index[6]; ++ u16 lfb_width; ++ u16 lfb_height; ++ u16 lfb_depth; ++}; ++ ++static bool accel = 1; ++ ++static struct vesa_mode vesa_mode_table[] = { ++ {"0x301", 640, 480, 8}, ++ {"0x303", 800, 600, 8}, ++ {"0x305", 1024, 768, 8}, ++ {"0x307", 1280, 1024, 8}, ++ ++ {"0x311", 640, 480, 16}, ++ {"0x314", 800, 600, 16}, ++ {"0x317", 1024, 768, 16}, ++ {"0x31A", 1280, 1024, 16}, ++ ++ {"0x312", 640, 480, 24}, ++ {"0x315", 800, 600, 24}, ++ {"0x318", 1024, 768, 24}, ++ {"0x31B", 1280, 1024, 24}, ++}; ++ ++struct screen_info sm712_scr_info; ++ ++static int sm712fb_setup(char *options) ++{ ++ char *this_opt; ++ ++ if (!options || !*options) ++ return 0; ++ ++ while ((this_opt = strsep(&options, ",")) != NULL) { ++ if (!*this_opt) ++ continue; ++ ++ if (!strcmp(this_opt, "accel:0")) ++ accel = false; ++ else if (!strcmp(this_opt, "accel:1")) ++ accel = true; ++ } ++ return 0; ++} ++ ++/* process command line options, get vga parameter */ ++static int __init sm712_vga_setup(char *options) ++{ ++ int i; ++ ++ if (!options || !*options) ++ return -EINVAL; ++ ++ sm712_scr_info.lfb_width = 0; ++ sm712_scr_info.lfb_height = 0; ++ sm712_scr_info.lfb_depth = 0; ++ ++ pr_debug("sm712_vga_setup = %s\n", options); ++ ++ for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { ++ if (strstr(options, vesa_mode_table[i].index)) { ++ sm712_scr_info.lfb_width = vesa_mode_table[i].lfb_width; ++ sm712_scr_info.lfb_height = ++ vesa_mode_table[i].lfb_height; ++ sm712_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; ++ return 0; ++ } ++ } ++ ++ return -1; ++} ++ ++__setup("vga=", sm712_vga_setup); ++ ++static void sm712_setpalette(int regno, unsigned red, unsigned green, ++ unsigned blue, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb = info->par; ++ ++ /* set bit 5:4 = 01 (write LCD RAM only) */ ++ sm712_write_seq(sfb, 0x66, (sm712_read_seq(sfb, 0x66) & 0xC3) | 0x10); ++ ++ sm712_writeb(sfb->mmio, DAC_REG, regno); ++ sm712_writeb(sfb->mmio, DAC_VAL, red >> 10); ++ sm712_writeb(sfb->mmio, DAC_VAL, green >> 10); ++ sm712_writeb(sfb->mmio, DAC_VAL, blue >> 10); ++} ++ ++/* chan_to_field ++ * ++ * convert a colour value into a field position ++ * ++ * from pxafb.c ++ */ ++ ++static inline unsigned int chan_to_field(unsigned int chan, ++ struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++static int sm712_blank(int blank_mode, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb = info->par; ++ ++ /* clear DPMS setting */ ++ switch (blank_mode) { ++ case FB_BLANK_UNBLANK: ++ /* Screen On: HSync: On, VSync : On */ ++ sm712_write_seq(sfb, 0x01, ++ (sm712_read_seq(sfb, 0x01) & (~0x20))); ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) & 0x77)); ++ sm712_write_seq(sfb, 0x22, ++ (sm712_read_seq(sfb, 0x22) & (~0x30))); ++ sm712_write_seq(sfb, 0x23, ++ (sm712_read_seq(sfb, 0x23) & (~0xc0))); ++ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); ++ sm712_write_seq(sfb, 0x31, (sm712_read_seq(sfb, 0x31) | 0x03)); ++ break; ++ case FB_BLANK_NORMAL: ++ /* Screen Off: HSync: On, VSync : On Soft blank */ ++ sm712_write_seq(sfb, 0x01, ++ (sm712_read_seq(sfb, 0x01) & (~0x20))); ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x22, ++ (sm712_read_seq(sfb, 0x22) & (~0x30))); ++ sm712_write_seq(sfb, 0x23, ++ (sm712_read_seq(sfb, 0x23) & (~0xc0))); ++ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01)); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ break; ++ case FB_BLANK_VSYNC_SUSPEND: ++ /* Screen On: HSync: On, VSync : Off */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x0c); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x20)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0x20)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ case FB_BLANK_HSYNC_SUSPEND: ++ /* Screen On: HSync: Off, VSync : On */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x0c); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x10)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ case FB_BLANK_POWERDOWN: ++ /* Screen On: HSync: Off, VSync : Off */ ++ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20)); ++ sm712_write_seq(sfb, 0x20, ++ (sm712_read_seq(sfb, 0x20) & (~0xB0))); ++ sm712_write_seq(sfb, 0x6a, 0x5a); ++ sm712_write_seq(sfb, 0x6b, 0x20); ++ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88)); ++ sm712_write_seq(sfb, 0x22, ++ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x30)); ++ sm712_write_seq(sfb, 0x23, ++ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8)); ++ sm712_write_seq(sfb, 0x24, ++ (sm712_read_seq(sfb, 0x24) & (~0x01))); ++ sm712_write_seq(sfb, 0x31, ++ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00)); ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int sm712_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned trans, struct fb_info *info) ++{ ++ struct sm712fb_info *sfb; ++ u32 val; ++ ++ sfb = info->par; ++ ++ if (regno > 255) ++ return 1; ++ ++ switch (sfb->fb.fix.visual) { ++ case FB_VISUAL_DIRECTCOLOR: ++ case FB_VISUAL_TRUECOLOR: ++ /* ++ * 16/32 bit true-colour, use pseudo-palette for 16 base color ++ */ ++ if (regno < 16) { ++ if (sfb->fb.var.bits_per_pixel == 16) { ++ u32 *pal = sfb->fb.pseudo_palette; ++ ++ val = chan_to_field(red, &sfb->fb.var.red); ++ val |= chan_to_field(green, &sfb->fb.var.green); ++ val |= chan_to_field(blue, &sfb->fb.var.blue); ++#ifdef __BIG_ENDIAN ++ pal[regno] = ++ ((red & 0xf800) >> 8) | ++ ((green & 0xe000) >> 13) | ++ ((green & 0x1c00) << 3) | ++ ((blue & 0xf800) >> 3); ++#else ++ pal[regno] = val; ++#endif ++ } else { ++ u32 *pal = sfb->fb.pseudo_palette; ++ ++ val = chan_to_field(red, &sfb->fb.var.red); ++ val |= chan_to_field(green, &sfb->fb.var.green); ++ val |= chan_to_field(blue, &sfb->fb.var.blue); ++#ifdef __BIG_ENDIAN ++ val = ++ (val & 0xff00ff00 >> 8) | ++ (val & 0x00ff00ff << 8); ++#endif ++ pal[regno] = val; ++ } ++ } ++ break; ++ ++ case FB_VISUAL_PSEUDOCOLOR: ++ /* color depth 8 bit */ ++ sm712_setpalette(regno, red, green, blue, info); ++ break; ++ ++ default: ++ return 1; /* unknown type */ ++ } ++ ++ return 0; ++ ++} ++ ++#ifdef __BIG_ENDIAN ++static ssize_t sm712fb_read(struct fb_info *info, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ ++ u32 *buffer, *dst; ++ u32 __iomem *src; ++ int c, i, cnt = 0, err = 0; ++ unsigned long total_size; ++ ++ if (!info || !info->screen_base) ++ return -ENODEV; ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return -EPERM; ++ ++ total_size = info->screen_size; ++ ++ if (total_size == 0) ++ total_size = info->fix.smem_len; ++ ++ if (p >= total_size) ++ return 0; ++ ++ if (count >= total_size) ++ count = total_size; ++ ++ if (count + p > total_size) ++ count = total_size - p; ++ ++ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ src = (u32 __iomem *) (info->screen_base + p); ++ ++ if (info->fbops->fb_sync) ++ info->fbops->fb_sync(info); ++ ++ while (count) { ++ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; ++ dst = buffer; ++ for (i = c >> 2; i--;) { ++ *dst = fb_readl(src++); ++ *dst = ++ (*dst & 0xff00ff00 >> 8) | (*dst & 0x00ff00ff << 8); ++ dst++; ++ } ++ if (c & 3) { ++ u8 *dst8 = (u8 *) dst; ++ u8 __iomem *src8 = (u8 __iomem *) src; ++ ++ for (i = c & 3; i--;) { ++ if (i & 1) { ++ *dst8++ = fb_readb(++src8); ++ } else { ++ *dst8++ = fb_readb(--src8); ++ src8 += 2; ++ } ++ } ++ src = (u32 __iomem *) src8; ++ } ++ ++ if (copy_to_user(buf, buffer, c)) { ++ err = -EFAULT; ++ break; ++ } ++ *ppos += c; ++ buf += c; ++ cnt += c; ++ count -= c; ++ } ++ ++ kfree(buffer); ++ ++ return (err) ? err : cnt; ++} ++ ++static ssize_t ++sm712fb_write(struct fb_info *info, const char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ ++ u32 *buffer, *src; ++ u32 __iomem *dst; ++ int c, i, cnt = 0, err = 0; ++ unsigned long total_size; ++ ++ if (!info || !info->screen_base) ++ return -ENODEV; ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return -EPERM; ++ ++ total_size = info->screen_size; ++ ++ if (total_size == 0) ++ total_size = info->fix.smem_len; ++ ++ if (p > total_size) ++ return -EFBIG; ++ ++ if (count > total_size) { ++ err = -EFBIG; ++ count = total_size; ++ } ++ ++ if (count + p > total_size) { ++ if (!err) ++ err = -ENOSPC; ++ ++ count = total_size - p; ++ } ++ ++ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ dst = (u32 __iomem *) (info->screen_base + p); ++ ++ if (info->fbops->fb_sync) ++ info->fbops->fb_sync(info); ++ ++ while (count) { ++ c = (count > PAGE_SIZE) ? PAGE_SIZE : count; ++ src = buffer; ++ ++ if (copy_from_user(src, buf, c)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ for (i = c >> 2; i--;) { ++ fb_writel((*src & 0xff00ff00 >> 8) | ++ (*src & 0x00ff00ff << 8), dst++); ++ src++; ++ } ++ if (c & 3) { ++ u8 *src8 = (u8 *) src; ++ u8 __iomem *dst8 = (u8 __iomem *) dst; ++ ++ for (i = c & 3; i--;) { ++ if (i & 1) { ++ fb_writeb(*src8++, ++dst8); ++ } else { ++ fb_writeb(*src8++, --dst8); ++ dst8 += 2; ++ } ++ } ++ dst = (u32 __iomem *) dst8; ++ } ++ ++ *ppos += c; ++ buf += c; ++ cnt += c; ++ count -= c; ++ } ++ ++ kfree(buffer); ++ ++ return (cnt) ? cnt : err; ++} ++#endif /* ! __BIG_ENDIAN */ ++ ++static void sm712_set_timing(struct sm712fb_info *sfb) ++{ ++ int i = 0, j = 0; ++ u32 m_nScreenStride; ++ ++ dev_dbg(&sfb->pdev->dev, ++ "sfb->width=%d sfb->height=%d " ++ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n", ++ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz); ++ ++ for (j = 0; j < numVGAModes; j++) { ++ if (VGAMode[j].mmSizeX != sfb->width || ++ VGAMode[j].mmSizeY != sfb->height || ++ VGAMode[j].bpp != sfb->fb.var.bits_per_pixel || ++ VGAMode[j].hz != sfb->hz) { ++ continue; ++ } ++ ++ dev_dbg(&sfb->pdev->dev, ++ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d " ++ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n", ++ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, ++ VGAMode[j].bpp, VGAMode[j].hz); ++ ++ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j); ++ ++ sm712_writeb(sfb->mmio, 0x3c6, 0x0); ++ ++ sm712_write_seq(sfb, 0, 0x1); ++ ++ sm712_writeb(sfb->mmio, 0x3c2, VGAMode[j].Init_MISC); ++ ++ /* init SEQ register SR00 - SR04 */ ++ for (i = 0; i < SR00_SR04_SIZE; i++) ++ sm712_write_seq(sfb, i, VGAMode[j].Init_SR00_SR04[i]); ++ ++ /* init SEQ register SR10 - SR24 */ ++ for (i = 0; i < SR10_SR24_SIZE; i++) ++ sm712_write_seq(sfb, i + 0x10, ++ VGAMode[j].Init_SR10_SR24[i]); ++ ++ /* init SEQ register SR30 - SR75 */ ++ for (i = 0; i < SR30_SR75_SIZE; i++) ++ if ((i + 0x30) != 0x62 && ++ (i + 0x30) != 0x6a && (i + 0x30) != 0x6b) ++ sm712_write_seq(sfb, i + 0x30, ++ VGAMode[j].Init_SR30_SR75[i]); ++ ++ /* init SEQ register SR80 - SR93 */ ++ for (i = 0; i < SR80_SR93_SIZE; i++) ++ sm712_write_seq(sfb, i + 0x80, ++ VGAMode[j].Init_SR80_SR93[i]); ++ ++ /* init SEQ register SRA0 - SRAF */ ++ for (i = 0; i < SRA0_SRAF_SIZE; i++) ++ sm712_write_seq(sfb, i + 0xa0, ++ VGAMode[j].Init_SRA0_SRAF[i]); ++ ++ /* init Graphic register GR00 - GR08 */ ++ for (i = 0; i < GR00_GR08_SIZE; i++) ++ sm712_write_grph(sfb, i, VGAMode[j].Init_GR00_GR08[i]); ++ ++ /* init Attribute register AR00 - AR14 */ ++ for (i = 0; i < AR00_AR14_SIZE; i++) ++ sm712_write_attr(sfb, i, VGAMode[j].Init_AR00_AR14[i]); ++ ++ /* init CRTC register CR00 - CR18 */ ++ for (i = 0; i < CR00_CR18_SIZE; i++) ++ sm712_write_crtc(sfb, i, VGAMode[j].Init_CR00_CR18[i]); ++ ++ /* init CRTC register CR30 - CR4D */ ++ for (i = 0; i < CR30_CR4D_SIZE; i++) ++ sm712_write_crtc(sfb, i + 0x30, ++ VGAMode[j].Init_CR30_CR4D[i]); ++ ++ /* init CRTC register CR90 - CRA7 */ ++ for (i = 0; i < CR90_CRA7_SIZE; i++) ++ sm712_write_crtc(sfb, i + 0x90, ++ VGAMode[j].Init_CR90_CRA7[i]); ++ } ++ sm712_writeb(sfb->mmio, 0x3c2, 0x67); ++ ++ /* set VPR registers */ ++ sm712_writel(sfb->vpr, 0x0C, 0x0); ++ sm712_writel(sfb->vpr, 0x40, 0x0); ++ ++ /* set data width */ ++ m_nScreenStride = (sfb->width * sfb->fb.var.bits_per_pixel) / 64; ++ switch (sfb->fb.var.bits_per_pixel) { ++ case 8: ++ sm712_writel(sfb->vpr, 0x0, 0x0); ++ break; ++ case 16: ++ sm712_writel(sfb->vpr, 0x0, 0x00020000); ++ break; ++ case 24: ++ sm712_writel(sfb->vpr, 0x0, 0x00040000); ++ break; ++ case 32: ++ sm712_writel(sfb->vpr, 0x0, 0x00030000); ++ break; ++ } ++ sm712_writel(sfb->vpr, 0x10, ++ (u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride)); ++} ++ ++static void sm712fb_setmode(struct sm712fb_info *sfb) ++{ ++ switch (sfb->fb.var.bits_per_pixel) { ++ case 32: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 4; ++ sfb->fb.var.red.length = 8; ++ sfb->fb.var.green.length = 8; ++ sfb->fb.var.blue.length = 8; ++ sfb->fb.var.red.offset = 16; ++ sfb->fb.var.green.offset = 8; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 24: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 3; ++ sfb->fb.var.red.length = 8; ++ sfb->fb.var.green.length = 8; ++ sfb->fb.var.blue.length = 8; ++ sfb->fb.var.red.offset = 16; ++ sfb->fb.var.green.offset = 8; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 8: ++ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres; ++ sfb->fb.var.red.length = 3; ++ sfb->fb.var.green.length = 3; ++ sfb->fb.var.blue.length = 2; ++ sfb->fb.var.red.offset = 5; ++ sfb->fb.var.green.offset = 2; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ case 16: ++ default: ++ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ sfb->fb.fix.line_length = sfb->fb.var.xres * 2; ++ sfb->fb.var.red.length = 5; ++ sfb->fb.var.green.length = 6; ++ sfb->fb.var.blue.length = 5; ++ sfb->fb.var.red.offset = 11; ++ sfb->fb.var.green.offset = 5; ++ sfb->fb.var.blue.offset = 0; ++ break; ++ } ++ ++ sfb->width = sfb->fb.var.xres; ++ sfb->height = sfb->fb.var.yres; ++ sfb->hz = 60; ++ sm712_set_timing(sfb); ++} ++ ++static int sm712_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ /* sanity checks */ ++ if (var->xres_virtual < var->xres) ++ var->xres_virtual = var->xres; ++ ++ if (var->yres_virtual < var->yres) ++ var->yres_virtual = var->yres; ++ ++ /* set valid default bpp */ ++ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && ++ (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) ++ var->bits_per_pixel = 16; ++ ++ return 0; ++} ++ ++static int sm712_set_par(struct fb_info *info) ++{ ++ sm712fb_setmode(info->par); ++ ++ return 0; ++} ++ ++static struct fb_ops sm712fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = sm712_check_var, ++ .fb_set_par = sm712_set_par, ++ .fb_setcolreg = sm712_setcolreg, ++ .fb_blank = sm712_blank, ++ .fb_fillrect = cfb_fillrect, ++ .fb_imageblit = cfb_imageblit, ++ .fb_copyarea = cfb_copyarea, ++#ifdef __BIG_ENDIAN ++ .fb_read = sm712fb_read, ++ .fb_write = sm712fb_write, ++#endif ++}; ++ ++/* ++ * alloc struct sm712fb_info and assign default values ++ */ ++static struct sm712fb_info *sm712_fb_info_new(struct pci_dev *pdev) ++{ ++ struct sm712fb_info *sfb; ++ ++ sfb = kzalloc(sizeof(*sfb), GFP_KERNEL); ++ ++ if (!sfb) ++ return NULL; ++ ++ sfb->pdev = pdev; ++ ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT; ++ sfb->fb.fbops = &sm712fb_ops; ++ sfb->fb.fix = sm712fb_fix; ++ sfb->fb.var = sm712fb_var; ++ sfb->fb.pseudo_palette = sfb->colreg; ++ sfb->fb.par = sfb; ++ sfb->accel = accel; ++ ++ return sfb; ++} ++ ++/* ++ * free struct sm712fb_info ++ */ ++static void sm712_fb_info_free(struct sm712fb_info *sfb) ++{ ++ kfree(sfb); ++} ++ ++/* ++ * Map in the screen memory ++ */ ++ ++static int sm712_map_smem(struct sm712fb_info *sfb, ++ struct pci_dev *pdev, u_long smem_len) ++{ ++ ++ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); ++ ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 32) ++ sfb->fb.fix.smem_start += 0x800000; ++#endif ++ ++ sfb->fb.fix.smem_len = smem_len; ++ ++ sfb->fb.screen_base = sfb->lfb; ++ ++ if (!sfb->fb.screen_base) { ++ dev_err(&pdev->dev, ++ "%s: unable to map screen memory\n", sfb->fb.fix.id); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Unmap in the screen memory ++ * ++ */ ++static void sm712_unmap_smem(struct sm712fb_info *sfb) ++{ ++ if (sfb && sfb->fb.screen_base) { ++ iounmap(sfb->fb.screen_base); ++ sfb->fb.screen_base = NULL; ++ sfb->lfb = NULL; ++ } ++} ++ ++static inline void sm712_init_hw(struct sm712fb_info *sfb) ++{ ++ /* enable linear memory mode and packed pixel format */ ++ outb_p(0x18, 0x3c4); ++ outb_p(0x11, 0x3c5); ++ ++ /* set MCLK = 14.31818 * (0x16 / 0x2) */ ++ sm712_write_seq(sfb, 0x6a, 0x16); ++ sm712_write_seq(sfb, 0x6b, 0x02); ++ sm712_write_seq(sfb, 0x62, 0x3e); ++ ++ /* enable PCI burst */ ++ sm712_write_seq(sfb, 0x17, 0x20); ++ ++#ifdef __BIG_ENDIAN ++ /* enable word swap */ ++ if (sfb->fb.var.bits_per_pixel == 32) ++ sm712_write_seq(sfb, 0x17, 0x30); ++#endif ++ ++ if (!sfb->accel) { ++ dev_info(&sfb->pdev->dev, "2d acceleration was disabled by user.\n"); ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; ++ return; ++ } ++ ++ if (sm712fb_init_accel(sfb) < 0) { ++ dev_info(&sfb->pdev->dev, "failed to enable 2d accleration.\n"); ++ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE; ++ return; ++ } else { ++ sm712fb_ops.fb_fillrect = sm712fb_fillrect; ++ sm712fb_ops.fb_copyarea = sm712fb_copyarea; ++ sm712fb_ops.fb_imageblit = sm712fb_imageblit; ++ sfb->fb.flags |= FBINFO_HWACCEL_COPYAREA | ++ FBINFO_HWACCEL_FILLRECT | ++ FBINFO_HWACCEL_IMAGEBLIT | ++ FBINFO_READS_FAST; ++ dev_info(&sfb->pdev->dev, "sm712fb: enable 2d acceleration.\n"); ++ } ++} ++ ++static int sm712fb_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct sm712fb_info *sfb; ++ int err; ++ unsigned long mmio_base; ++ ++#ifndef MODULE ++ char *option = NULL; ++ ++ if (!fb_get_options("sm712fb", &option)) ++ sm712fb_setup(option); ++#endif ++ ++ dev_info(&pdev->dev, "Silicon Motion display driver."); ++ ++ err = pci_enable_device(pdev); /* enable SMTC chip */ ++ if (err) ++ return err; ++ ++ sprintf(sm712fb_fix.id, "sm712fb"); ++ ++ sfb = sm712_fb_info_new(pdev); ++ ++ if (!sfb) { ++ err = -ENOMEM; ++ goto free_fail; ++ } ++ ++ sfb->chip_id = ent->device; ++ ++ pci_set_drvdata(pdev, sfb); ++ ++ /* get mode parameter from sm712_scr_info */ ++ if (sm712_scr_info.lfb_width != 0) { ++ sfb->fb.var.xres = sm712_scr_info.lfb_width; ++ sfb->fb.var.yres = sm712_scr_info.lfb_height; ++ sfb->fb.var.bits_per_pixel = sm712_scr_info.lfb_depth; ++ } else { ++ /* default resolution 1024x600 16bit mode */ ++ sfb->fb.var.xres = SM712_DEFAULT_XRES; ++ sfb->fb.var.yres = SM712_DEFAULT_YRES; ++ sfb->fb.var.bits_per_pixel = SM712_DEFAULT_BPP; ++ } ++ ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 24) ++ sfb->fb.var.bits_per_pixel = (sm712_scr_info.lfb_depth = 32); ++#endif ++ ++ /* Map address and memory detection */ ++ mmio_base = pci_resource_start(pdev, 0); ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); ++ ++ if (sfb->chip_id != 0x712) { ++ dev_err(&pdev->dev, ++ "No valid Silicon Motion display chip was detected!"); ++ ++ goto fb_fail; ++ } ++ ++ sfb->fb.fix.mmio_start = mmio_base + SM712_REG_BASE; ++ sfb->fb.fix.mmio_len = SM712_REG_SIZE; ++#ifdef __BIG_ENDIAN ++ sfb->lfb = ioremap(mmio_base, 0x00c00000); ++#else ++ sfb->lfb = ioremap(mmio_base, 0x00800000); ++#endif ++ sfb->mmio = sfb->lfb + SM712_MMIO_BASE; ++ sfb->dpr = sfb->lfb + SM712_DPR_BASE; ++ sfb->vpr = sfb->lfb + SM712_VPR_BASE; ++ sfb->dataport = sfb->lfb + SM712_DATAPORT_BASE; ++#ifdef __BIG_ENDIAN ++ if (sfb->fb.var.bits_per_pixel == 32) { ++ sfb->lfb += 0x800000; ++ dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb); ++ } ++#endif ++ if (!sfb->mmio) { ++ dev_err(&pdev->dev, ++ "%s: unable to map memory mapped IO!", sfb->fb.fix.id); ++ err = -ENOMEM; ++ goto fb_fail; ++ } ++ ++ sm712_init_hw(sfb); ++ ++ /* can support 32 bpp */ ++ if (15 == sfb->fb.var.bits_per_pixel) ++ sfb->fb.var.bits_per_pixel = 16; ++ ++ sfb->fb.var.xres_virtual = sfb->fb.var.xres; ++ sfb->fb.var.yres_virtual = sfb->fb.var.yres; ++ err = sm712_map_smem(sfb, pdev, SM712_VRAM_SIZE); ++ if (err) ++ goto fail; ++ ++ sm712fb_setmode(sfb); ++ ++ err = register_framebuffer(&sfb->fb); ++ if (err < 0) ++ goto fail; ++ ++ dev_info(&pdev->dev, ++ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.", ++ sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres, ++ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); ++ ++ return 0; ++ ++fail: ++ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail."); ++ ++ sm712_unmap_smem(sfb); ++fb_fail: ++ sm712_fb_info_free(sfb); ++free_fail: ++ pci_disable_device(pdev); ++ ++ return err; ++} ++ ++/* ++ * 0x712 (LynxEM+) ++ */ ++static const struct pci_device_id sm712fb_pci_table[] = { ++ {PCI_DEVICE(0x126f, 0x712),}, ++ {0,} ++}; ++ ++static void sm712fb_pci_remove(struct pci_dev *pdev) ++{ ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ sm712_unmap_smem(sfb); ++ unregister_framebuffer(&sfb->fb); ++ sm712_fb_info_free(sfb); ++} ++ ++#ifdef CONFIG_PM ++static int sm712fb_pci_suspend(struct device *device) ++{ ++ struct pci_dev *pdev = to_pci_dev(device); ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ ++ /* set the hw in sleep mode use external clock and self memory refresh ++ * so that we can turn off internal PLLs later on ++ */ ++ sm712_write_seq(sfb, 0x20, (sm712_read_seq(sfb, 0x20) | 0xc0)); ++ sm712_write_seq(sfb, 0x69, (sm712_read_seq(sfb, 0x69) & 0xf7)); ++ ++ console_lock(); ++ fb_set_suspend(&sfb->fb, 1); ++ console_unlock(); ++ ++ /* additionally turn off all function blocks including internal PLLs */ ++ sm712_write_seq(sfb, 0x21, 0xff); ++ ++ return 0; ++} ++ ++static int sm712fb_pci_resume(struct device *device) ++{ ++ struct pci_dev *pdev = to_pci_dev(device); ++ struct sm712fb_info *sfb; ++ ++ sfb = pci_get_drvdata(pdev); ++ ++ /* reinit hardware */ ++ sm712_init_hw(sfb); ++ ++ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0xc0)); ++ sm712_write_seq(sfb, 0x33, ((sm712_read_seq(sfb, 0x33) | 0x08) & 0xfb)); ++ ++ sm712fb_setmode(sfb); ++ ++ console_lock(); ++ fb_set_suspend(&sfb->fb, 0); ++ console_unlock(); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(sm712_pm_ops, sm712fb_pci_suspend, sm712fb_pci_resume); ++#define SM712_PM_OPS (&sm712_pm_ops) ++ ++#else /* !CONFIG_PM */ ++ ++#define SM712_PM_OPS NULL ++ ++#endif /* !CONFIG_PM */ ++ ++static struct pci_driver sm712fb_driver = { ++ .name = "sm712fb", ++ .id_table = sm712fb_pci_table, ++ .probe = sm712fb_pci_probe, ++ .remove = sm712fb_pci_remove, ++ .driver.pm = SM712_PM_OPS, ++}; ++ ++module_pci_driver(sm712fb_driver); ++ ++module_param(accel, bool, S_IRUGO); ++MODULE_PARM_DESC(accel, "Enable or disable 2D Acceleration"); ++ ++MODULE_AUTHOR("Siliconmotion "); ++MODULE_DESCRIPTION("Framebuffer driver for Silicon Motion SM712 Graphic Cards"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.h b/drivers/video/fbdev/sm712fb/sm712fb_drv.h +new file mode 100644 +index 0000000..bf81bff +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.h +@@ -0,0 +1,130 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Framebuffer driver for Silicon Motion SM712 chip ++ */ ++ ++#ifndef _SM712FB_DRV_H ++#define _SM712FB_DRV_H ++ ++/* ++* Private structure ++*/ ++struct sm712fb_info { ++ struct pci_dev *pdev; ++ struct fb_info fb; ++ u16 chip_id; ++ u8 chip_rev_id; ++ ++ void __iomem *lfb; /* linear frame buffer, the base address */ ++ ++ void __iomem *dpr; /* drawing processor control regs */ ++ void __iomem *vpr; /* video processor control regs */ ++ void __iomem *cpr; /* capture processor control regs */ ++ void __iomem *mmio; /* memory map IO port */ ++ void __iomem *dataport; /* 2d drawing engine data port */ ++ ++ u_int width; ++ u_int height; ++ u_int hz; ++ ++ u32 colreg[17]; ++ ++ bool accel; ++}; ++ ++/* constants for registers operations */ ++ ++#include "sm712fb_io.h" ++ ++#define FB_ACCEL_SMI_LYNX 88 ++ ++#define SM712_DEFAULT_XRES 1024 ++#define SM712_DEFAULT_YRES 600 ++#define SM712_DEFAULT_BPP 16 ++ ++#define SM712_VRAM_SIZE 0x00400000 ++ ++#define SM712_REG_BASE 0x00400000 ++#define SM712_REG_SIZE 0x00400000 ++ ++#define SM712_MMIO_BASE 0x00700000 ++ ++#define SM712_DPR_BASE 0x00408000 ++#define SM712_DPR_SIZE (0x6C + 1) ++ ++#define DPR_COORDS(x, y) (((x) << 16) | (y)) ++ ++#define DPR_SRC_COORDS 0x00 ++#define DPR_DST_COORDS 0x04 ++#define DPR_SPAN_COORDS 0x08 ++#define DPR_DE_CTRL 0x0c ++#define DPR_PITCH 0x10 ++#define DPR_FG_COLOR 0x14 ++#define DPR_BG_COLOR 0x18 ++#define DPR_STRETCH 0x1c ++#define DPR_COLOR_COMPARE 0x20 ++#define DPR_COLOR_COMPARE_MASK 0x24 ++#define DPR_BYTE_BIT_MASK 0x28 ++#define DPR_CROP_TOPLEFT_COORDS 0x2c ++#define DPR_CROP_BOTRIGHT_COORDS 0x30 ++#define DPR_SRC_WINDOW 0x3c ++#define DPR_SRC_BASE 0x40 ++#define DPR_DST_BASE 0x44 ++ ++#define DE_CTRL_START 0x80000000 ++#define DE_CTRL_RTOL 0x08000000 ++#define DE_CTRL_COMMAND_MASK 0x001f0000 ++#define DE_CTRL_COMMAND_SHIFT 16 ++#define DE_CTRL_COMMAND_BITBLT 0x00 ++#define DE_CTRL_COMMAND_SOLIDFILL 0x01 ++#define DE_CTRL_COMMAND_HOST_WRITE 0x08 ++#define DE_CTRL_ROP_ENABLE 0x00008000 ++#define DE_CTRL_ROP_MASK 0x000000ff ++#define DE_CTRL_ROP_SHIFT 0 ++#define DE_CTRL_ROP_SRC 0x0c ++ ++#define DE_CTRL_HOST_SHIFT 22 ++#define DE_CTRL_HOST_MONO 1 ++ ++#define SCR_DE_STATUS 0x16 ++#define SCR_DE_STATUS_MASK 0x18 ++#define SCR_DE_ENGINE_IDLE 0x10 ++ ++#define SM712_VPR_BASE 0x0040c000 ++#define SM712_VPR_SIZE (0x44 + 1) ++ ++#define SM712_DATAPORT_BASE 0x00400000 ++ ++#define SR00_SR04_SIZE (0x04 - 0x00 + 1) ++#define SR10_SR24_SIZE (0x24 - 0x10 + 1) ++#define SR30_SR75_SIZE (0x75 - 0x30 + 1) ++#define SR80_SR93_SIZE (0x93 - 0x80 + 1) ++#define SRA0_SRAF_SIZE (0xAF - 0xA0 + 1) ++#define GR00_GR08_SIZE (0x08 - 0x00 + 1) ++#define AR00_AR14_SIZE (0x14 - 0x00 + 1) ++#define CR00_CR18_SIZE (0x18 - 0x00 + 1) ++#define CR30_CR4D_SIZE (0x4D - 0x30 + 1) ++#define CR90_CRA7_SIZE (0xA7 - 0x90 + 1) ++ ++#define DAC_REG (0x3c8) ++#define DAC_VAL (0x3c9) ++ ++#endif +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_io.h b/drivers/video/fbdev/sm712fb/sm712fb_io.h +new file mode 100644 +index 0000000..93346a0 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_io.h +@@ -0,0 +1,90 @@ ++/* ++ * Silicon Motion SM712 frame buffer device ++ * ++ * Copyright (C) 2006 Silicon Motion Technology Corp. ++ * Authors: Ge Wang, gewang@siliconmotion.com ++ * Boyod boyod.yang@siliconmotion.com.cn ++ * ++ * Copyright (C) 2009 Lemote, Inc. ++ * Author: Wu Zhangjin, wuzhangjin@gmail.com ++ * ++ * Copyright (C) 2011 Igalia, S.L. ++ * Author: Javier M. Mellid ++ * ++ * Copyright (C) 2014 Tom Li. ++ * Author: Tom Li (Yifeng Li) ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ */ ++ ++ ++#define sm712_writeb(base, reg, dat) writeb(dat, base + reg) ++#define sm712_writew(base, reg, dat) writew(dat, base + reg) ++#define sm712_writel(base, reg, dat) writel(dat, base + reg) ++ ++#define sm712_readb(base, reg) readb(base + reg) ++#define sm712_readw(base, reg) readw(base + reg) ++#define sm712_readl(base, reg) readl(base + reg) ++ ++ ++static inline void sm712_write_crtc(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3d4, reg); ++ sm712_writeb(fb->mmio, 0x3d5, val); ++} ++ ++static inline u8 sm712_read_crtc(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3d4, reg); ++ return sm712_readb(fb->mmio, 0x3d5); ++} ++ ++static inline void sm712_write_grph(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3ce, reg); ++ sm712_writeb(fb->mmio, 0x3cf, val); ++} ++ ++static inline u8 sm712_read_grph(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3ce, reg); ++ return sm712_readb(fb->mmio, 0x3cf); ++} ++ ++static inline void sm712_write_attr(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_readb(fb->mmio, 0x3da); ++ sm712_writeb(fb->mmio, 0x3c0, reg); ++ sm712_readb(fb->mmio, 0x3c1); ++ sm712_writeb(fb->mmio, 0x3c0, val); ++} ++ ++static inline void sm712_write_seq(struct sm712fb_info *fb, u8 reg, u8 val) ++{ ++ sm712_writeb(fb->mmio, 0x3c4, reg); ++ sm712_writeb(fb->mmio, 0x3c5, val); ++} ++ ++static inline u8 sm712_read_seq(struct sm712fb_info *fb, u8 reg) ++{ ++ sm712_writeb(fb->mmio, 0x3c4, reg); ++ return sm712_readb(fb->mmio, 0x3c5); ++} ++ ++static inline u32 sm712_read_dpr(struct sm712fb_info *fb, u8 reg) ++{ ++ return sm712_readl(fb->dpr, reg); ++} ++ ++static inline void sm712_write_dpr(struct sm712fb_info *fb, u8 reg, u32 val) ++{ ++ sm712_writel(fb->dpr, reg, val); ++} ++ ++static inline void sm712_write_dataport(struct sm712fb_info *fb, u32 val) ++{ ++ sm712_writel(fb->dataport, 0, val); ++} +diff --git a/drivers/video/fbdev/sm712fb/sm712fb_modedb.h b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h +new file mode 100644 +index 0000000..16ee7e3 +--- /dev/null ++++ b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h +@@ -0,0 +1,682 @@ ++/* The next structure holds all information relevant for a specific video mode. ++ */ ++ ++struct ModeInit { ++ int mmSizeX; ++ int mmSizeY; ++ int bpp; ++ int hz; ++ unsigned char Init_MISC; ++ unsigned char Init_SR00_SR04[SR00_SR04_SIZE]; ++ unsigned char Init_SR10_SR24[SR10_SR24_SIZE]; ++ unsigned char Init_SR30_SR75[SR30_SR75_SIZE]; ++ unsigned char Init_SR80_SR93[SR80_SR93_SIZE]; ++ unsigned char Init_SRA0_SRAF[SRA0_SRAF_SIZE]; ++ unsigned char Init_GR00_GR08[GR00_GR08_SIZE]; ++ unsigned char Init_AR00_AR14[AR00_AR14_SIZE]; ++ unsigned char Init_CR00_CR18[CR00_CR18_SIZE]; ++ unsigned char Init_CR30_CR4D[CR30_CR4D_SIZE]; ++ unsigned char Init_CR90_CRA7[CR90_CRA7_SIZE]; ++}; ++ ++/********************************************************************** ++ SM712 Mode table. ++ **********************************************************************/ ++struct ModeInit VGAMode[] = { ++ { ++ /* mode#0: 640 x 480 16Bpp 60Hz */ ++ 640, 480, 16, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ { ++ /* mode#1: 640 x 480 24Bpp 60Hz */ ++ 640, 480, 24, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ { ++ /* mode#0: 640 x 480 32Bpp 60Hz */ ++ 640, 480, 32, 60, ++ /* Init_MISC */ ++ 0xE3, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, ++ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, ++ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, ++ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, ++ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, ++ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, ++ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, ++ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, ++ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, ++ }, ++ }, ++ ++ { /* mode#2: 800 x 600 16Bpp 60Hz */ ++ 800, 600, 16, 60, ++ /* Init_MISC */ ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, ++ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, ++ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ { /* mode#3: 800 x 600 24Bpp 60Hz */ ++ 800, 600, 24, 60, ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, ++ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ { /* mode#7: 800 x 600 32Bpp 60Hz */ ++ 800, 600, 32, 60, ++ /* Init_MISC */ ++ 0x2B, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, ++ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, ++ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, ++ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, ++ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, ++ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, ++ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, ++ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, ++ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, ++ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, ++ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, ++ }, ++ }, ++ /* We use 1024x768 table to light 1024x600 panel for lemote */ ++ { /* mode#4: 1024 x 600 16Bpp 60Hz */ ++ 1024, 600, 16, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x00, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, ++ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x00, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, ++ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, ++ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, ++ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, ++ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#5: 1024 x 768 24Bpp 60Hz */ ++ 1024, 768, 24, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x30, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, ++ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#4: 1024 x 768 32Bpp 60Hz */ ++ 1024, 768, 32, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, ++ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ { /* mode#6: 320 x 240 16Bpp 60Hz */ ++ 320, 240, 16, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, ++ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++ ++ { /* mode#8: 320 x 240 32Bpp 60Hz */ ++ 320, 240, 32, 60, ++ /* Init_MISC */ ++ 0xEB, ++ { /* Init_SR0_SR4 */ ++ 0x03, 0x01, 0x0F, 0x03, 0x0E, ++ }, ++ { /* Init_SR10_SR24 */ ++ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, ++ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xC4, 0x32, 0x02, 0x01, 0x01, ++ }, ++ { /* Init_SR30_SR75 */ ++ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, ++ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, ++ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, ++ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, ++ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, ++ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, ++ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, ++ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, ++ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, ++ }, ++ { /* Init_SR80_SR93 */ ++ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, ++ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, ++ 0x00, 0x00, 0x00, 0x00, ++ }, ++ { /* Init_SRA0_SRAF */ ++ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, ++ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, ++ }, ++ { /* Init_GR00_GR08 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, ++ 0xFF, ++ }, ++ { /* Init_AR00_AR14 */ ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x41, 0x00, 0x0F, 0x00, 0x00, ++ }, ++ { /* Init_CR00_CR18 */ ++ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, ++ 0xFF, ++ }, ++ { /* Init_CR30_CR4D */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, ++ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, ++ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, ++ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, ++ }, ++ { /* Init_CR90_CRA7 */ ++ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, ++ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, ++ }, ++ }, ++}; ++ ++#define numVGAModes ARRAY_SIZE(VGAMode) +diff --git a/drivers/video/output.c b/drivers/video/output.c +new file mode 100644 +index 0000000..1446c49 +--- /dev/null ++++ b/drivers/video/output.c +@@ -0,0 +1,133 @@ ++/* ++ * output.c - Display Output Switch driver ++ * ++ * Copyright (C) 2006 Luming Yu ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++ ++MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Luming Yu "); ++ ++static ssize_t state_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ ssize_t ret_size = 0; ++ struct output_device *od = to_output_device(dev); ++ if (od->props) ++ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); ++ return ret_size; ++} ++ ++static ssize_t state_store(struct device *dev, struct device_attribute *attr, ++ const char *buf,size_t count) ++{ ++ char *endp; ++ struct output_device *od = to_output_device(dev); ++ int request_state = simple_strtoul(buf,&endp,0); ++ size_t size = endp - buf; ++ ++ if (isspace(*endp)) ++ size++; ++ if (size != count) ++ return -EINVAL; ++ ++ if (od->props) { ++ od->request_state = request_state; ++ od->props->set_state(od); ++ } ++ return count; ++} ++static DEVICE_ATTR_RW(state); ++ ++static void video_output_release(struct device *dev) ++{ ++ struct output_device *od = to_output_device(dev); ++ kfree(od); ++} ++ ++static struct attribute *video_output_attrs[] = { ++ &dev_attr_state.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(video_output); ++ ++static struct class video_output_class = { ++ .name = "video_output", ++ .dev_release = video_output_release, ++ .dev_groups = video_output_groups, ++}; ++ ++struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op) ++{ ++ struct output_device *new_dev; ++ int ret_code = 0; ++ ++ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); ++ if (!new_dev) { ++ ret_code = -ENOMEM; ++ goto error_return; ++ } ++ new_dev->props = op; ++ new_dev->dev.class = &video_output_class; ++ new_dev->dev.parent = dev; ++ dev_set_name(&new_dev->dev, "%s", name); ++ dev_set_drvdata(&new_dev->dev, devdata); ++ ret_code = device_register(&new_dev->dev); ++ if (ret_code) { ++ kfree(new_dev); ++ goto error_return; ++ } ++ return new_dev; ++ ++error_return: ++ return ERR_PTR(ret_code); ++} ++EXPORT_SYMBOL(video_output_register); ++ ++void video_output_unregister(struct output_device *dev) ++{ ++ if (!dev) ++ return; ++ device_unregister(&dev->dev); ++} ++EXPORT_SYMBOL(video_output_unregister); ++ ++static void __exit video_output_class_exit(void) ++{ ++ class_unregister(&video_output_class); ++} ++ ++static int __init video_output_class_init(void) ++{ ++ return class_register(&video_output_class); ++} ++ ++postcore_initcall(video_output_class_init); ++module_exit(video_output_class_exit); +diff --git a/include/linux/sm501.h b/include/linux/sm501.h +index 02fde50..a8677f0 100644 +--- a/include/linux/sm501.h ++++ b/include/linux/sm501.h +@@ -27,6 +27,9 @@ extern unsigned long sm501_set_clock(struct device *dev, + extern unsigned long sm501_find_clock(struct device *dev, + int clksrc, unsigned long req_freq); + ++extern void sm501_configure_gpio(struct device *dev, ++ unsigned int gpio, unsigned char mode); ++ + /* sm501_misc_control + * + * Modify the SM501's MISC_CONTROL register +@@ -122,6 +125,7 @@ struct sm501_reg_init { + #define SM501_USE_AC97 (1<<7) + #define SM501_USE_I2S (1<<8) + #define SM501_USE_GPIO (1<<9) ++#define SM501_USE_PWM (1<<10) + + #define SM501_USE_ALL (0xffffffff) + +diff --git a/include/linux/video_output.h b/include/linux/video_output.h +new file mode 100644 +index 0000000..ed5cdeb +--- /dev/null ++++ b/include/linux/video_output.h +@@ -0,0 +1,57 @@ ++/* ++ * ++ * Copyright (C) 2006 Luming Yu ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ */ ++#ifndef _LINUX_VIDEO_OUTPUT_H ++#define _LINUX_VIDEO_OUTPUT_H ++#include ++#include ++struct output_device; ++struct output_properties { ++ int (*set_state)(struct output_device *); ++ int (*get_status)(struct output_device *); ++}; ++struct output_device { ++ int request_state; ++ struct output_properties *props; ++ struct device dev; ++}; ++#define to_output_device(obj) container_of(obj, struct output_device, dev) ++#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE) ++struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op); ++void video_output_unregister(struct output_device *dev); ++#else ++static struct output_device *video_output_register(const char *name, ++ struct device *dev, ++ void *devdata, ++ struct output_properties *op) ++{ ++ return ERR_PTR(-ENODEV); ++} ++static void video_output_unregister(struct output_device *dev) ++{ ++ return; ++} ++#endif ++#endif +diff --git a/init/calibrate.c b/init/calibrate.c +index ce635dc..10e775d 100644 +--- a/init/calibrate.c ++++ b/init/calibrate.c +@@ -21,6 +21,7 @@ static int __init lpj_setup(char *str) + + __setup("lpj=", lpj_setup); + ++#ifndef ARCH_HAS_PREPARED_LPJ + #ifdef ARCH_HAS_READ_CURRENT_TIMER + + /* This routine uses the read_current_timer() routine and gets the +@@ -171,6 +172,7 @@ static unsigned long calibrate_delay_direct(void) + return 0; + } + #endif ++#endif /* ARCH_HAS_PREPARED_LPJ */ + + /* + * This is the number of bits of precision for the loops_per_jiffy. Each +@@ -291,6 +293,7 @@ void calibrate_delay(void) + lpj = lpj_fine; + pr_info("Calibrating delay loop (skipped), " + "value calculated using timer frequency.. "); ++#ifndef ARCH_HAS_PREPARED_LPJ + } else if ((lpj = calibrate_delay_is_known())) { + ; + } else if ((lpj = calibrate_delay_direct()) != 0) { +@@ -301,6 +304,7 @@ void calibrate_delay(void) + if (!printed) + pr_info("Calibrating delay loop... "); + lpj = calibrate_delay_converge(); ++#endif /* ARCH_HAS_PREPARED_LPJ */ + } + per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj; + if (!printed) +diff --git a/net/rfkill/core.c b/net/rfkill/core.c +index fa7cd79..616abb5 100644 +--- a/net/rfkill/core.c ++++ b/net/rfkill/core.c +@@ -111,7 +111,7 @@ static LIST_HEAD(rfkill_list); /* list of registered rf switches */ + static DEFINE_MUTEX(rfkill_global_mutex); + static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ + +-static unsigned int rfkill_default_state = 1; ++static unsigned int rfkill_default_state; /* default: 0 = radio off */ + module_param_named(default_state, rfkill_default_state, uint, 0444); + MODULE_PARM_DESC(default_state, + "Default initial state for all radio types, 0 = radio off"); +diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl +index 826470d..9e6dc30 100755 +--- a/scripts/recordmcount.pl ++++ b/scripts/recordmcount.pl +@@ -309,14 +309,33 @@ if ($arch eq "x86_64") { + $cc .= " -m64"; + $objcopy .= " -O elf64-sparc"; + } elsif ($arch eq "mips") { +- # To enable module support, we need to enable the -mlong-calls option +- # of gcc for module, after using this option, we can not get the real +- # offset of the calling to _mcount, but the offset of the lui +- # instruction or the addiu one. herein, we record the address of the +- # first one, and then we can replace this instruction by a branch +- # instruction to jump over the profiling function to filter the +- # indicated functions, or swith back to the lui instruction to trace +- # them, which means dynamic tracing. ++ # ++ # To disable tracing, just replace "jal _mcount" with nop; ++ # to enable tracing, replace back. so, the offset 14 is ++ # needed to be recorded. ++ # ++ # 10: 03e0082d move at,ra ++ # 14: 0c000000 jal 0 ++ # 14: R_MIPS_26 _mcount ++ # 14: R_MIPS_NONE *ABS* ++ # 14: R_MIPS_NONE *ABS* ++ # 18: 00020021 nop ++ # ++ # ++ # ++ # If no long call(-mlong-calls), the same to kernel. ++ # ++ # If the module space differs from the kernel space, long ++ # call is needed, as a result, the address of _mcount is ++ # needed to be recorded in a register and then jump from ++ # module space to kernel space via "jalr ". To ++ # disable tracing, "jalr " can be replaced by ++ # nop; to enable tracing, replace it back. Since the ++ # offset of "jalr " is not easy to be matched, ++ # the offset of the 1st _mcount below is recorded and to ++ # disable tracing, "lui v1, 0x0" is substituted with "b ++ # label", which jumps over "jalr "; to enable ++ # tracing, replace it back. + # + # c: 3c030000 lui v1,0x0 + # c: R_MIPS_HI16 _mcount +@@ -328,19 +347,12 @@ if ($arch eq "x86_64") { + # 10: R_MIPS_NONE *ABS* + # 14: 03e0082d move at,ra + # 18: 0060f809 jalr v1 ++ # label: + # +- # for the kernel: +- # +- # 10: 03e0082d move at,ra +- # 14: 0c000000 jal 0 +- # 14: R_MIPS_26 _mcount +- # 14: R_MIPS_NONE *ABS* +- # 14: R_MIPS_NONE *ABS* +- # 18: 00020021 nop + if ($is_module eq "0") { + $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$"; + } else { +- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$"; ++ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_(HI16|26)\\s+_mcount\$"; + } + $objdump .= " -Melf-trad".$endian."mips "; + +diff --git a/scripts/sstrip.sh b/scripts/sstrip.sh +new file mode 100755 +index 0000000..49b973a +--- /dev/null ++++ b/scripts/sstrip.sh +@@ -0,0 +1,59 @@ ++#!/bin/bash ++# sstrip.sh -- strip the section table of an elf file ++# ++# Copyright (C) 2010 Wu Zhangjin, wuzhangjin@gmail.com ++# Licensed under the GPLv2 ++# ++# Since the section table is useless for the embedded device, it can be ++# stripped out. ++# ++# Note: Some bootloader may check the section table but most of the time, it ++# may be not really used, If it really need the section table, it may need the ++# decompressed kernel image. ++ ++# Usage ++ ++function usage ++{ ++cat </dev/null` ++[ "xELF" != "x${FILE_TYPE}" ] && echo "$0: ${IMAGE} is not an ELF file" && exit -1 ++ ++[ "x${V}" == "x1" ] && orig_filesz=`wc -c ${IMAGE} | cut -d' ' -f1` ++ ++# Get the offset of the section table, here get the end of the program section ++filesz=$((`${OBJDUMP} -p ${IMAGE} | grep -m1 filesz | tr -s ' ' | cut -d' ' -f3`)) ++ ++# Truncate it via the dd tool ++dd if=/dev/null bs=1 of=${IMAGE} seek=${filesz} 2>/dev/null ++ ++# Clear the section table information in the ELF header ++# The last 6 bytes of the ELF header are the section table information ++echo -ne "\x00\x00\x00\x00\x00\x00" | dd of=${IMAGE} bs=1 seek=46 count=6 conv=notrunc 2>/dev/null ++ ++# Debug ++if [ "x${V}" == "x1" ]; then ++ echo "----------------------------------------------------------------" ++ echo "Strip the section table at ${filesz} of ${IMAGE}" ++ echo "----------------------------------------------------------------" ++ echo " sstrip: $0" ++ echo " objdump: ${OBJDUMP}" ++ echo "original size: ${orig_filesz}" ++ echo "current size: ${filesz}" ++ echo "reduced size: $((${orig_filesz} - ${filesz}))" ++fi diff --git a/libre/linux-libre-grsec/PKGBUILD b/libre/linux-libre-grsec/PKGBUILD index 97c34f539..ccdce0f72 100644 --- a/libre/linux-libre-grsec/PKGBUILD +++ b/libre/linux-libre-grsec/PKGBUILD @@ -12,9 +12,9 @@ pkgbase=linux-libre-grsec # Build kernel with -grsec localname _pkgbasever=4.0-gnu -_pkgver=4.0.3-gnu +_pkgver=4.0.4-gnu _grsecver=3.1 -_timestamp=201505141746 +_timestamp=201505182014 _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -43,22 +43,22 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li 'change-default-console-loglevel.patch' # loongson-community patch: http://linux-libre.fsfla.org/pub/linux-libre/lemote/gnewsense/pool/debuginfo/ # Note: Makefile patching was removed due which we are using specific flags from grsecurity patch - '4.0-rc7-37af2c8aae-loongson-community.patch') + '4.0.2-ae91f13af5-loongson-community.patch') sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' - '73e5adbee83c5d5898f03b4f7525876cc0db6eab0e569a4229ee8d8cf9e3ef2e' + 'e447de9a53c5aefd25f0474f3304ab87076b88353badaae20dcbd85712e85e61' 'SKIP' - 'e10e9292b02728a3e2d4157b385298095c29634d00e7ae5f9f2847576d69c570' + '5e098d6ed12ec7926b7a2697fde24ccfabd5ca81de486fc81d257fbf3e003ad0' 'SKIP' - 'd1b2bfc86563d522562850556a2dd39f41b91b992cb4d839551e44e8d9df0ae3' - '92580d3bd2f8c66ccc9467e9a4bfbc012e90a3d32953503750309313755a3ea2' - 'cfb811c37f4b04bbc93cd87c5d1fa3bff2bcdd6e28bffce703d49beb9f3877d6' + 'd4e66b81d29d5048f072b3eda89b12e1564c2b3c9d0e27f9efbd7290b52cc9ee' + '5c12d80d81dbde43c138acf69a036640a28c8b49c02c8547033a60a0fecc9f08' + '3383ed8dfa70ec91275e52c12965c2e265fffe494c2ee1904c20e3d2773a5993' 'f0d90e756f14533ee67afda280500511a62465b4f76adcc5effa95a40045179c' 'bfd4a7f61febe63c880534dcb7c31c5b932dde6acf991810b41a939a93535494' '6de8a8319271809ffdb072b68d53d155eef12438e6d04ff06a5a4db82c34fa8a' '13bd7a8d9ed6b6bc971e4cd162262c5a20448a83796af39ce394d827b0e5de74' '1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99' - '8a070d193bc54db696b38ac844cfbfd62724f483ad74c9a288ccab462c32f80e') + '13e141279af2bc17decfc041e015710daac9a6cd1c9b4e871a76cb8f916b9e22') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva 'DE9452CE46F42094907F108B44D1C0F82525FE49' # Bradley Spengler @@ -100,7 +100,7 @@ prepare() { # Adding loongson-community patch if [ "${CARCH}" == "mips64el" ]; then - patch -p1 -i ${srcdir}/4.0-rc7-37af2c8aae-loongson-community.patch + patch -p1 -i ${srcdir}/4.0.2-ae91f13af5-loongson-community.patch fi cat "${srcdir}/config.${CARCH}" > ./.config diff --git a/libre/linux-libre-grsec/config.i686 b/libre/linux-libre-grsec/config.i686 index 703e061c3..34d4907b2 100644 --- a/libre/linux-libre-grsec/config.i686 +++ b/libre/linux-libre-grsec/config.i686 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 4.0.1-gnu-201505031602-1-grsec Kernel Configuration +# Linux/x86 4.0.4-gnu-201505182014-1-grsec Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -151,8 +151,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_HUGETLB is not set # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y @@ -838,7 +838,7 @@ CONFIG_TCP_CONG_DCTCP=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -3190,6 +3190,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m CONFIG_INPUT_E3X0_BUTTON=m CONFIG_INPUT_PCSPKR=m @@ -3646,7 +3647,7 @@ CONFIG_POWER_RESET_GPIO=y # CONFIG_POWER_RESET_RESTART is not set # CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3804,6 +3805,7 @@ CONFIG_SENSORS_W83627EHF=m CONFIG_SENSORS_ACPI_POWER=m CONFIG_SENSORS_ATK0110=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_OF=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set @@ -4313,6 +4315,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4824,8 +4827,10 @@ CONFIG_SOUND_OSS_CORE=y CONFIG_SND=m CONFIG_SND_TIMER=m CONFIG_SND_PCM=m +CONFIG_SND_DMAENGINE_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -5036,7 +5041,109 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y +# CONFIG_SND_ATMEL_SOC is not set +CONFIG_SND_DESIGNWARE_I2S=m + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +CONFIG_SND_SST_MFLD_PLATFORM=m +CONFIG_SND_SST_IPC=m +CONFIG_SND_SST_IPC_ACPI=m +CONFIG_SND_SOC_INTEL_SST=m +CONFIG_SND_SOC_INTEL_SST_ACPI=m +CONFIG_SND_SOC_INTEL_HASWELL=m +CONFIG_SND_SOC_INTEL_BAYTRAIL=m +CONFIG_SND_SOC_INTEL_HASWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH=m +CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +CONFIG_SND_SOC_MAX98090=m +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +CONFIG_SND_SOC_RL6231=m +CONFIG_SND_SOC_RT286=m +# CONFIG_SND_SOC_RT5631 is not set +CONFIG_SND_SOC_RT5640=m +CONFIG_SND_SOC_RT5645=m +CONFIG_SND_SOC_RT5670=m +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -6233,6 +6340,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set CONFIG_EXTCON_SM5502=m @@ -7307,7 +7415,7 @@ CONFIG_CRYPTO_CRC32_PCLMUL=m CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m diff --git a/libre/linux-libre-grsec/config.mips64el b/libre/linux-libre-grsec/config.mips64el index 599589376..f7001ed72 100644 --- a/libre/linux-libre-grsec/config.mips64el +++ b/libre/linux-libre-grsec/config.mips64el @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/mips 4.0.1-gnu-201505042053-1-grsec Kernel Configuration +# Linux/mips 4.0.4-gnu-201505182014-1-grsec Kernel Configuration # CONFIG_MIPS=y @@ -271,8 +271,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y CONFIG_FAIR_GROUP_SCHED=y @@ -626,7 +626,7 @@ CONFIG_TCP_CONG_ILLINOIS=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -2811,6 +2811,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m # CONFIG_INPUT_E3X0_BUTTON is not set CONFIG_INPUT_MC13783_PWRBUTTON=m @@ -3184,7 +3185,7 @@ CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_BRCMSTB is not set # CONFIG_POWER_RESET_RESTART is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3324,6 +3325,7 @@ CONFIG_SENSORS_W83L786NG=m CONFIG_SENSORS_W83627HF=m CONFIG_SENSORS_W83627EHF=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set # CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set @@ -3778,6 +3780,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4231,6 +4234,7 @@ CONFIG_SND_TIMER=m CONFIG_SND_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -4395,7 +4399,87 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +# CONFIG_SND_ATMEL_SOC is not set + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -5380,6 +5464,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set # CONFIG_EXTCON_SM5502 is not set @@ -6365,7 +6450,7 @@ CONFIG_CRYPTO_CRC32=m CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m diff --git a/libre/linux-libre-grsec/config.x86_64 b/libre/linux-libre-grsec/config.x86_64 index 53dc4920d..b5f475fac 100644 --- a/libre/linux-libre-grsec/config.x86_64 +++ b/libre/linux-libre-grsec/config.x86_64 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 4.0.1-gnu-201505031602-1-grsec Kernel Configuration +# Linux/x86 4.0.4-gnu-201505182014-1-grsec Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -159,8 +159,8 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -# CONFIG_MEMCG_SWAP_ENABLED is not set -# CONFIG_MEMCG_KMEM is not set +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMCG_KMEM=y # CONFIG_CGROUP_HUGETLB is not set # CONFIG_CGROUP_PERF is not set CONFIG_CGROUP_SCHED=y @@ -822,7 +822,7 @@ CONFIG_TCP_CONG_DCTCP=m CONFIG_DEFAULT_CUBIC=y # CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set +CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -3079,6 +3079,7 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_AD714X_I2C=m CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set CONFIG_INPUT_BMA150=m CONFIG_INPUT_E3X0_BUTTON=m CONFIG_INPUT_PCSPKR=m @@ -3496,7 +3497,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_RESTART is not set CONFIG_POWER_AVS=y -CONFIG_HWMON=m +CONFIG_HWMON=y CONFIG_HWMON_VID=m # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3653,6 +3654,7 @@ CONFIG_SENSORS_W83627EHF=m CONFIG_SENSORS_ACPI_POWER=m CONFIG_SENSORS_ATK0110=m CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set # CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set @@ -4142,6 +4144,7 @@ CONFIG_RADIO_SI4713=m CONFIG_USB_SI4713=m CONFIG_PLATFORM_SI4713=m CONFIG_I2C_SI4713=m +CONFIG_RADIO_SI476X=m CONFIG_USB_MR800=m CONFIG_USB_DSBR=m CONFIG_RADIO_MAXIRADIO=m @@ -4632,8 +4635,10 @@ CONFIG_SOUND_OSS_CORE=y CONFIG_SND=m CONFIG_SND_TIMER=m CONFIG_SND_PCM=m +CONFIG_SND_DMAENGINE_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m @@ -4803,7 +4808,109 @@ CONFIG_SND_BEBOB=m CONFIG_SND_PCMCIA=y CONFIG_SND_VXPOCKET=m CONFIG_SND_PDAUDIOCF=m -# CONFIG_SND_SOC is not set +CONFIG_SND_SOC=m +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y +# CONFIG_SND_ATMEL_SOC is not set +CONFIG_SND_DESIGNWARE_I2S=m + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +CONFIG_SND_SST_MFLD_PLATFORM=m +CONFIG_SND_SST_IPC=m +CONFIG_SND_SST_IPC_ACPI=m +CONFIG_SND_SOC_INTEL_SST=m +CONFIG_SND_SOC_INTEL_SST_ACPI=m +CONFIG_SND_SOC_INTEL_HASWELL=m +CONFIG_SND_SOC_INTEL_BAYTRAIL=m +CONFIG_SND_SOC_INTEL_HASWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH=m +CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m +# CONFIG_SND_SOC_XTFPGA_I2S is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES8328 is not set +CONFIG_SND_SOC_MAX98090=m +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +CONFIG_SND_SOC_RL6231=m +CONFIG_SND_SOC_RT286=m +# CONFIG_SND_SOC_RT5631 is not set +CONFIG_SND_SOC_RT5640=m +CONFIG_SND_SOC_RT5645=m +CONFIG_SND_SOC_RT5670=m +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SI476X=m +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=m +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD=m # CONFIG_SOUND_PRIME is not set CONFIG_AC97_BUS=m @@ -5930,6 +6037,7 @@ CONFIG_EXTCON=m # Extcon Device Drivers # # CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set CONFIG_EXTCON_GPIO=m # CONFIG_EXTCON_RT8973A is not set CONFIG_EXTCON_SM5502=m @@ -7001,7 +7109,7 @@ CONFIG_CRYPTO_CRCT10DIF=y CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m CONFIG_CRYPTO_GHASH=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m -- cgit v1.2.3 From 1d228d5aea01528d7c3a1de1884e701b95f5d74e Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 23 May 2015 21:18:16 -0300 Subject: linux-libre-api-headers-4.0_gnu-1: updating version --- libre/linux-libre-api-headers/PKGBUILD | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'libre') diff --git a/libre/linux-libre-api-headers/PKGBUILD b/libre/linux-libre-api-headers/PKGBUILD index 7b378033e..770e5d75a 100644 --- a/libre/linux-libre-api-headers/PKGBUILD +++ b/libre/linux-libre-api-headers/PKGBUILD @@ -1,4 +1,4 @@ -# $Id: PKGBUILD 231100 2015-02-07 10:33:26Z allan $ +# $Id: PKGBUILD 237944 2015-04-23 05:19:11Z allan $ # Maintainer (Arch): Allan McRae # Maintainer: André Silva # Contributor: Luke Shumaker @@ -6,8 +6,8 @@ # toolchain build order: linux-libre-api-headers->glibc->binutils->gcc->binutils->glibc pkgname=linux-libre-api-headers -_pkgbasever=3.18-gnu -_pkgver=3.18.5-gnu +_pkgbasever=4.0-gnu +_pkgver=${_pkgbasever} _srcname=linux-${_pkgbasever%-*} _archpkgver=${_pkgver%-*} @@ -21,12 +21,10 @@ provides=( "linux-api-headers=${_archpkgver}") conflicts=('linux-api-headers') replaces=( 'linux-api-headers') source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/linux-libre-${_pkgbasever}.tar.xz" - "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/linux-libre-${_pkgbasever}.tar.xz.sign" - "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgver}/patch-${_pkgbasever}-${_pkgver}.xz" - "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgver}/patch-${_pkgbasever}-${_pkgver}.xz.sign") -md5sums=('b3c2a6827813398dde7e8a2d4e02a2c3' - 'SKIP' - '703db9a7b1c55dcbb2878eaa8e38b0e4' + "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/linux-libre-${_pkgbasever}.tar.xz.sign") + #"http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgver}/patch-${_pkgbasever}-${_pkgver}.xz" + #"http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgver}/patch-${_pkgbasever}-${_pkgver}.xz.sign") +md5sums=('87edb0b508abb8d8484bc08daa2ee96d' 'SKIP') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva -- cgit v1.2.3 From ba37a91ed1eb8229da6af996276699c6577bd531 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Sat, 23 May 2015 21:29:20 -0300 Subject: spectrwm-2.7.0-1.parabola1: updating version --- libre/spectrwm/PKGBUILD | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'libre') diff --git a/libre/spectrwm/PKGBUILD b/libre/spectrwm/PKGBUILD index a5e29caed..af9d4c8aa 100644 --- a/libre/spectrwm/PKGBUILD +++ b/libre/spectrwm/PKGBUILD @@ -1,9 +1,9 @@ -# $Id: PKGBUILD 126653 2015-01-27 19:06:39Z kkeen $ +# $Id: PKGBUILD 133981 2015-05-22 20:37:45Z kkeen $ # Maintainer (Arch): Kyle Keen # Contributor (Arch): Christoph Zeiler pkgname=spectrwm -pkgver=2.6.2 +pkgver=2.7.0 pkgrel=1.parabola1 pkgdesc="A minimalistic automatic tiling window manager that tries to stay out of the way, without nonfree profont support" arch=('i686' 'x86_64' 'mips64el') @@ -19,16 +19,11 @@ optdepends=('scrot: screenshots' 'terminus-font: great font') backup=(etc/spectrwm.conf) -# the +2.6.0 gnu/linux makefile does not build -# so download and use the 2.5.1 makefile until this is fixed - source=(http://opensource.conformal.com/snapshots/$pkgname/$pkgname-$pkgver.tgz \ - http://opensource.conformal.com/snapshots/$pkgname/$pkgname-2.5.1.tgz \ LICENSE \ baraction.sh \ spectrwm-no-preload) -md5sums=('eba7cba0c85706435657f744bf9086bc' - 'd9aec3342920e31cbe60f1032571043a' +md5sums=('a638207b5e20ad1bfaf0a8ae61a69eef' 'a67cfe51079481e5b0eab1ad371379e3' '950d663692e1da56e0ac864c6c3ed80e' '974d109ce0af39cc73936d5efd682480') @@ -47,7 +42,6 @@ build() { sed -i 's/setconfspawn("lock".*/setconfspawn("lock", "xlock", SWM_SPAWN_OPTIONAL);/' spectrwm.c cd linux - cp "$srcdir/$pkgname-2.5.1/linux/Makefile" ./ make PREFIX="/usr" } @@ -71,9 +65,4 @@ package() { # fix this for real in the makefile rm "$pkgdir/usr/bin/scrotwm" ln -s "/usr/bin/spectrwm" "$pkgdir/usr/bin/scrotwm" - mkdir -p "$pkgdir"/usr/share/man/{es,it,pt,ru}/man1/ - mv "$pkgdir/usr/share/man/man1/spectrwm_es.1" "$pkgdir/usr/share/man/es/man1/" - mv "$pkgdir/usr/share/man/man1/spectrwm_it.1" "$pkgdir/usr/share/man/it/man1/" - mv "$pkgdir/usr/share/man/man1/spectrwm_pt.1" "$pkgdir/usr/share/man/pt/man1/" - mv "$pkgdir/usr/share/man/man1/spectrwm_ru.1" "$pkgdir/usr/share/man/ru/man1/" } -- cgit v1.2.3 From 822902f3f8a0170b8f29ad0512ab94ed61fd0357 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Mon, 25 May 2015 13:52:00 -0300 Subject: linux-libre-grsec{,-knock}-4.0.4_gnu.201505222222-1: updating version --- kernels/linux-libre-grsec-knock/PKGBUILD | 14 +++++++------- libre/linux-libre-grsec/PKGBUILD | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'libre') diff --git a/kernels/linux-libre-grsec-knock/PKGBUILD b/kernels/linux-libre-grsec-knock/PKGBUILD index c9f1cf0e4..7672cab65 100644 --- a/kernels/linux-libre-grsec-knock/PKGBUILD +++ b/kernels/linux-libre-grsec-knock/PKGBUILD @@ -14,7 +14,7 @@ pkgbase=linux-libre-grsec-knock # Build kernel with -grsec-knock localname _pkgbasever=4.0-gnu _pkgver=4.0.4-gnu _grsecver=3.1 -_timestamp=201505182014 +_timestamp=201505222222 _knockpatchver=3.18_1 _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname @@ -34,8 +34,8 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/linux-libre-${_pkgbasever}.tar.xz.sign" "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgver}/patch-${_pkgbasever}-${_pkgver}.xz" "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgver}/patch-${_pkgbasever}-${_pkgver}.xz.sign" - "https://grsecurity.net/test/grsecurity-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch" - "https://grsecurity.net/test/grsecurity-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch.sig" + "https://repo.parabola.nu/other/grsecurity-libre/test/grsecurity-libre-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch" + "https://repo.parabola.nu/other/grsecurity-libre/test/grsecurity-libre-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch.sig" "http://gnunet.org/sites/default/files/tcp_stealth_${_knockpatchver}.diff" "tcp_stealth_${_knockpatchver}.diff.sig::http://gnunet.org/sites/default/files/tcp_stealth_${_knockpatchver%_1}.diff_1.sig" # the main kernel config files @@ -51,7 +51,7 @@ sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' 'e447de9a53c5aefd25f0474f3304ab87076b88353badaae20dcbd85712e85e61' 'SKIP' - '5e098d6ed12ec7926b7a2697fde24ccfabd5ca81de486fc81d257fbf3e003ad0' + '880b46fd8ac5690587aa0a8db8445956bbab62d12b72c28b78a5dfe05d3ef5b7' 'SKIP' '93a1610c203ea4c187ac5b50dce105fac86df914b1406e1d85df5857d36201c9' 'SKIP' @@ -66,7 +66,7 @@ sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'ac7232b38f5a25a79a23c25c8cd5ed4579ca5402466d3370dd093626998092b3') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva - 'DE9452CE46F42094907F108B44D1C0F82525FE49' # Bradley Spengler + 'C92BAA713B8D53D3CAE63FC9E6974752F9704456' # André Silva 'F949CFBD140A6DD071E90B8CDC24396B6D451038' # Julian Kirsch ) @@ -88,8 +88,8 @@ prepare() { patch -p1 -i "${srcdir}/patch-${_pkgbasever}-${_pkgver}" fi - # add grsecurity patches - patch -Np1 -i "${srcdir}/grsecurity-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch" + # add grsecurity patches (without nonfree bnx2 firmware patching) + patch -Np1 -i "${srcdir}/grsecurity-libre-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch" rm localversion-grsec # add knock patch diff --git a/libre/linux-libre-grsec/PKGBUILD b/libre/linux-libre-grsec/PKGBUILD index ccdce0f72..d946e9050 100644 --- a/libre/linux-libre-grsec/PKGBUILD +++ b/libre/linux-libre-grsec/PKGBUILD @@ -14,7 +14,7 @@ pkgbase=linux-libre-grsec # Build kernel with -grsec localname _pkgbasever=4.0-gnu _pkgver=4.0.4-gnu _grsecver=3.1 -_timestamp=201505182014 +_timestamp=201505222222 _replacesarchkernel=('linux%') # '%' gets replaced with _kernelname _replacesoldkernels=('kernel26%' 'kernel26-libre%') # '%' gets replaced with _kernelname @@ -33,8 +33,8 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/linux-libre-${_pkgbasever}.tar.xz.sign" "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgver}/patch-${_pkgbasever}-${_pkgver}.xz" "http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgver}/patch-${_pkgbasever}-${_pkgver}.xz.sign" - "https://grsecurity.net/test/grsecurity-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch" - "https://grsecurity.net/test/grsecurity-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch.sig" + "https://repo.parabola.nu/other/grsecurity-libre/test/grsecurity-libre-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch" + "https://repo.parabola.nu/other/grsecurity-libre/test/grsecurity-libre-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch.sig" # the main kernel config files 'config.i686' 'config.x86_64' 'config.mips64el' # standard config files for mkinitcpio ramdisk @@ -48,7 +48,7 @@ sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'SKIP' 'e447de9a53c5aefd25f0474f3304ab87076b88353badaae20dcbd85712e85e61' 'SKIP' - '5e098d6ed12ec7926b7a2697fde24ccfabd5ca81de486fc81d257fbf3e003ad0' + '880b46fd8ac5690587aa0a8db8445956bbab62d12b72c28b78a5dfe05d3ef5b7' 'SKIP' 'd4e66b81d29d5048f072b3eda89b12e1564c2b3c9d0e27f9efbd7290b52cc9ee' '5c12d80d81dbde43c138acf69a036640a28c8b49c02c8547033a60a0fecc9f08' @@ -61,7 +61,7 @@ sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' '13e141279af2bc17decfc041e015710daac9a6cd1c9b4e871a76cb8f916b9e22') validpgpkeys=( '474402C8C582DAFBE389C427BCB7CF877E7D47A7' # Alexandre Oliva - 'DE9452CE46F42094907F108B44D1C0F82525FE49' # Bradley Spengler + 'C92BAA713B8D53D3CAE63FC9E6974752F9704456' # André Silva ) _kernelname=${pkgbase#linux-libre} @@ -82,8 +82,8 @@ prepare() { patch -p1 -i "${srcdir}/patch-${_pkgbasever}-${_pkgver}" fi - # add grsecurity patches - patch -Np1 -i "${srcdir}/grsecurity-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch" + # add grsecurity patches (without nonfree bnx2 firmware patching) + patch -Np1 -i "${srcdir}/grsecurity-libre-${_grsecver}-${_pkgver%-*}-${_timestamp}.patch" rm localversion-grsec # add freedo as boot logo -- cgit v1.2.3 From 6be532a3cfddcfb1dc41746cba2b3be37f82e005 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 26 May 2015 11:56:00 -0300 Subject: linux-libre-4.0.4_gnu-2: add proposed fix for data loss on md raid0 when discard is used (FS#45040 -> https://bugs.archlinux.org/task/45040) --- libre/linux-libre/PKGBUILD | 7 ++- ...x-restore-to-sector-variable-in-raid0_mak.patch | 50 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 libre/linux-libre/md-raid0-fix-restore-to-sector-variable-in-raid0_mak.patch (limited to 'libre') diff --git a/libre/linux-libre/PKGBUILD b/libre/linux-libre/PKGBUILD index ca13870d4..51c10d7c1 100644 --- a/libre/linux-libre/PKGBUILD +++ b/libre/linux-libre/PKGBUILD @@ -18,7 +18,7 @@ _replacesoldmodules=('linux-libre%-kmod-alx') # '%' gets replaced with _kernelna _srcname=linux-${_pkgbasever%-*} _archpkgver=${_pkgver%-*} pkgver=${_pkgver//-/_} -pkgrel=1 +pkgrel=2 arch=('i686' 'x86_64' 'mips64el') url="http://linux-libre.fsfla.org/" license=('GPL2') @@ -33,6 +33,7 @@ source=("http://linux-libre.fsfla.org/pub/linux-libre/releases/${_pkgbasever}/li # standard config files for mkinitcpio ramdisk 'linux.preset' 'logo_linux_'{clut224.ppm,vga16.ppm,mono.pbm} + 'md-raid0-fix-restore-to-sector-variable-in-raid0_mak.patch' 'change-default-console-loglevel.patch' # loongson-community patch: http://linux-libre.fsfla.org/pub/linux-libre/lemote/gnewsense/pool/debuginfo/ '4.0.2-ae91f13af5-loongson-community.patch') @@ -47,6 +48,7 @@ sha256sums=('0e2dd5be12c1f82ab3d03b89cbe3f1a20e14332ec42c102efb226a6283fdd38a' 'bfd4a7f61febe63c880534dcb7c31c5b932dde6acf991810b41a939a93535494' '6de8a8319271809ffdb072b68d53d155eef12438e6d04ff06a5a4db82c34fa8a' '13bd7a8d9ed6b6bc971e4cd162262c5a20448a83796af39ce394d827b0e5de74' + 'bc83293e64653d60793708a0e277741f57c018f5ea3551a8aff3a220df917ceb' '1256b241cd477b265a3c2d64bdc19ffe3c9bbcee82ea3994c590c2c76e767d99' '13e141279af2bc17decfc041e015710daac9a6cd1c9b4e871a76cb8f916b9e22') validpgpkeys=( @@ -78,6 +80,9 @@ prepare() { # add latest fixes from stable queue, if needed # http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git + # https://bugzilla.kernel.org/show_bug.cgi?id=98501 + patch -Np1 -i "${srcdir}/md-raid0-fix-restore-to-sector-variable-in-raid0_mak.patch" + # set DEFAULT_CONSOLE_LOGLEVEL to 4 (same value as the 'quiet' kernel param) # remove this when a Kconfig knob is made available by upstream # (relevant patch sent upstream: https://lkml.org/lkml/2011/7/26/227) diff --git a/libre/linux-libre/md-raid0-fix-restore-to-sector-variable-in-raid0_mak.patch b/libre/linux-libre/md-raid0-fix-restore-to-sector-variable-in-raid0_mak.patch new file mode 100644 index 000000000..9f09102dc --- /dev/null +++ b/libre/linux-libre/md-raid0-fix-restore-to-sector-variable-in-raid0_mak.patch @@ -0,0 +1,50 @@ +From a81157768a00e8cf8a7b43b5ea5cac931262374f Mon Sep 17 00:00:00 2001 +From: Eric Work +Date: Mon, 18 May 2015 23:26:23 -0700 +Subject: [PATCH] md/raid0: fix restore to sector variable in + raid0_make_request + +The variable "sector" in "raid0_make_request()" was improperly updated +by a call to "sector_div()" which modifies its first argument in place. +Commit 47d68979cc968535cb87f3e5f2e6a3533ea48fbd restored this variable +after the call for later re-use. Unfortunetly the restore was done after +the referenced variable "bio" was advanced. This lead to the original +value and the restored value being different. Here we move this line to +the proper place. + +One observed side effect of this bug was discarding a file though +unlinking would cause an unrelated file's contents to be discarded. + +Signed-off-by: NeilBrown +Fixes: 47d68979cc96 ("md/raid0: fix bug with chunksize not a power of 2.") +Cc: stable@vger.kernel.org (any that received above backport) +URL: https://bugzilla.kernel.org/show_bug.cgi?id=98501 +--- + drivers/md/raid0.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c +index 6a68ef5..efb654e 100644 +--- a/drivers/md/raid0.c ++++ b/drivers/md/raid0.c +@@ -524,6 +524,9 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) + ? (sector & (chunk_sects-1)) + : sector_div(sector, chunk_sects)); + ++ /* Restore due to sector_div */ ++ sector = bio->bi_iter.bi_sector; ++ + if (sectors < bio_sectors(bio)) { + split = bio_split(bio, sectors, GFP_NOIO, fs_bio_set); + bio_chain(split, bio); +@@ -531,7 +534,6 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) + split = bio; + } + +- sector = bio->bi_iter.bi_sector; + zone = find_zone(mddev->private, §or); + tmp_dev = map_sector(mddev, zone, sector, §or); + split->bi_bdev = tmp_dev->bdev; +-- +2.4.1 + -- cgit v1.2.3 From a8ba939031e3e5629d89ea44807be4e394f8c0e1 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 26 May 2015 11:57:40 -0300 Subject: spectrwm-2.7.1-1.parabola1: updating version --- libre/spectrwm/PKGBUILD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libre') diff --git a/libre/spectrwm/PKGBUILD b/libre/spectrwm/PKGBUILD index af9d4c8aa..930263166 100644 --- a/libre/spectrwm/PKGBUILD +++ b/libre/spectrwm/PKGBUILD @@ -1,9 +1,9 @@ -# $Id: PKGBUILD 133981 2015-05-22 20:37:45Z kkeen $ +# $Id: PKGBUILD 134036 2015-05-24 19:37:57Z kkeen $ # Maintainer (Arch): Kyle Keen # Contributor (Arch): Christoph Zeiler pkgname=spectrwm -pkgver=2.7.0 +pkgver=2.7.1 pkgrel=1.parabola1 pkgdesc="A minimalistic automatic tiling window manager that tries to stay out of the way, without nonfree profont support" arch=('i686' 'x86_64' 'mips64el') @@ -23,7 +23,7 @@ source=(http://opensource.conformal.com/snapshots/$pkgname/$pkgname-$pkgver.tgz LICENSE \ baraction.sh \ spectrwm-no-preload) -md5sums=('a638207b5e20ad1bfaf0a8ae61a69eef' +md5sums=('eb7d8c3db709551a90751ecc2157d6d1' 'a67cfe51079481e5b0eab1ad371379e3' '950d663692e1da56e0ac864c6c3ed80e' '974d109ce0af39cc73936d5efd682480') -- cgit v1.2.3 From 9109b256afe18368456ccdd593808c8693da54c8 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 26 May 2015 20:33:27 -0400 Subject: update libre/libretools --- libre/libretools/PKGBUILD | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'libre') diff --git a/libre/libretools/PKGBUILD b/libre/libretools/PKGBUILD index 75e5c9649..d67658e7e 100644 --- a/libre/libretools/PKGBUILD +++ b/libre/libretools/PKGBUILD @@ -9,11 +9,11 @@ pkgdesc="Programs for Parabola development" url="https://projects.parabola.nu/packages/libretools.git/" license=('GPL3' 'GPL2') -pkgver=20150105.1 -_libretools_commit=9c33131ece34a52341b1a31606d56329371fcce8 -_devtools_commit=5f4e575914fd597d31e5b9edd203eb6a8aa1306a -md5sums=('bcb043b5869e5b2b26d470f0b631d4b3' - '4fbe3aa6e7f87fa720547a8832d3419c') +pkgver=20150526 +_libretools_commit=a608070d29143f11826725ae0261bf0dcd902bc2 +_devtools_commit=b04dc724f01f47107b31b791950d22c27aca7d9b +md5sums=('81c7681cb6e8b94fa87e18cd8e4ef61a' + '84ce76368ddca3bd02198ebc4e85ab3f') _packages_url=https://projects.parabola.nu/packages source=($_packages_url/libretools.git/snapshot/libretools-$_libretools_commit.tar.bz2 -- cgit v1.2.3