diff -uNr linux-2.4.20/CREDITS linux-2.4.20-ben6/CREDITS --- linux-2.4.20/CREDITS 2002-11-29 00:53:08.000000000 +0100 +++ linux-2.4.20-ben6/CREDITS 2003-02-16 20:19:51.000000000 +0100 @@ -1488,7 +1488,7 @@ S: United Kingdom N: Ani Joshi -E: ajoshi@shell.unixbox.com +E: ajoshi@kernel.crashing.org D: fbdev hacking N: Bernhard Kaindl diff -uNr linux-2.4.20/Documentation/Configure.help linux-2.4.20-ben6/Documentation/Configure.help --- linux-2.4.20/Documentation/Configure.help 2002-11-29 00:53:08.000000000 +0100 +++ linux-2.4.20-ben6/Documentation/Configure.help 2003-02-16 20:21:36.000000000 +0100 @@ -26242,6 +26242,29 @@ If unsure, say N. +CONFIG_CPU_FREQ + Clock scaling allows you to change the clock speed of CPUs on the + fly. This is a nice method to save battery power on notebooks, + because the lower the clock speed, the less power the CPU consumes. + + For more information, take a look at linux/Documentation/cpufreq or + at + + If in doubt, say N. + +CONFIG_CPU_FREQ_24_API + This enables the /proc/sys/cpu/ sysctl interface for controlling + CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. Note + that some drivers do not support this interface or offer less + functionality. + + If you say N here, you'll be able to control CPUFreq using the + new /proc/cpufreq interface. + + For details, take a look at linux/Documentation/cpufreq. + + If in doubt, say N. + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -uNr linux-2.4.20/Documentation/cpufreq linux-2.4.20-ben6/Documentation/cpufreq --- linux-2.4.20/Documentation/cpufreq 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/Documentation/cpufreq 2003-02-16 20:21:11.000000000 +0100 @@ -0,0 +1,361 @@ + CPU frequency and voltage scaling code in the Linux(TM) kernel + + + L i n u x C P U F r e q + + + + + Dominik Brodowski + David Kimdon + + + + Clock scaling allows you to change the clock speed of the CPUs on the + fly. This is a nice method to save battery power, because the lower + the clock speed, the less power the CPU consumes. + + + +Contents: +--------- +1. Supported architectures +2. User interface +2.1 /proc/cpufreq interface [2.6] +2.2. /proc/sys/cpu/ interface [2.4] +3. CPUFreq core and interfaces +3.1 General information +3.2 CPUFreq notifiers +3.3 CPUFreq architecture drivers +4. Mailing list and Links + + + +1. Supported architectures +========================== + +ARM: + ARM Integrator, SA 1100, SA1110 +-------------------------------- + This driver will be ported to new CPUFreq core soon, so + far it will not work. + + +AMD Elan: + SC400, SC410 +-------------------------------- + You need to specify the highest allowed CPU frequency as + a module parameter ("max_freq") or as boot parameter + ("elanfreq="). Else the available speed range will be + limited to the speed at which the CPU runs while this + module is loaded. + + +VIA Cyrix Longhaul: + VIA Samuel/CyrixIII, VIA Cyrix Samuel/C3, + VIA Cyrix Ezra, VIA Cyrix Ezra-T +-------------------------------- + If you do not want to scale the Front Side Bus or voltage, + pass the module parameter "dont_scale_fsb 1" or + "dont_scale_voltage 1". Additionally, it is advised that + you pass the current Front Side Bus speed (in MHz) to + this module as module parameter "current_fsb", e.g. + "current_fsb 133" for a Front Side Bus speed of 133 MHz. + + +Intel SpeedStep: + certain mobile Intel Pentium III (Coppermine), and all mobile + Intel Pentium III-M (Tualatin) and mobile Intel Pentium 4 P4-Ms. +-------------------------------- + Unfortunately only modern Intel ICH2-M and ICH3-M chipsets are + supported. + + +P4 CPU Clock Modulation: + Intel Pentium 4 Xeon processors +--------------------------------- + Note that you can only switch the speed of two logical CPUs at + once - but each phyiscal CPU may have different throttling levels. + + +PowerNow! K6: + mobile AMD K6-2+ / mobile K6-3+: +-------------------------------- + No known issues. + + +Transmeta Crusoe Longrun: + Transmeta Crusoe processors: +-------------------------------- + Does not work with the 2.4. /proc/sys/cpu/ interface. + + + +2. User Interface +================= + +2.1 /proc/cpufreq interface [2.6] +*********************************** + +Starting in the patches for kernel 2.5.33, CPUFreq uses a "policy" +interface /proc/cpufreq. + +When you "cat" this file, you'll find something like: + +-- + minimum CPU frequency - maximum CPU frequency - policy +CPU 0 1200000 ( 75%) - 1600000 (100%) - performance +-- + +This means the current policy allows this CPU to be run anywhere +between 1.2 GHz (the value is in kHz) and 1.6 GHz with an eye towards +performance. + +To change the policy, "echo" the desired new policy into +/proc/cpufreq. Use one of the following formats: + +cpu_nr:min_freq:max_freq:policy +cpu_nr%min_freq%max_freq%policy +min_freq:max_freq:policy +min_freq%max_freq%policy + +with cpu_nr being the CPU which shall be affected, min_freq and +max_freq the lower and upper limit of the CPU core frequency in kHz, +and policy either "performance" or "powersave". +A few examples: + +root@notebook:#echo -n "0:0:0:powersave" > /proc/cpufreq + sets the CPU #0 to the lowest supported frequency. + +root@notebook:#echo -n "1%100%100%performance" > /proc/cpufreq + sets the CPU #1 to the highest supported frequency. + +root@notebook:#echo -n "1000000:2000000:performance" > /proc/cpufreq + to set the frequency of all CPUs between 1 GHz and 2 GHz and to + the policy "performance". + +Please note that the values you "echo" into /proc/cpufreq are +validated first, and may be limited by hardware or thermal +considerations. Because of this, a read from /proc/cpufreq might +differ from what was written into it. + + +When you read /proc/cpufreq for the first time after a CPUFreq driver +has been initialized, you'll see the "default policy" for this +driver. If this does not suit your needs, you can pass a boot +parameter to the cpufreq core. Use the following syntax for this: + "cpufreq=min_freq:max_freq:policy", i.e. you may not chose a +specific CPU and you need to specify the limits in kHz and not in +per cent. + + +2.2 /proc/cpufreq interface [2.4] +*********************************** + +Previsiously (and still available as a config option), CPUFreq used +a "sysctl" interface which is located in + /proc/sys/cpu/0/ + /proc/sys/cpu/1/ ... (SMP only) + +In these directories, you will find three files of importance for +CPUFreq: speed-max, speed-min and speed: + +speed shows the current CPU frequency in kHz, +speed-min the minimum supported CPU frequency, and +speed-max the maximum supported CPU frequency. + + +To change the CPU frequency, "echo" the desired CPU frequency (in kHz) +to speed. For example, to set the CPU speed to the lowest/highest +allowed frequency do: + +root@notebook:# cat /proc/sys/cpu/0/speed-min > /proc/sys/cpu/0/speed +root@notebook:# cat /proc/sys/cpu/0/speed-max > /proc/sys/cpu/0/speed + + + +3. CPUFreq core and interfaces +=============================== + +3.1 General information +************************* + +The CPUFreq core code is located in linux/kernel/cpufreq.c. This +cpufreq code offers a standardized interface for the CPUFreq +architecture drivers (those pieces of code that do actual +frequency transitions), as well as to "notifiers". These are device +drivers or other part of the kernel that need to be informed of +policy changes (like thermal modules like ACPI) or of all +frequency changes (like timing code) or even need to force certain +speed limits (like LCD drivers on ARM architecture). Additionally, the +kernel "constant" loops_per_jiffy is updated on frequency changes +here. + + +3.2 CPUFreq notifiers +*********************** + +CPUFreq notifiers conform to the standard kernel notifier interface. +See linux/include/linux/notifier.h for details on notifiers. + +There are two different CPUFreq notifiers - policy notifiers and +transition notifiers. + + +3.2.1 CPUFreq policy notifiers +****************************** + +These are notified when a new policy is intended to be set. Each +CPUFreq policy notifier is called three times for a policy transition: + +1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if + they see a need for this - may it be thermal considerations or + hardware limitations. + +2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid + hardware failure. + +3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy + - if two hardware drivers failed to agree on a new policy before this + stage, the incompatible hardware shall be shut down, and the user + informed of this. + +The phase is specified in the second argument to the notifier. + +The third argument, a void *pointer, points to a struct cpufreq_policy +consisting of five values: cpu, min, max, policy and max_cpu_freq. Min +and max are the lower and upper frequencies (in kHz) of the new +policy, policy the new policy, cpu the number of the affected CPU or +CPUFREQ_ALL_CPUS for all CPUs; and max_cpu_freq the maximum supported +CPU frequency. This value is given for informational purposes only. + + +3.2.2 CPUFreq transition notifiers +********************************** + +These are notified twice when the CPUfreq driver switches the CPU core +frequency and this change has any external implications. + +The second argument specifies the phase - CPUFREQ_PRECHANGE or +CPUFREQ_POSTCHANGE. + +The third argument is a struct cpufreq_freqs with the following +values: +cpu - number of the affected CPU or CPUFREQ_ALL_CPUS +old - old frequency +new - new frequency + + +3.3 CPUFreq architecture drivers +********************************** + +CPUFreq architecture drivers are the pieces of kernel code that +actually perform CPU frequency transitions. These need to be +initialized separately (separate initcalls), and may be +modularized. They interact with the CPUFreq core in the following way: + +cpufreq_register() +------------------ +cpufreq_register registers an arch driver to the CPUFreq core. Please +note that only one arch driver may be registered at any time. -EBUSY +is returned when an arch driver is already registered. The argument to +cpufreq_register, struct cpufreq_driver *driver, is described later. + +cpufreq_unregister() +-------------------- +cpufreq_unregister unregisters an arch driver, e.g. on module +unloading. Please note that there is no check done that this is called +from the driver which actually registered itself to the core, so +please only call this function when you are sure the arch driver got +registered correctly before. + +cpufreq_notify_transition() +--------------------------- +On "dumb" hardware where only fixed frequency can be set, the driver +must call cpufreq_notify_transition() once before, and once after the +actual transition. + +struct cpufreq_driver +--------------------- +On initialization, the arch driver is supposed to pass a pointer +to a struct cpufreq_driver *cpufreq_driver consisting of the following +entries: + +cpufreq_verify_t verify: This is a pointer to a function with the + following definition: + void verify_function (struct cpufreq_policy *policy). + This function must verify the new policy is within the limits + supported by the CPU, and at least one supported CPU is within + this range. It may be useful to use cpufreq.h / + cpufreq_verify_within_limits for this. + +cpufreq_setpolicy_t setpolicy: This is a pointer to a function with + the following definition: + void setpolicy_function (struct cpufreq_policy *policy). + This function must set the CPU to the new policy. If it is a + "dumb" CPU which only allows fixed frequencies to be set, it + shall set it to the lowest within the limit for + CPUFREQ_POLICY_POWERSAVE, and to the highest for + CPUFREQ_POLICY_PERFORMANCE. Once CONFIG_CPU_FREQ_DYNAMIC is + implemented, it can use a dynamic method to adjust the speed + between the lower and upper limit. + +struct cpufreq_policy *policy: This is an array of NR_CPUS struct + cpufreq_policies, containing the current policies set for these + CPUs. Note that policy[0].max_cpu_freq must contain the + absolute maximum CPU frequency supported by _all_ CPUs. + +In case the driver is expected to run with the 2.4.-style API +(/proc/sys/cpu/.../), two more values must be passed +#ifdef CONFIG_CPU_FREQ_24_API + unsigned int cpu_min_freq; + unsigned int cpu_cur_freq[NR_CPUS]; +#endif + with cpu_min_freq being the minimum CPU frequency supported by + the CPUs; and the entries in cpu_cur_freq reflecting the + current speed of the appropriate CPU. + +Some Requirements to CPUFreq architecture drivers +------------------------------------------------- +* Only call cpufreq_register() when the ability to switch CPU + frequencies is _verified_ or can't be missing +* cpufreq_unregister() may only be called if cpufreq_register() has + been successfully(!) called before. +* kfree() the struct cpufreq_driver only after the call to + cpufreq_unregister(), unless cpufreq_register() failed. +* Be aware that there is currently no error management in the + setpolicy() code in the CPUFreq core. So only call yourself a + cpufreq_driver if you are really a working cpufreq_driver! + + + +4. Mailing list and Links +************************* + + +Mailing List +------------ +There is a CPU frequency changing CVS commit and general list where +you can report bugs, problems or submit patches. To post a message, +send an email to cpufreq@www.linux.org.uk, to subscribe go to +http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the +mailing list are available to subscribers at +http://www.linux.org.uk/mailman/private/cpufreq/. + + +Links +----- +the FTP archives: +* ftp://ftp.linux.org.uk/pub/linux/cpufreq/ + +how to access the CVS repository: +* http://cvs.arm.linux.org.uk/ + +the CPUFreq Mailing list: +* http://www.linux.org.uk/mailman/listinfo/cpufreq + +Clock and voltage scaling for the SA-1100: +* http://www.lart.tudelft.nl/projects/scaling + +CPUFreq project homepage +* http://www.brodo.de/cpufreq/ diff -uNr linux-2.4.20/MAINTAINERS linux-2.4.20-ben6/MAINTAINERS --- linux-2.4.20/MAINTAINERS 2002-11-29 00:53:08.000000000 +0100 +++ linux-2.4.20-ben6/MAINTAINERS 2003-02-16 20:20:13.000000000 +0100 @@ -1160,8 +1160,8 @@ NVIDIA (RIVA) FRAMEBUFFER DRIVER P: Ani Joshi -M: ajoshi@shell.unixbox.com -L: linux-nvidia@lists.surfsouth.com +M: ajoshi@kernel.crashing.org +L: linux-fbdev-devel@lists.sourceforge.net S: Maintained OLYMPIC NETWORK DRIVER @@ -1336,13 +1336,13 @@ RADEON FRAMEBUFFER DISPLAY DRIVER P: Ani Joshi -M: ajoshi@shell.unixbox.com +M: ajoshi@kernel.crashing.org L: linux-fbdev-devel@lists.sourceforge.net S: Maintained RAGE128 FRAMEBUFFER DISPLAY DRIVER P: Ani Joshi -M: ajoshi@shell.unixbox.com +M: ajoshi@kernel.crashing.org L: linux-fbdev-devel@lists.sourceforge.net S: Maintained diff -uNr linux-2.4.20/Makefile linux-2.4.20-ben6/Makefile --- linux-2.4.20/Makefile 2002-11-29 00:53:16.000000000 +0100 +++ linux-2.4.20-ben6/Makefile 2003-02-16 20:21:38.000000000 +0100 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 20 -EXTRAVERSION = +EXTRAVERSION = -ben6 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -uNr linux-2.4.20/arch/alpha/mm/fault.c linux-2.4.20-ben6/arch/alpha/mm/fault.c --- linux-2.4.20/arch/alpha/mm/fault.c 2002-11-29 00:53:08.000000000 +0100 +++ linux-2.4.20-ben6/arch/alpha/mm/fault.c 2003-02-16 20:20:03.000000000 +0100 @@ -124,7 +124,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -uNr linux-2.4.20/arch/arm/mm/fault-common.c linux-2.4.20-ben6/arch/arm/mm/fault-common.c --- linux-2.4.20/arch/arm/mm/fault-common.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.20-ben6/arch/arm/mm/fault-common.c 2003-02-16 20:21:47.000000000 +0100 @@ -229,7 +229,7 @@ goto survive; check_stack: - if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) + if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr, NULL)) goto good_area; out: return fault; diff -uNr linux-2.4.20/arch/cris/mm/fault.c linux-2.4.20-ben6/arch/cris/mm/fault.c --- linux-2.4.20/arch/cris/mm/fault.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.20-ben6/arch/cris/mm/fault.c 2003-02-16 20:20:13.000000000 +0100 @@ -315,7 +315,7 @@ if (address + PAGE_SIZE < rdusp()) goto bad_area; } - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; /* diff -uNr linux-2.4.20/arch/i386/mm/fault.c linux-2.4.20-ben6/arch/i386/mm/fault.c --- linux-2.4.20/arch/i386/mm/fault.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.20-ben6/arch/i386/mm/fault.c 2003-02-16 20:19:53.000000000 +0100 @@ -32,7 +32,7 @@ */ int __verify_write(const void * addr, unsigned long size) { - struct vm_area_struct * vma; + struct vm_area_struct * vma, * prev_vma; unsigned long start = (unsigned long) addr; if (!size) @@ -78,7 +78,8 @@ check_stack: if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, start) == 0) + find_vma_prev(current->mm, start, &prev_vma); + if (expand_stack(vma, start, prev_vma) == 0) goto good_area; bad_area: @@ -141,7 +142,7 @@ { struct task_struct *tsk; struct mm_struct *mm; - struct vm_area_struct * vma; + struct vm_area_struct * vma, * prev_vma; unsigned long address; unsigned long page; unsigned long fixup; @@ -202,7 +203,8 @@ if (address + 32 < regs->esp) goto bad_area; } - if (expand_stack(vma, address)) + find_vma_prev(mm, address, &prev_vma); + if (expand_stack(vma, address, prev_vma)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -uNr linux-2.4.20/arch/ia64/mm/fault.c linux-2.4.20-ben6/arch/ia64/mm/fault.c --- linux-2.4.20/arch/ia64/mm/fault.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.20-ben6/arch/ia64/mm/fault.c 2003-02-16 20:20:03.000000000 +0100 @@ -134,7 +134,7 @@ if (rgn_index(address) != rgn_index(vma->vm_start) || rgn_offset(address) >= RGN_MAP_LIMIT) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; } else { vma = prev_vma; diff -uNr linux-2.4.20/arch/m68k/mm/fault.c linux-2.4.20-ben6/arch/m68k/mm/fault.c --- linux-2.4.20/arch/m68k/mm/fault.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.20-ben6/arch/m68k/mm/fault.c 2003-02-16 20:21:17.000000000 +0100 @@ -120,7 +120,7 @@ if (address + 256 < rdusp()) goto map_err; } - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto map_err; /* diff -uNr linux-2.4.20/arch/mips/mm/fault.c linux-2.4.20-ben6/arch/mips/mm/fault.c --- linux-2.4.20/arch/mips/mm/fault.c 2002-11-29 00:53:10.000000000 +0100 +++ linux-2.4.20-ben6/arch/mips/mm/fault.c 2003-02-16 20:19:51.000000000 +0100 @@ -113,7 +113,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -uNr linux-2.4.20/arch/mips64/mm/fault.c linux-2.4.20-ben6/arch/mips64/mm/fault.c --- linux-2.4.20/arch/mips64/mm/fault.c 2002-11-29 00:53:10.000000000 +0100 +++ linux-2.4.20-ben6/arch/mips64/mm/fault.c 2003-02-16 20:20:40.000000000 +0100 @@ -137,7 +137,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -uNr linux-2.4.20/arch/ppc/8260_io/Makefile linux-2.4.20-ben6/arch/ppc/8260_io/Makefile --- linux-2.4.20/arch/ppc/8260_io/Makefile 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/8260_io/Makefile 2003-02-16 20:20:24.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:19 cort +# BK Id: SCCS/s.Makefile 1.5 06/05/01 21:22:01 paulus # # # Makefile for the linux MPC8xx ppc-specific parts of comm processor diff -uNr linux-2.4.20/arch/ppc/8260_io/commproc.c linux-2.4.20-ben6/arch/ppc/8260_io/commproc.c --- linux-2.4.20/arch/ppc/8260_io/commproc.c 2001-11-03 02:43:54.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/8260_io/commproc.c 2003-02-16 20:21:40.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.commproc.c 1.10 10/16/01 16:21:52 trini + * BK Id: SCCS/s.commproc.c 1.11 11/04/01 22:58:20 paulus */ /* diff -uNr linux-2.4.20/arch/ppc/8260_io/enet.c linux-2.4.20-ben6/arch/ppc/8260_io/enet.c --- linux-2.4.20/arch/ppc/8260_io/enet.c 2001-10-08 20:40:13.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/8260_io/enet.c 2003-02-16 20:19:53.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.enet.c 1.9 09/14/01 18:01:16 trini + * BK Id: SCCS/s.enet.c 1.10 10/08/01 16:49:24 trini */ /* * Ethernet driver for Motorola MPC8260. diff -uNr linux-2.4.20/arch/ppc/8260_io/fcc_enet.c linux-2.4.20-ben6/arch/ppc/8260_io/fcc_enet.c --- linux-2.4.20/arch/ppc/8260_io/fcc_enet.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/8260_io/fcc_enet.c 2003-02-16 20:21:04.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fcc_enet.c 1.7 05/17/01 18:14:20 cort + * BK Id: SCCS/s.fcc_enet.c 1.11 06/05/01 21:22:01 paulus */ /* * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. diff -uNr linux-2.4.20/arch/ppc/8260_io/uart.c linux-2.4.20-ben6/arch/ppc/8260_io/uart.c --- linux-2.4.20/arch/ppc/8260_io/uart.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/8260_io/uart.c 2003-02-16 20:20:39.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.uart.c 1.13 12/29/01 14:50:03 trini + * BK Id: SCCS/s.uart.c 1.16 11/19/02 08:55:00 trini */ /* * UART driver for MPC8260 CPM SCC or SMC @@ -910,9 +910,9 @@ * enables, because we want to put them back if they were * present. */ - prev_mode = smcp->smc_smcmr; - smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; - smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); + prev_mode = smcp->smc_smcmr & (SMCMR_REN | SMCMR_TEN); + smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART + | prev_mode; } else { sccp = &immr->im_scc[idx - SCC_IDX_BASE]; diff -uNr linux-2.4.20/arch/ppc/8xx_io/Makefile linux-2.4.20-ben6/arch/ppc/8xx_io/Makefile --- linux-2.4.20/arch/ppc/8xx_io/Makefile 2001-09-08 21:39:33.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/8xx_io/Makefile 2003-02-16 20:20:13.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.6 08/30/01 09:33:48 trini +# BK Id: SCCS/s.Makefile 1.7 09/09/01 12:20:42 trini # # # Makefile for the linux MPC8xx ppc-specific parts of comm processor diff -uNr linux-2.4.20/arch/ppc/8xx_io/commproc.c linux-2.4.20-ben6/arch/ppc/8xx_io/commproc.c --- linux-2.4.20/arch/ppc/8xx_io/commproc.c 2001-11-03 02:43:54.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/8xx_io/commproc.c 2003-02-16 20:20:21.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.commproc.c 1.15 10/16/01 16:21:52 trini + * BK Id: SCCS/s.commproc.c 1.16 11/04/01 22:58:20 paulus */ /* diff -uNr linux-2.4.20/arch/ppc/8xx_io/enet.c linux-2.4.20-ben6/arch/ppc/8xx_io/enet.c --- linux-2.4.20/arch/ppc/8xx_io/enet.c 2001-10-17 23:37:01.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/8xx_io/enet.c 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.enet.c 1.17 10/11/01 11:55:47 trini + * BK Id: SCCS/s.enet.c 1.18 10/17/01 18:40:00 trini */ /* * Ethernet driver for Motorola MPC8xx. diff -uNr linux-2.4.20/arch/ppc/8xx_io/fec.c linux-2.4.20-ben6/arch/ppc/8xx_io/fec.c --- linux-2.4.20/arch/ppc/8xx_io/fec.c 2002-11-29 00:53:10.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/8xx_io/fec.c 2003-02-16 20:20:00.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.fec.c 1.24 09/11/02 14:41:30 paulus */ /* * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. diff -uNr linux-2.4.20/arch/ppc/8xx_io/uart.c linux-2.4.20-ben6/arch/ppc/8xx_io/uart.c --- linux-2.4.20/arch/ppc/8xx_io/uart.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/8xx_io/uart.c 2003-02-16 20:20:04.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.uart.c 1.23 12/29/01 14:50:03 trini + * BK Id: SCCS/s.uart.c 1.26 11/19/02 08:55:00 trini */ /* * UART driver for MPC860 CPM SCC or SMC @@ -1008,9 +1008,9 @@ * enables, because we want to put them back if they were * present. */ - prev_mode = smcp->smc_smcmr; - new_mode = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; - new_mode |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); + prev_mode = smcp->smc_smcmr & (SMCMR_REN | SMCMR_TEN); + new_mode = smcr_mk_clen(bits) | cval | SMCMR_SM_UART + | prev_mode; if (!(prev_mode & SMCMR_PEN)) /* If parity is disabled, mask out even/odd */ prev_mode &= ~SMCMR_PM_EVEN; diff -uNr linux-2.4.20/arch/ppc/Makefile linux-2.4.20-ben6/arch/ppc/Makefile --- linux-2.4.20/arch/ppc/Makefile 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/Makefile 2003-02-16 20:21:14.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: %F% %I% %G% %U% %#% +# BK Id: SCCS/s.Makefile 1.31 11/27/02 12:15:43 benh # # This file is included by the global makefile so that you can add your own # architecture-specific flags and dependencies. Remember to do have actions diff -uNr linux-2.4.20/arch/ppc/amiga/Makefile linux-2.4.20-ben6/arch/ppc/amiga/Makefile --- linux-2.4.20/arch/ppc/amiga/Makefile 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/amiga/Makefile 2003-02-16 20:19:54.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.5 05/21/01 00:48:24 cort +# BK Id: SCCS/s.Makefile 1.7 06/05/01 21:22:02 paulus # # # Makefile for Linux arch/m68k/amiga source directory diff -uNr linux-2.4.20/arch/ppc/amiga/amiga_ksyms.c linux-2.4.20-ben6/arch/ppc/amiga/amiga_ksyms.c --- linux-2.4.20/arch/ppc/amiga/amiga_ksyms.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/amiga/amiga_ksyms.c 2003-02-16 20:21:30.000000000 +0100 @@ -1,4 +1,4 @@ /* - * BK Id: SCCS/s.amiga_ksyms.c 1.5 05/17/01 18:14:20 cort + * BK Id: SCCS/s.amiga_ksyms.c 1.7 06/05/01 21:22:02 paulus */ #include "../../m68k/amiga/amiga_ksyms.c" diff -uNr linux-2.4.20/arch/ppc/amiga/amiints.c linux-2.4.20-ben6/arch/ppc/amiga/amiints.c --- linux-2.4.20/arch/ppc/amiga/amiints.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/amiga/amiints.c 2003-02-16 20:21:37.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.amiints.c 1.11 08/29/02 13:07:54 paulus */ /* * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code diff -uNr linux-2.4.20/arch/ppc/amiga/amisound.c linux-2.4.20-ben6/arch/ppc/amiga/amisound.c --- linux-2.4.20/arch/ppc/amiga/amisound.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/amiga/amisound.c 2003-02-16 20:20:41.000000000 +0100 @@ -1,4 +1,4 @@ /* - * BK Id: SCCS/s.amisound.c 1.5 05/17/01 18:14:20 cort + * BK Id: SCCS/s.amisound.c 1.7 06/05/01 21:22:02 paulus */ #include "../../m68k/amiga/amisound.c" diff -uNr linux-2.4.20/arch/ppc/amiga/bootinfo.c linux-2.4.20-ben6/arch/ppc/amiga/bootinfo.c --- linux-2.4.20/arch/ppc/amiga/bootinfo.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/amiga/bootinfo.c 2003-02-16 20:20:00.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.bootinfo.c 1.5 05/17/01 18:14:20 cort + * BK Id: SCCS/s.bootinfo.c 1.7 06/05/01 21:22:02 paulus */ /* * linux/arch/ppc/amiga/bootinfo.c diff -uNr linux-2.4.20/arch/ppc/amiga/chipram.c linux-2.4.20-ben6/arch/ppc/amiga/chipram.c --- linux-2.4.20/arch/ppc/amiga/chipram.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/amiga/chipram.c 2003-02-16 20:20:09.000000000 +0100 @@ -1,4 +1,4 @@ /* - * BK Id: SCCS/s.chipram.c 1.7 05/21/01 00:49:49 cort + * BK Id: SCCS/s.chipram.c 1.9 06/05/01 21:22:02 paulus */ #include "../../m68k/amiga/chipram.c" diff -uNr linux-2.4.20/arch/ppc/amiga/cia.c linux-2.4.20-ben6/arch/ppc/amiga/cia.c --- linux-2.4.20/arch/ppc/amiga/cia.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/amiga/cia.c 2003-02-16 20:20:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.cia.c 1.10 08/29/02 13:07:54 paulus */ /* * linux/arch/m68k/amiga/cia.c - CIA support diff -uNr linux-2.4.20/arch/ppc/amiga/config.c linux-2.4.20-ben6/arch/ppc/amiga/config.c --- linux-2.4.20/arch/ppc/amiga/config.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/amiga/config.c 2003-02-16 20:19:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.config.c 1.16 08/29/02 13:07:54 paulus */ #define m68k_debug_device debug_device diff -uNr linux-2.4.20/arch/ppc/amiga/ints.c linux-2.4.20-ben6/arch/ppc/amiga/ints.c --- linux-2.4.20/arch/ppc/amiga/ints.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/amiga/ints.c 2003-02-16 20:21:11.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ints.c 1.5 05/17/01 18:14:20 cort + * BK Id: SCCS/s.ints.c 1.7 06/05/01 21:22:02 paulus */ /* * linux/arch/ppc/amiga/ints.c diff -uNr linux-2.4.20/arch/ppc/amiga/pcmcia.c linux-2.4.20-ben6/arch/ppc/amiga/pcmcia.c --- linux-2.4.20/arch/ppc/amiga/pcmcia.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/amiga/pcmcia.c 2003-02-16 20:20:24.000000000 +0100 @@ -1,4 +1,4 @@ /* - * BK Id: SCCS/s.pcmcia.c 1.5 05/17/01 18:14:20 cort + * BK Id: SCCS/s.pcmcia.c 1.7 06/05/01 21:22:02 paulus */ #include "../../m68k/amiga/pcmcia.c" diff -uNr linux-2.4.20/arch/ppc/amiga/time.c linux-2.4.20-ben6/arch/ppc/amiga/time.c --- linux-2.4.20/arch/ppc/amiga/time.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/amiga/time.c 2003-02-16 20:21:33.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.time.c 1.9 10/09/02 10:28:17 paulus */ #include /* CONFIG_HEARTBEAT */ #include diff -uNr linux-2.4.20/arch/ppc/boot/chrp/Makefile linux-2.4.20-ben6/arch/ppc/boot/chrp/Makefile --- linux-2.4.20/arch/ppc/boot/chrp/Makefile 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/chrp/Makefile 2003-02-16 20:20:40.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.15 01/11/02 10:46:06 trini +# BK Id: SCCS/s.Makefile 1.16 03/07/02 13:42:36 trini # # Makefile for making ELF bootable images for booting on CHRP # using Open Firmware. diff -uNr linux-2.4.20/arch/ppc/boot/chrp/main.c linux-2.4.20-ben6/arch/ppc/boot/chrp/main.c --- linux-2.4.20/arch/ppc/boot/chrp/main.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/chrp/main.c 2003-02-16 20:19:50.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.main.c 1.16 01/12/02 10:36:33 trini + * BK Id: SCCS/s.main.c 1.17 03/07/02 13:42:36 trini */ /* * Copyright (C) Paul Mackerras 1997. diff -uNr linux-2.4.20/arch/ppc/boot/chrp/misc.S linux-2.4.20-ben6/arch/ppc/boot/chrp/misc.S --- linux-2.4.20/arch/ppc/boot/chrp/misc.S 2001-05-25 00:02:06.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/chrp/misc.S 2003-02-16 20:21:15.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:16:59 cort + * BK Id: SCCS/s.misc.S 1.7 06/05/01 20:20:04 paulus */ /* * Copyright (C) Paul Mackerras 1997. diff -uNr linux-2.4.20/arch/ppc/boot/chrp/start.c linux-2.4.20-ben6/arch/ppc/boot/chrp/start.c --- linux-2.4.20/arch/ppc/boot/chrp/start.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/chrp/start.c 2003-02-16 20:20:00.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.start.c 1.8 07/25/01 18:13:07 trini + * BK Id: SCCS/s.start.c 1.10 06/25/02 10:29:26 paulus */ /* * Copyright (C) Paul Mackerras 1997. diff -uNr linux-2.4.20/arch/ppc/boot/common/crt0.S linux-2.4.20-ben6/arch/ppc/boot/common/crt0.S --- linux-2.4.20/arch/ppc/boot/common/crt0.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/boot/common/crt0.S 2003-02-16 20:21:30.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.crt0.S 1.14 01/11/02 10:46:07 trini + * BK Id: SCCS/s.crt0.S 1.16 08/13/02 20:27:36 paulus */ /* Copyright (c) 1997 Paul Mackerras * Initial Power Macintosh COFF version. diff -uNr linux-2.4.20/arch/ppc/boot/common/ns16550.c linux-2.4.20-ben6/arch/ppc/boot/common/ns16550.c --- linux-2.4.20/arch/ppc/boot/common/ns16550.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/common/ns16550.c 2003-02-16 20:20:04.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ns16550.c 1.16 03/13/02 09:17:06 trini + * BK Id: SCCS/s.ns16550.c 1.17 04/16/02 20:08:22 paulus */ /* * COM1 NS16550 support diff -uNr linux-2.4.20/arch/ppc/boot/common/string.S linux-2.4.20-ben6/arch/ppc/boot/common/string.S --- linux-2.4.20/arch/ppc/boot/common/string.S 2001-05-25 00:02:06.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/common/string.S 2003-02-16 20:21:07.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.string.S 1.8 05/18/01 06:20:29 patch + * BK Id: SCCS/s.string.S 1.9 06/05/01 20:01:06 paulus */ /* * String handling functions for PowerPC. diff -uNr linux-2.4.20/arch/ppc/boot/include/nonstdio.h linux-2.4.20-ben6/arch/ppc/boot/include/nonstdio.h --- linux-2.4.20/arch/ppc/boot/include/nonstdio.h 2001-08-28 15:58:33.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/include/nonstdio.h 2003-02-16 20:19:57.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.nonstdio.h 1.9 07/25/01 18:13:07 trini + * BK Id: SCCS/s.nonstdio.h 1.10 08/29/01 08:49:23 paulus */ /* * Copyright (C) Paul Mackerras 1997. diff -uNr linux-2.4.20/arch/ppc/boot/include/rs6000.h linux-2.4.20-ben6/arch/ppc/boot/include/rs6000.h --- linux-2.4.20/arch/ppc/boot/include/rs6000.h 2001-05-25 00:02:06.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/include/rs6000.h 2003-02-16 20:20:35.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.rs6000.h 1.7 05/18/01 15:17:23 cort + * BK Id: SCCS/s.rs6000.h 1.8 06/05/01 20:20:05 paulus */ /* IBM RS/6000 "XCOFF" file definitions for BFD. Copyright (C) 1990, 1991 Free Software Foundation, Inc. diff -uNr linux-2.4.20/arch/ppc/boot/include/zlib.h linux-2.4.20-ben6/arch/ppc/boot/include/zlib.h --- linux-2.4.20/arch/ppc/boot/include/zlib.h 2001-05-25 00:02:06.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/include/zlib.h 2003-02-16 20:19:54.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.zlib.h 1.8 05/18/01 15:17:23 cort + * BK Id: SCCS/s.zlib.h 1.9 06/05/01 20:20:05 paulus */ /* * This file is derived from zlib.h and zconf.h from the zlib-0.95 diff -uNr linux-2.4.20/arch/ppc/boot/lib/zlib.c linux-2.4.20-ben6/arch/ppc/boot/lib/zlib.c --- linux-2.4.20/arch/ppc/boot/lib/zlib.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/lib/zlib.c 2003-02-16 20:21:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.zlib.c 1.9 12/05/01 16:19:42 mporter + * BK Id: SCCS/s.zlib.c 1.12 03/21/02 14:10:28 trini */ /* * This file is derived from various .h and .c files from the zlib-0.95 diff -uNr linux-2.4.20/arch/ppc/boot/pmac/Makefile linux-2.4.20-ben6/arch/ppc/boot/pmac/Makefile --- linux-2.4.20/arch/ppc/boot/pmac/Makefile 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/pmac/Makefile 2003-02-16 20:21:46.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.19 01/16/02 11:08:07 trini +# BK Id: SCCS/s.Makefile 1.20 03/07/02 13:42:36 trini # # Makefile for making XCOFF bootable images for booting on PowerMacs # using Open Firmware. diff -uNr linux-2.4.20/arch/ppc/boot/pmac/chrpmain.c linux-2.4.20-ben6/arch/ppc/boot/pmac/chrpmain.c --- linux-2.4.20/arch/ppc/boot/pmac/chrpmain.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/pmac/chrpmain.c 2003-02-16 20:21:42.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.chrpmain.c 1.18 01/11/02 10:46:07 trini + * BK Id: SCCS/s.chrpmain.c 1.19 03/07/02 13:42:37 trini */ /* * Copyright (C) Paul Mackerras 1997. diff -uNr linux-2.4.20/arch/ppc/boot/pmac/misc.S linux-2.4.20-ben6/arch/ppc/boot/pmac/misc.S --- linux-2.4.20/arch/ppc/boot/pmac/misc.S 2001-05-25 00:02:07.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/pmac/misc.S 2003-02-16 20:20:13.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:17:15 cort + * BK Id: SCCS/s.misc.S 1.7 06/05/01 20:20:05 paulus */ /* * Copyright (C) Paul Mackerras 1997. diff -uNr linux-2.4.20/arch/ppc/boot/pmac/start.c linux-2.4.20-ben6/arch/ppc/boot/pmac/start.c --- linux-2.4.20/arch/ppc/boot/pmac/start.c 2001-08-28 15:58:33.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/pmac/start.c 2003-02-16 20:21:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.start.c 1.10 07/25/01 18:13:07 trini + * BK Id: SCCS/s.start.c 1.11 08/29/01 08:49:23 paulus */ /* * Copyright (C) Paul Mackerras 1997. diff -uNr linux-2.4.20/arch/ppc/boot/prep/Makefile linux-2.4.20-ben6/arch/ppc/boot/prep/Makefile --- linux-2.4.20/arch/ppc/boot/prep/Makefile 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/prep/Makefile 2003-02-16 20:21:51.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.30 01/26/02 12:27:41 trini +# BK Id: SCCS/s.Makefile 1.32 08/29/02 13:11:12 paulus # # arch/ppc/boot/Makefile # diff -uNr linux-2.4.20/arch/ppc/boot/prep/head.S linux-2.4.20-ben6/arch/ppc/boot/prep/head.S --- linux-2.4.20/arch/ppc/boot/prep/head.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/boot/prep/head.S 2003-02-16 20:19:53.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head.S 1.13 01/11/02 10:46:07 trini + * BK Id: SCCS/s.head.S 1.15 08/13/02 21:25:13 paulus */ #include diff -uNr linux-2.4.20/arch/ppc/boot/prep/iso_font.h linux-2.4.20-ben6/arch/ppc/boot/prep/iso_font.h --- linux-2.4.20/arch/ppc/boot/prep/iso_font.h 2001-05-25 00:02:07.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/prep/iso_font.h 2003-02-16 20:21:14.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.iso_font.h 1.6 05/18/01 15:16:42 cort + * BK Id: SCCS/s.iso_font.h 1.7 06/05/01 20:20:05 paulus */ static const unsigned char font[] = { /* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff -uNr linux-2.4.20/arch/ppc/boot/prep/kbd.c linux-2.4.20-ben6/arch/ppc/boot/prep/kbd.c --- linux-2.4.20/arch/ppc/boot/prep/kbd.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/prep/kbd.c 2003-02-16 20:20:34.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.kbd.c 1.9 01/11/02 10:46:07 trini + * BK Id: SCCS/s.kbd.c 1.10 03/07/02 13:42:37 trini */ #include diff -uNr linux-2.4.20/arch/ppc/boot/prep/misc.c linux-2.4.20-ben6/arch/ppc/boot/prep/misc.c --- linux-2.4.20/arch/ppc/boot/prep/misc.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/prep/misc.c 2003-02-16 20:19:53.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.c 1.25 01/26/02 12:27:41 trini + * BK Id: SCCS/s.misc.c 1.27 03/07/02 13:42:37 trini * * arch/ppc/boot/prep/misc.c * diff -uNr linux-2.4.20/arch/ppc/boot/prep/of1275.c linux-2.4.20-ben6/arch/ppc/boot/prep/of1275.c --- linux-2.4.20/arch/ppc/boot/prep/of1275.c 2001-05-25 00:02:07.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/prep/of1275.c 2003-02-16 20:20:25.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.of1275.c 1.6 05/18/01 15:16:42 cort + * BK Id: SCCS/s.of1275.c 1.7 06/05/01 20:20:05 paulus */ /* Open Firmware Client Interface */ diff -uNr linux-2.4.20/arch/ppc/boot/prep/of1275.h linux-2.4.20-ben6/arch/ppc/boot/prep/of1275.h --- linux-2.4.20/arch/ppc/boot/prep/of1275.h 2001-05-25 00:02:07.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/prep/of1275.h 2003-02-16 20:20:23.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.of1275.h 1.6 05/18/01 15:16:42 cort + * BK Id: SCCS/s.of1275.h 1.7 06/05/01 20:20:05 paulus */ /* 6.3.2.1 Client interface */ diff -uNr linux-2.4.20/arch/ppc/boot/prep/vreset.c linux-2.4.20-ben6/arch/ppc/boot/prep/vreset.c --- linux-2.4.20/arch/ppc/boot/prep/vreset.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/prep/vreset.c 2003-02-16 20:20:31.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.vreset.c 1.13 01/11/02 10:46:08 trini + * BK Id: SCCS/s.vreset.c 1.14 03/07/02 13:42:37 trini */ /* * vreset.c diff -uNr linux-2.4.20/arch/ppc/boot/utils/addnote.c linux-2.4.20-ben6/arch/ppc/boot/utils/addnote.c --- linux-2.4.20/arch/ppc/boot/utils/addnote.c 2001-05-25 00:02:07.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/utils/addnote.c 2003-02-16 20:19:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.addnote.c 1.7 05/18/01 15:17:23 cort + * BK Id: SCCS/s.addnote.c 1.8 06/05/01 20:20:06 paulus */ /* * Program to hack in a PT_NOTE program header entry in an ELF file. diff -uNr linux-2.4.20/arch/ppc/boot/utils/hack-coff.c linux-2.4.20-ben6/arch/ppc/boot/utils/hack-coff.c --- linux-2.4.20/arch/ppc/boot/utils/hack-coff.c 2001-05-25 00:02:07.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/utils/hack-coff.c 2003-02-16 20:21:43.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.hack-coff.c 1.8 05/18/01 06:20:29 patch + * BK Id: SCCS/s.hack-coff.c 1.9 06/05/01 20:20:06 paulus */ /* * hack-coff.c - hack the header of an xcoff file to fill in diff -uNr linux-2.4.20/arch/ppc/boot/utils/mknote.c linux-2.4.20-ben6/arch/ppc/boot/utils/mknote.c --- linux-2.4.20/arch/ppc/boot/utils/mknote.c 2001-05-25 00:02:07.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/utils/mknote.c 2003-02-16 20:20:39.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mknote.c 1.7 05/18/01 15:17:23 cort + * BK Id: SCCS/s.mknote.c 1.8 06/05/01 20:20:06 paulus */ /* * Copyright (C) Cort Dougan 1999. diff -uNr linux-2.4.20/arch/ppc/boot/utils/mkprep.c linux-2.4.20-ben6/arch/ppc/boot/utils/mkprep.c --- linux-2.4.20/arch/ppc/boot/utils/mkprep.c 2001-05-25 00:02:07.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/boot/utils/mkprep.c 2003-02-16 20:20:03.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mkprep.c 1.7 05/18/01 06:20:29 patch + * BK Id: SCCS/s.mkprep.c 1.8 06/05/01 20:20:06 paulus */ /* * Makes a prep bootable image which can be dd'd onto diff -uNr linux-2.4.20/arch/ppc/config.in linux-2.4.20-ben6/arch/ppc/config.in --- linux-2.4.20/arch/ppc/config.in 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/config.in 2003-02-16 20:20:00.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: %F% %I% %G% %U% %#% +# BK Id: SCCS/s.config.in 1.54 05/21/02 16:43:05 benh # # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. @@ -52,6 +52,17 @@ define_bool CONFIG_PPC_STD_MMU n fi +bool 'CPU Frequency scaling' CONFIG_CPU_FREQ +if [ "$CONFIG_CPU_FREQ" = "y" ]; then + bool ' /proc/sys/cpu/ interface (2.4.)' CONFIG_CPU_FREQ_24_API + if [ "$CONFIG_CPU_FREQ_24_API" = "n" ]; then + define_bool CONFIG_CPU_FREQ_26_API y + fi + if [ "$CONFIG_ADB_PMU" = "y" ]; then + bool " Support for Apple PowerBooks" CONFIG_CPU_FREQ_PMAC + fi +fi + if [ "$CONFIG_8260" = "y" ]; then define_bool CONFIG_SERIAL_CONSOLE y bool 'Support for EST8260' CONFIG_EST8260 diff -uNr linux-2.4.20/arch/ppc/configs/pmac_defconfig linux-2.4.20-ben6/arch/ppc/configs/pmac_defconfig --- linux-2.4.20/arch/ppc/configs/pmac_defconfig 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/configs/pmac_defconfig 2003-02-16 20:20:00.000000000 +0100 @@ -1,5 +1,5 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set @@ -30,6 +30,10 @@ # CONFIG_8xx is not set # CONFIG_8260 is not set CONFIG_PPC_STD_MMU=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_24_API is not set +CONFIG_CPU_FREQ_26_API=y +CONFIG_CPU_FREQ_PMAC=y CONFIG_ALL_PPC=y # CONFIG_APUS is not set # CONFIG_SPRUCE is not set @@ -37,9 +41,7 @@ # CONFIG_GEMINI is not set # CONFIG_SMP is not set CONFIG_ALTIVEC=y -CONFIG_TAU=y -# CONFIG_TAU_INT is not set -# CONFIG_TAU_AVERAGE is not set +# CONFIG_TAU is not set CONFIG_PPC_ISATIMER=y # @@ -78,7 +80,7 @@ CONFIG_PPC_RTC=y CONFIG_PPC601_SYNC_FIX=y CONFIG_PROC_DEVICETREE=y -CONFIG_PPC_RTAS=y +# CONFIG_PPC_RTAS is not set CONFIG_BOOTX_TEXT=y # CONFIG_PREP_RESIDUAL is not set # CONFIG_PROC_PREPRESIDUAL is not set @@ -98,7 +100,7 @@ # # Block devices # -CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set @@ -152,7 +154,7 @@ CONFIG_IP_NF_CONNTRACK=m CONFIG_IP_NF_FTP=m CONFIG_IP_NF_IRC=m -# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_LIMIT=m CONFIG_IP_NF_MATCH_MAC=m @@ -182,8 +184,12 @@ CONFIG_IP_NF_NAT_SNMP_BASIC=m CONFIG_IP_NF_NAT_IRC=m CONFIG_IP_NF_NAT_FTP=m -# CONFIG_IP_NF_MANGLE is not set -# CONFIG_IP_NF_TARGET_LOG is not set +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_ARPTABLES=m @@ -193,12 +199,14 @@ # CONFIG_IP_NF_COMPAT_IPFWADM is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set -# CONFIG_ATM is not set +CONFIG_ATM=y +CONFIG_ATM_CLIP=y +CONFIG_ATM_CLIP_NO_ICMP=y +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set # CONFIG_VLAN_8021Q is not set - -# -# -# # CONFIG_IPX is not set CONFIG_ATALK=m @@ -236,10 +244,6 @@ # IDE, ATA and ATAPI Block devices # CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y @@ -258,12 +262,8 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set CONFIG_BLK_DEV_IDEFLOPPY=y -CONFIG_BLK_DEV_IDESCSI=y +CONFIG_BLK_DEV_IDESCSI=m # CONFIG_IDE_TASK_IOCTL is not set - -# -# IDE chipset support/bugfixes -# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set @@ -273,7 +273,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_IDEDMA_FORCED is not set -CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_PCI_AUTO is not set # CONFIG_IDEDMA_ONLYDISK is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_PCI_WIP is not set @@ -286,7 +286,7 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set -CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_CMD64X is not set # CONFIG_BLK_DEV_CMD680 is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set @@ -295,9 +295,9 @@ # CONFIG_BLK_DEV_HPT366 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_PDC202XX is not set -# CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_FORCE is not set +CONFIG_BLK_DEV_PDC202XX=y +CONFIG_PDC202XX_BURST=y +CONFIG_PDC202XX_FORCE=y # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_SLC90E66 is not set @@ -322,10 +322,6 @@ # SCSI support # CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y @@ -334,10 +330,6 @@ CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -353,15 +345,11 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AACRAID is not set -CONFIG_SCSI_AIC7XXX=m +CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_AIC7XXX_PROBE_EISA_VL is not set # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set -CONFIG_SCSI_AIC7XXX_OLD=m -# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set -CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 -CONFIG_AIC7XXX_OLD_PROC_STATS=y # CONFIG_SCSI_DPT_I2O is not set CONFIG_SCSI_ADVANSYS=m # CONFIG_SCSI_IN2000 is not set @@ -402,7 +390,7 @@ # CONFIG_SCSI_DEBUG is not set CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=5 -CONFIG_SCSI_MESH_RESET_DELAY_MS=500 +CONFIG_SCSI_MESH_RESET_DELAY_MS=4000 CONFIG_SCSI_MAC53C94=y # @@ -414,24 +402,12 @@ # IEEE 1394 (FireWire) support (EXPERIMENTAL) # CONFIG_IEEE1394=m - -# -# Device Drivers -# - -# -# Texas Instruments PCILynx requires I2C bit-banging -# CONFIG_IEEE1394_OHCI1394=m - -# -# Protocol Drivers -# CONFIG_IEEE1394_VIDEO1394=m CONFIG_IEEE1394_SBP2=m # CONFIG_IEEE1394_SBP2_PHYS_DMA is not set CONFIG_IEEE1394_ETH1394=m -# CONFIG_IEEE1394_DV1394 is not set +CONFIG_IEEE1394_DV1394=m CONFIG_IEEE1394_RAWIO=m # CONFIG_IEEE1394_CMP is not set # CONFIG_IEEE1394_VERBOSEDEBUG is not set @@ -448,7 +424,7 @@ # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set +CONFIG_TUN=m # CONFIG_ETHERTAP is not set # @@ -529,6 +505,7 @@ CONFIG_PPP_DEFLATE=y CONFIG_PPP_BSDCOMP=m # CONFIG_PPPOE is not set +# CONFIG_PPPOATM is not set # CONFIG_SLIP is not set # @@ -546,10 +523,6 @@ CONFIG_APPLE_AIRPORT=m # CONFIG_PLX_HERMES is not set CONFIG_PCI_HERMES=m - -# -# Wireless Pcmcia cards support -# CONFIG_PCMCIA_HERMES=m # CONFIG_AIRO_CS is not set CONFIG_NET_WIRELESS=y @@ -590,6 +563,21 @@ # CONFIG_AIRONET4500_CS is not set # +# ATM drivers +# +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_FORE200E_MAYBE is not set + +# # Amateur Radio support # # CONFIG_HAMRADIO is not set @@ -598,18 +586,10 @@ # IrDA (infrared) support # CONFIG_IRDA=m - -# -# IrDA protocols -# CONFIG_IRLAN=m CONFIG_IRNET=m CONFIG_IRCOMM=m -# CONFIG_IRDA_ULTRA is not set - -# -# IrDA options -# +CONFIG_IRDA_ULTRA=y CONFIG_IRDA_CACHE_LAST_LSAP=y CONFIG_IRDA_FAST_RR=y # CONFIG_IRDA_DEBUG is not set @@ -617,21 +597,9 @@ # # Infrared-port device drivers # - -# -# SIR device drivers -# CONFIG_IRTTY_SIR=m -# CONFIG_IRPORT_SIR is not set - -# -# Dongle support -# +CONFIG_IRPORT_SIR=m # CONFIG_DONGLE is not set - -# -# FIR device drivers -# # CONFIG_USB_IRDA is not set # CONFIG_NSC_FIR is not set # CONFIG_WINBOND_FIR is not set @@ -643,7 +611,65 @@ # # ISDN subsystem # -# CONFIG_ISDN is not set +CONFIG_ISDN=m +CONFIG_ISDN_BOOL=y +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_MPP=y +CONFIG_ISDN_PPP_BSDCOMP=m +# CONFIG_ISDN_AUDIO is not set + +# +# ISDN feature submodules +# +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DIVERSION is not set + +# +# Passive ISDN cards +# +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_HISAX=y +# CONFIG_HISAX_EURO is not set +# CONFIG_HISAX_1TR6 is not set +# CONFIG_HISAX_NI1 is not set +CONFIG_HISAX_MAX_CARDS=8 +# CONFIG_HISAX_TELESPCI is not set +# CONFIG_HISAX_S0BOX is not set +# CONFIG_HISAX_FRITZPCI is not set +# CONFIG_HISAX_AVM_A1_PCMCIA is not set +# CONFIG_HISAX_ELSA is not set +# CONFIG_HISAX_DIEHLDIVA is not set +# CONFIG_HISAX_SEDLBAUER is not set +# CONFIG_HISAX_NETJET is not set +# CONFIG_HISAX_NETJET_U is not set +# CONFIG_HISAX_NICCY is not set +# CONFIG_HISAX_BKM_A4T is not set +# CONFIG_HISAX_SCT_QUADRO is not set +CONFIG_HISAX_GAZEL=y +# CONFIG_HISAX_HFC_PCI is not set +# CONFIG_HISAX_W6692 is not set +# CONFIG_HISAX_HFC_SX is not set +# CONFIG_HISAX_ENTERNOW_PCI is not set +# CONFIG_HISAX_DEBUG is not set +# CONFIG_HISAX_SEDLBAUER_CS is not set +# CONFIG_HISAX_ELSA_CS is not set +# CONFIG_HISAX_AVM_A1_CS is not set +CONFIG_HISAX_ST5481=m +# CONFIG_HISAX_FRITZ_PCIPNP is not set + +# +# Active ISDN cards +# +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_EICON is not set +# CONFIG_ISDN_DRV_TPAM is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_HYSDN is not set +# CONFIG_HYSDN_CAPI is not set # # Old CD-ROM drivers (not SCSI, not IDE) @@ -660,7 +686,7 @@ # CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y -# CONFIG_FB_RIVA is not set +CONFIG_FB_RIVA=y # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_PM3 is not set @@ -733,7 +759,7 @@ CONFIG_ADB=y CONFIG_ADB_MACIO=y CONFIG_INPUT_ADBHID=y -CONFIG_MAC_ADBKEYCODES=y +# CONFIG_MAC_ADBKEYCODES is not set CONFIG_MAC_EMUMOUSEBTN=y CONFIG_MAC_HID=y # CONFIG_ANSLCD is not set @@ -784,10 +810,6 @@ # CONFIG_INPUT_EMU10K1 is not set # CONFIG_INPUT_SERIO is not set # CONFIG_INPUT_SERPORT is not set - -# -# Joysticks -# # CONFIG_INPUT_ANALOG is not set # CONFIG_INPUT_A3D is not set # CONFIG_INPUT_ADI is not set @@ -813,6 +835,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_AMD_PM768 is not set CONFIG_NVRAM=y # CONFIG_RTC is not set # CONFIG_DTLK is not set @@ -823,19 +846,54 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_AGP is not set +CONFIG_AGP=m +# CONFIG_AGP_INTEL is not set +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_AMD_8151 is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +# CONFIG_AGP_SWORKS is not set +CONFIG_AGP_UNINORTH=y # CONFIG_DRM is not set # # PCMCIA character devices # -# CONFIG_PCMCIA_SERIAL_CS is not set +CONFIG_PCMCIA_SERIAL_CS=m # CONFIG_SYNCLINK_CS is not set # # Multimedia devices # -# CONFIG_VIDEO_DEV is not set +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# +# CONFIG_VIDEO_PROC_FS is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_VIDEO_PMS is not set +CONFIG_VIDEO_PLANB=m +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set # # File systems @@ -878,7 +936,7 @@ # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y @@ -1017,81 +1075,53 @@ # CONFIG_USB=y # CONFIG_USB_DEBUG is not set - -# -# Miscellaneous USB options -# CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_LONG_TIMEOUT is not set - -# -# USB Host Controller Drivers -# # CONFIG_USB_EHCI_HCD is not set # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set +CONFIG_USB_AUDIO=m # CONFIG_USB_EMI26 is not set # CONFIG_USB_BLUETOOTH is not set # CONFIG_USB_MIDI is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_DEBUG=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y # CONFIG_USB_STORAGE_SDDR55 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_STORAGE_JUMPSHOT=y CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m - -# -# USB Human Interface Devices (HID) -# CONFIG_USB_HID=y CONFIG_USB_HIDINPUT=y -# CONFIG_USB_HIDDEV is not set +CONFIG_USB_HIDDEV=y # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set - -# -# USB Imaging devices -# # CONFIG_USB_DC2XX is not set # CONFIG_USB_MDC800 is not set CONFIG_USB_SCANNER=m # CONFIG_USB_MICROTEK is not set # CONFIG_USB_HPUSBSCSI is not set - -# -# USB Multimedia devices -# - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network adaptors -# +# CONFIG_USB_IBMCAM is not set +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +# CONFIG_USB_SE401 is not set +# CONFIG_USB_STV680 is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set -# CONFIG_USB_CDCETHER is not set +CONFIG_USB_CDCETHER=m # CONFIG_USB_USBNET is not set - -# -# USB port drivers -# # CONFIG_USB_USS720 is not set # @@ -1110,18 +1140,24 @@ # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_EDGEPORT_TI is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y # CONFIG_USB_SERIAL_MCT_U232 is not set # CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set - -# -# USB Miscellaneous drivers -# # CONFIG_USB_RIO500 is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_TIGL is not set diff -uNr linux-2.4.20/arch/ppc/kernel/Makefile linux-2.4.20-ben6/arch/ppc/kernel/Makefile --- linux-2.4.20/arch/ppc/kernel/Makefile 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/Makefile 2003-02-16 20:21:38.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: %F% %I% %G% %U% %#% +# BK Id: SCCS/s.Makefile 1.49 10/29/02 20:27:52 benh # # # Makefile for the linux kernel. diff -uNr linux-2.4.20/arch/ppc/kernel/align.c linux-2.4.20-ben6/arch/ppc/kernel/align.c --- linux-2.4.20/arch/ppc/kernel/align.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/align.c 2003-02-16 20:20:00.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.align.c 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.align.c 1.7 06/05/01 21:22:02 paulus */ /* * align.c - handle alignment exceptions for the Power PC. diff -uNr linux-2.4.20/arch/ppc/kernel/bitops.c linux-2.4.20-ben6/arch/ppc/kernel/bitops.c --- linux-2.4.20/arch/ppc/kernel/bitops.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/bitops.c 2003-02-16 20:20:09.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.bitops.c 1.7 05/17/01 18:14:21 cort + * BK Id: SCCS/s.bitops.c 1.9 06/05/01 21:22:02 paulus */ /* * Copyright (C) 1996 Paul Mackerras. diff -uNr linux-2.4.20/arch/ppc/kernel/btext.c linux-2.4.20-ben6/arch/ppc/kernel/btext.c --- linux-2.4.20/arch/ppc/kernel/btext.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/btext.c 2003-02-16 20:21:31.000000000 +0100 @@ -45,22 +45,14 @@ static unsigned char vga_font[cmapsz]; int boot_text_mapped; +int force_printk_to_btext; boot_infos_t disp_bi; extern char *klimit; -/* - * Powermac can use btext_* after boot for xmon, - * chrp only uses it during early boot. - */ -#ifdef CONFIG_XMON -#define BTEXT __pmac -#define BTDATA __pmacdata -#else -#define BTEXT __init -#define BTDATA __initdata -#endif /* CONFIG_XMON */ +#define BTEXT +#define BTDATA /* * This is called only when we are booted via BootX. diff -uNr linux-2.4.20/arch/ppc/kernel/checks.c linux-2.4.20-ben6/arch/ppc/kernel/checks.c --- linux-2.4.20/arch/ppc/kernel/checks.c 2001-05-22 02:04:46.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/checks.c 2003-02-16 20:20:41.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.checks.c 1.6 05/17/01 18:14:21 cort + * BK Id: SCCS/s.checks.c 1.8 06/05/01 21:22:02 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/kernel/cputable.c linux-2.4.20-ben6/arch/ppc/kernel/cputable.c --- linux-2.4.20/arch/ppc/kernel/cputable.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/cputable.c 2003-02-16 20:20:12.000000000 +0100 @@ -144,7 +144,16 @@ 32, 32, __setup_cpu_750cx }, - { /* 750FX (All revs for now) */ + { /* 750FX rev 2.0 must disable HID0[DPM] */ + 0xffffffff, 0x70000200, "750FX", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | + CPU_FTR_NO_DPM, + COMMON_PPC, + 32, 32, + __setup_cpu_750 + }, + { /* 750FX (All revs except 2.0) */ 0xffff0000, 0x70000000, "750FX", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP | diff -uNr linux-2.4.20/arch/ppc/kernel/entry.S linux-2.4.20-ben6/arch/ppc/kernel/entry.S --- linux-2.4.20/arch/ppc/kernel/entry.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/entry.S 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.entry.S 1.26 01/25/02 15:15:24 benh + * BK Id: SCCS/s.entry.S 1.29 01/20/03 22:26:36 benh */ /* * PowerPC version @@ -166,7 +166,6 @@ .globl ret_from_syscall_2 ret_from_syscall_2: stw r3,RESULT(r1) /* Save result */ - stw r3,GPR0(r1) /* temporary gross hack to make strace work */ li r10,-_LAST_ERRNO cmpl 0,r3,r10 blt 60f diff -uNr linux-2.4.20/arch/ppc/kernel/find_name.c linux-2.4.20-ben6/arch/ppc/kernel/find_name.c --- linux-2.4.20/arch/ppc/kernel/find_name.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/find_name.c 2003-02-16 20:20:37.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.find_name.c 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.find_name.c 1.7 06/05/01 21:22:02 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/kernel/galaxy_pci.c linux-2.4.20-ben6/arch/ppc/kernel/galaxy_pci.c --- linux-2.4.20/arch/ppc/kernel/galaxy_pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/galaxy_pci.c 2003-02-16 20:21:48.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.galaxy_pci.c 1.10 08/13/02 20:27:37 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/kernel/head.S linux-2.4.20-ben6/arch/ppc/kernel/head.S --- linux-2.4.20/arch/ppc/kernel/head.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/head.S 2003-02-16 20:20:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.head.S 1.58 01/25/03 21:28:49 benh */ /* * PowerPC version @@ -40,6 +40,8 @@ #include #endif +#undef DEBUG_RESET + #ifdef CONFIG_PPC64BRIDGE #define LOAD_BAT(n, reg, RA, RB) \ ld RA,(n*32)+0(reg); \ @@ -310,15 +312,31 @@ .long ret_from_except /* System reset */ -#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ -#ifdef CONFIG_GEMINI +/* MVME/MTX and gemini start the secondary here + * Changed so that location is dynamically changed to a + * branch for CPU startup, then restored, so we still have + * the exception vector around for debugging + */ +#if defined(CONFIG_SMP) && defined(CONFIG_GEMINI) . = 0x100 b __secondary_start_gemini -#else /* CONFIG_GEMINI */ - STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) -#endif /* CONFIG_GEMINI */ +#else +#ifdef DEBUG_RESET + . = 0x100 + li r3,0 + mfspr r0,SRR0 + stw r0,0(r3) + mfspr r0,SRR1 + stw r0,4(r3) + mflr r0 + stw r0,8(r3) + stw r1,12(r3) + stw r2,16(r3) +1: nop + b 1b #else STD_EXCEPTION(0x100, Reset, UnknownException) +#endif #endif /* Machine check */ @@ -1268,7 +1286,8 @@ MTMSRD(r0) isync #endif - + mr r3,r24 + bl smp_call_init_cpu lis r3,-KERNELBASE@h mr r4,r24 bl identify_cpu @@ -1348,12 +1367,14 @@ blr _GLOBAL(__setup_cpu_7400) mflr r4 + bl setup_7400_workarounds bl setup_common_caches bl setup_750_7400_hid0 mtlr r4 blr _GLOBAL(__setup_cpu_7410) mflr r4 + bl setup_7410_workarounds bl setup_common_caches bl setup_750_7400_hid0 li r3,0 @@ -1414,6 +1435,47 @@ isync blr +/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some + * erratas we work around here. + * Moto MPC710CE.pdf describes them, those are errata + * #3, #4 and #5 + * Note that we assume the firmware didn't choose to + * apply other workarounds (there are other ones documented + * in the .pdf). It appear that Apple firmware only works + * around #3 and with the same fix we use. We may want to + * check if the CPU is using 60x bus mode in which case + * the workaround for errata #4 is useless. Also, we may + * want to explicitely clear HID0_NOPDST as this is not + * needed once we have applied workaround #5 (though it's + * not set by Apple's firmware at least). + */ +setup_7400_workarounds: + mfpvr r3 + rlwinm r3,r3,0,20,31 + cmpwi 0,r3,0x0207 + ble 1f + blr +setup_7410_workarounds: + mfpvr r3 + rlwinm r3,r3,0,20,31 + cmpwi 0,r3,0x0100 + bnelr +1: + mfspr r11,SPRN_MSSSR0 + /* Errata #3: Set L1OPQ_SIZE to 0x10 */ + rlwinm r11,r11,0,9,6 + oris r11,r11,0x0100 + /* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */ + oris r11,r11,0x0002 + /* Errata #5: Set DRLT_SIZE to 0x01 */ + rlwinm r11,r11,0,5,2 + oris r11,r11,0x0800 + sync + mtspr SPRN_MSSSR0,r11 + sync + isync + blr + /* 740/750/7400/7410 * Enable Store Gathering (SGE), Address Brodcast (ABE), * Branch History Table (BHTE), Branch Target ICache (BTIC) @@ -1423,7 +1485,9 @@ setup_750_7400_hid0: mfspr r11,HID0 ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC +BEGIN_FTR_SECTION oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ +END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) li r3,HID0_SPD andc r11,r11,r3 /* clear SPD: enable speculative */ li r3,0 @@ -1439,6 +1503,18 @@ * (waiting for confirmation) */ setup_750cx: + mfspr r10, SPRN_HID1 + rlwinm r10,r10,4,28,31 + cmpi cr0,r10,7 + cmpi cr1,r10,9 + cmpi cr2,r10,11 + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + cror 4*cr0+eq,4*cr0+eq,4*cr2+eq + bnelr + lwz r6,CPU_SPEC_FEATURES(r5) + li r7,CPU_FTR_CAN_NAP + andc r6,r6,r7 + stw r6,CPU_SPEC_FEATURES(r5) blr /* 750fx specific @@ -1476,7 +1552,9 @@ /* All of the bits we have to set..... */ ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK +BEGIN_FTR_SECTION oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ +END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) /* All of the bits we have to clear.... */ diff -uNr linux-2.4.20/arch/ppc/kernel/head_4xx.S linux-2.4.20-ben6/arch/ppc/kernel/head_4xx.S --- linux-2.4.20/arch/ppc/kernel/head_4xx.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/head_4xx.S 2003-02-16 20:21:16.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head_4xx.S 1.6 05/21/01 11:50:00 paulus + * BK Id: SCCS/s.head_4xx.S 1.9 08/13/02 20:27:37 paulus */ /* * Copyright (c) 1995-1996 Gary Thomas diff -uNr linux-2.4.20/arch/ppc/kernel/head_8xx.S linux-2.4.20-ben6/arch/ppc/kernel/head_8xx.S --- linux-2.4.20/arch/ppc/kernel/head_8xx.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/head_8xx.S 2003-02-16 20:19:50.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.head_8xx.S 1.31 09/11/02 14:41:30 paulus */ /* * arch/ppc/kernel/except_8xx.S diff -uNr linux-2.4.20/arch/ppc/kernel/i8259.c linux-2.4.20-ben6/arch/ppc/kernel/i8259.c --- linux-2.4.20/arch/ppc/kernel/i8259.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/i8259.c 2003-02-16 20:21:30.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.i8259.c 1.18 10/12/02 14:14:20 paulus */ #include @@ -21,17 +21,37 @@ int i8259_pic_irq_offset; -/* Acknowledge the irq using the PCI host bridge's interrupt acknowledge - * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.) +/* + * Acknowledge the IRQ using either the PCI host bridge's interrupt + * acknowledge feature or poll. How i8259_init() is called determines + * which is called. It should be noted that polling is broken on some + * IBM and Motorola PReP boxes so we must use the int-ack feature on them. */ -int i8259_irq(struct pt_regs *regs) +int +i8259_irq(struct pt_regs *regs) { int irq; - spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); + spin_lock(&i8259_lock); - irq = *pci_intack; - if (irq==7) { + /* Either int-ack or poll for the IRQ */ + if (pci_intack) + irq = *pci_intack; + else { + /* Perform an interrupt acknowledge cycle on controller 1. */ + outb(0x0C, 0x20); /* prepare for poll */ + irq = inb(0x20) & 7; + if (irq == 2 ) { + /* + * Interrupt is cascaded so perform interrupt + * acknowledge on controller 2. + */ + outb(0x0C, 0xA0); /* prepare for poll */ + irq = (inb(0xA0) & 7) + 8; + } + } + + if (irq == 7) { /* * This may be a spurious interrupt. * @@ -39,47 +59,13 @@ * significant bit is not set then there is no valid * interrupt. */ - if(~inb(0x20)&0x80) { + if (!pci_intack) + outb(0x0B, 0x20); /* ISR register */ + if(~inb(0x20) & 0x80) irq = -1; - } } - spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); - return irq; -} - -/* Poke the 8259's directly using poll commands. */ -int i8259_poll(struct pt_regs *regs) -{ - int irq; - spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); - /* - * Perform an interrupt acknowledge cycle on controller 1 - */ - outb(0x0C, 0x20); /* prepare for poll */ - irq = inb(0x20) & 7; - if (irq == 2) { - /* - * Interrupt is cascaded so perform interrupt - * acknowledge on controller 2 - */ - outb(0x0C, 0xA0); /* prepare for poll */ - irq = (inb(0xA0) & 7) + 8; - } else if (irq==7) { - /* - * This may be a spurious interrupt - * - * Read the interrupt status register. If the most - * significant bit is not set then there is no valid - * interrupt - */ - outb(0x0b, 0x20); - if(~inb(0x20)&0x80) { - spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); - return -1; - } - } - spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); + spin_unlock(&i8259_lock); return irq; } diff -uNr linux-2.4.20/arch/ppc/kernel/idle.c linux-2.4.20-ben6/arch/ppc/kernel/idle.c --- linux-2.4.20/arch/ppc/kernel/idle.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/idle.c 2003-02-16 20:20:14.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.idle.c 1.26 10/29/02 20:27:52 benh */ /* * Idle daemon for PowerPC. Idle daemon will handle any action diff -uNr linux-2.4.20/arch/ppc/kernel/idle_6xx.S linux-2.4.20-ben6/arch/ppc/kernel/idle_6xx.S --- linux-2.4.20/arch/ppc/kernel/idle_6xx.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/idle_6xx.S 2003-02-16 20:21:04.000000000 +0100 @@ -107,13 +107,23 @@ andis. r0,r3,HID0_NAP@h beq 2f BEGIN_FTR_SECTION - /* Disable L2 prefetch on some 745x */ + /* Disable L2 prefetch on some 745x and try to ensure + * L2 prefetch engines are idle. As explained by errata + * text, we can't be sure they are, we just hope very hard + * that well be enough (sic !). At least I noticed Apple + * doesn't even bother doing the dcbf's here... + */ mfspr r4,SPRN_MSSCR0 rlwinm r4,r4,0,0,29 sync mtspr SPRN_MSSCR0,r4 sync isync + lis r4,KERNELBASE@h + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 + dcbf 0,r4 END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR) #ifdef DEBUG lis r6,nap_enter_count@ha @@ -142,7 +152,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) andc r4,r4,r5 or r4,r4,r3 - oris r4,r4,HID0_DPM@h /* that should be done once for all ... */ +BEGIN_FTR_SECTION + oris r4,r4,HID0_DPM@h /* that should be done once for all */ +END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) mtspr SPRN_HID0,r4 BEGIN_FTR_SECTION DSSALL diff -uNr linux-2.4.20/arch/ppc/kernel/indirect_pci.c linux-2.4.20-ben6/arch/ppc/kernel/indirect_pci.c --- linux-2.4.20/arch/ppc/kernel/indirect_pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/indirect_pci.c 2003-02-16 20:19:53.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.indirect_pci.c 1.12 08/13/02 20:27:37 paulus */ /* * Support for indirect PCI bridges. diff -uNr linux-2.4.20/arch/ppc/kernel/irq.c linux-2.4.20-ben6/arch/ppc/kernel/irq.c --- linux-2.4.20/arch/ppc/kernel/irq.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/irq.c 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.irq.c 1.39 06/04/02 16:06:19 benh */ /* * arch/ppc/kernel/irq.c @@ -78,6 +78,10 @@ unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; atomic_t ppc_n_lost_interrupts; +#ifdef CONFIG_DEBUG_SPINLOCK +int debug_long_irqlock; +#endif /* CONFIG_DEBUG_SPINLOCK */ + /* nasty hack for shared irq's since we need to do kmalloc calls but * can't very early in the boot when we need to do a request irq. * this needs to be removed. @@ -528,27 +532,21 @@ int irq, first = 1; hardirq_enter( cpu ); - for (;;) { - /* - * Every arch is required to implement ppc_md.get_irq. - * This function will either return an irq number or -1 to - * indicate there are no more pending. But the first time - * through the loop this means there wasn't and IRQ pending. - * The value -2 is for buggy hardware and means that this IRQ - * has already been handled. -- Tom - */ - irq = ppc_md.get_irq( regs ); - - if (irq >= 0) - ppc_irq_dispatch_handler( regs, irq ); - else { - if (irq != -2 && first) - /* That's not SMP safe ... but who cares ? */ - ppc_spurious_interrupts++; - break; - } + /* + * Every platform is required to implement ppc_md.get_irq. + * This function will either return an irq number or -1 to + * indicate there are no more pending. But the first time + * through the loop this means there wasn't an IRQ pending. + * The value -2 is for buggy hardware and means that this IRQ + * has already been handled. -- Tom + */ + while ((irq = ppc_md.get_irq(regs)) >= 0) { + ppc_irq_dispatch_handler(regs, irq); first = 0; } + if (irq != -2 && first) + /* That's not SMP safe ... but who cares ? */ + ppc_spurious_interrupts++; hardirq_exit( cpu ); if (softirq_pending(cpu)) @@ -596,6 +594,24 @@ unsigned long *stack; int cpu = smp_processor_id(); +#ifdef CONFIG_XMON + xmon_printf("\n%s, CPU %d:\n", str, cpu); + xmon_printf("irq: %d [%d %d]\n", + atomic_read(&global_irq_count), + local_irq_count(0), + local_irq_count(1)); + xmon_printf("bh: %d [%d %d]\n", + atomic_read(&global_bh_count), + local_bh_count(0), + local_bh_count(1)); + stack = (unsigned long *) &str; + for (i = 40; i ; i--) { + unsigned long x = *++stack; + if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) { + xmon_printf("<[%08lx]> ", x); + } + } +#endif /* CONFIG_XMON */ printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [%d %d]\n", atomic_read(&global_irq_count), @@ -712,6 +728,9 @@ do { do { if (loops-- == 0) { +#ifdef CONFIG_XMON + xmon_printf("get_irqlock(%d) waiting, global_irq_holder=%d\n", cpu, global_irq_holder); +#endif printk("get_irqlock(%d) waiting, global_irq_holder=%d\n", cpu, global_irq_holder); #ifdef CONFIG_XMON xmon(0); diff -uNr linux-2.4.20/arch/ppc/kernel/m8260_setup.c linux-2.4.20-ben6/arch/ppc/kernel/m8260_setup.c --- linux-2.4.20/arch/ppc/kernel/m8260_setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/m8260_setup.c 2003-02-16 20:21:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.m8260_setup.c 1.33 09/26/02 22:13:19 paulus */ /* * linux/arch/ppc/kernel/setup.c diff -uNr linux-2.4.20/arch/ppc/kernel/m8xx_setup.c linux-2.4.20-ben6/arch/ppc/kernel/m8xx_setup.c --- linux-2.4.20/arch/ppc/kernel/m8xx_setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/m8xx_setup.c 2003-02-16 20:21:18.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.m8xx_setup.c 1.45 10/12/02 14:14:20 paulus * * linux/arch/ppc/kernel/setup.c * @@ -45,6 +45,7 @@ #include #include #include +#include #include "ppc8xx_pic.h" @@ -63,9 +64,9 @@ m8xx_setup_arch(void) { int cpm_page; - + cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE); - + /* Reset the Communication Processor Module. */ m8xx_cpm_reset(cpm_page); @@ -73,10 +74,10 @@ #ifdef notdef ROOT_DEV = to_kdev_t(0x0301); /* hda1 */ #endif - + #ifdef CONFIG_BLK_DEV_INITRD #if 0 - ROOT_DEV = to_kdev_t(0x0200); /* floppy */ + ROOT_DEV = to_kdev_t(0x0200); /* floppy */ rd_prompt = 1; rd_doload = 1; rd_image_start = 0; @@ -218,7 +219,7 @@ __asm__("mtmsr %0" : : "r" (msr) ); dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0]; - printk("Restart failed\n"); + printk("Restart failed\n"); while(1); } @@ -241,7 +242,7 @@ bd_t *bp; bp = (bd_t *)__res; - + seq_printf(m, "clock\t\t: %ldMHz\n" "bus clock\t: %ldMHz\n", bp->bi_intfreq / 1000000, @@ -264,7 +265,7 @@ for ( i = 0 ; i < NR_SIU_INTS ; i++ ) irq_desc[i].handler = &ppc8xx_pic; - + /* We could probably incorporate the CPM into the multilevel * interrupt structure. */ @@ -275,7 +276,7 @@ for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ ) irq_desc[i].handler = &i8259_pic; i8259_pic.irq_offset = NR_SIU_INTS; - i8259_init(); + i8259_init(0); request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL); enable_irq(ISA_BRIDGE_INT); #endif @@ -297,7 +298,7 @@ { bd_t *binfo; extern unsigned char __res[]; - + binfo = (bd_t *)__res; return binfo->bi_memsize; @@ -348,7 +349,7 @@ if ( r3 ) memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); - + #ifdef CONFIG_PCI m8xx_setup_pci_ptrs(); #endif @@ -363,7 +364,7 @@ #endif /* CONFIG_BLK_DEV_INITRD */ /* take care of cmd line */ if ( r6 ) - { + { *(char *)(r7+KERNELBASE) = 0; strcpy(cmd_line, (char *)(r6+KERNELBASE)); } @@ -397,5 +398,5 @@ #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) m8xx_ide_init(); -#endif +#endif } diff -uNr linux-2.4.20/arch/ppc/kernel/misc.S linux-2.4.20-ben6/arch/ppc/kernel/misc.S --- linux-2.4.20/arch/ppc/kernel/misc.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/misc.S 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.misc.S 1.50 10/20/02 20:14:44 benh */ /* * This file contains miscellaneous low-level functions. diff -uNr linux-2.4.20/arch/ppc/kernel/mk_defs.c linux-2.4.20-ben6/arch/ppc/kernel/mk_defs.c --- linux-2.4.20/arch/ppc/kernel/mk_defs.c 2001-08-28 15:58:33.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/mk_defs.c 2003-02-16 20:19:53.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mk_defs.c 1.11 08/19/01 22:43:23 paulus + * BK Id: SCCS/s.mk_defs.c 1.12 08/29/01 08:49:24 paulus */ /* * This program is used to generate definitions needed by diff -uNr linux-2.4.20/arch/ppc/kernel/open_pic.c linux-2.4.20-ben6/arch/ppc/kernel/open_pic.c --- linux-2.4.20/arch/ppc/kernel/open_pic.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/open_pic.c 2003-02-16 20:21:42.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.open_pic.c 1.40 10/12/02 14:14:20 paulus */ /* * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling @@ -38,7 +38,6 @@ static u_int NumSources; static int open_pic_irq_offset; static volatile OpenPIC_Source *ISR[NR_IRQS]; -static volatile unsigned char* chrp_int_ack_special; /* Global Operations */ static void openpic_disable_8259_pass_through(void); @@ -309,7 +308,6 @@ return; open_pic_irq_offset = offset; - chrp_int_ack_special = (volatile unsigned char*)chrp_ack; /* Initialize timer interrupts */ if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba); @@ -776,14 +774,8 @@ /* Yep - because openpic !=> i8259, for one thing. -VAL */ if (open_pic_irq_offset && irq == open_pic_irq_offset) { - /* - * This magic address generates a PCI IACK cycle. - */ - if ( chrp_int_ack_special ) - irq = *chrp_int_ack_special; #ifndef CONFIG_GEMINI - else - irq = i8259_poll(regs); + irq = i8259_irq(regs); #endif openpic_eoi(); } diff -uNr linux-2.4.20/arch/ppc/kernel/pci-dma.c linux-2.4.20-ben6/arch/ppc/kernel/pci-dma.c --- linux-2.4.20/arch/ppc/kernel/pci-dma.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/pci-dma.c 2003-02-16 20:20:20.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pci-dma.c 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.pci-dma.c 1.7 06/05/01 21:22:03 paulus */ /* * Copyright (C) 2000 Ani Joshi diff -uNr linux-2.4.20/arch/ppc/kernel/pci.c linux-2.4.20-ben6/arch/ppc/kernel/pci.c --- linux-2.4.20/arch/ppc/kernel/pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/pci.c 2003-02-16 20:21:47.000000000 +0100 @@ -1,8 +1,8 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.pci.c 1.60 01/20/03 21:55:26 benh */ /* - * Common pmac/prep/chrp pci routines. -- Cort + * Common PCI code for PPC architecture */ #include @@ -25,7 +25,7 @@ #include #include -#undef DEBUG +#define DEBUG #ifdef DEBUG #define DBG(x...) printk(x) @@ -113,7 +113,11 @@ int reg; struct pci_controller* hose = dev->sysdata; unsigned long io_offset; - + + if (dev->vendor == PCI_VENDOR_ID_APPLE && dev->device == PCI_DEVICE_ID_APPLE_KEYLARGO) { + printk("trying to reloc keylargo !! skipping\n"); + return; + } new = res->start; if (hose && res->flags & IORESOURCE_IO) { io_offset = (unsigned long)hose->io_base_virt - isa_io_base; @@ -335,8 +339,9 @@ { struct resource *pr, *r = &dev->resource[idx]; - DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n", - dev->slot_name, idx, r->start, r->end, r->flags); + DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx), vd: %04x, dev: %04x\n", + dev->slot_name, idx, r->start, r->end, r->flags, + dev->vendor, dev->device); pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) { printk(KERN_ERR "PCI: Cannot allocate resource region %d" @@ -795,6 +800,10 @@ } ranges += np; } + DBG("hose %s, pci_mem_offset: %08lx, start0: %08lx\n", + dev->name, hose->pci_mem_offset, hose->mem_resources[0].start); + DBG(" io_base_virt: %p, io_base_phys: %08lx, isa_mem_base: %08lx\n", + hose->io_base_virt, hose->io_base_phys, isa_mem_base); } /* We create the "pci-OF-bus-map" property now so it appears in the @@ -894,7 +903,8 @@ struct pci_dev *dev = pci_dev_b(ln); u16 class = dev->class >> 8; - if (class == PCI_CLASS_DISPLAY_VGA || class == PCI_CLASS_NOT_DEFINED_VGA) + if (class == PCI_CLASS_DISPLAY_VGA || + class == PCI_CLASS_NOT_DEFINED_VGA) *found_vga = 1; if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate) rc |= check_for_io_childs(dev->subordinate, res, found_vga); @@ -905,7 +915,8 @@ struct resource *r; unsigned long r_size; - if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI && i >= PCI_BRIDGE_RESOURCES) + if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI + && i >= PCI_BRIDGE_RESOURCES) continue; r = &dev->resource[i]; r_size = r->end - r->start; @@ -931,30 +942,45 @@ do_fixup_p2p_level(struct pci_bus *bus) { struct list_head *ln; - int i; + int i, parent_io; int has_vga = 0; + + for (parent_io=0; parent_io<4; parent_io++) + if (bus->resource[parent_io]->flags & IORESOURCE_IO) + break; + if (parent_io >= 4) + return; for (ln=bus->children.next; ln != &bus->children; ln=ln->next) { struct pci_bus *b = pci_bus_b(ln); struct pci_dev *d = b->self; struct pci_controller* hose = (struct pci_controller *)d->sysdata; struct resource *res = b->resource[0]; + struct resource tmp_res; unsigned long max; int found_vga = 0; - res->end = 0; - res->start = 0x1000; + memset(&tmp_res, 0, sizeof(tmp_res)); + tmp_res.start = bus->resource[parent_io]->start; + + /* We don't let low addresses go through that closed P2P bridge, well, + * that may not be necessary but I feel safer that way + */ + if (tmp_res.start == 0) + tmp_res.start = 0x1000; - if (!list_empty(&b->devices) && res && res->flags == 0 && res != bus->resource[0] && + if (!list_empty(&b->devices) && res && res->flags == 0 && + res != bus->resource[parent_io] && (d->class >> 8) == PCI_CLASS_BRIDGE_PCI && - check_for_io_childs(b, res, &found_vga)) { + check_for_io_childs(b, &tmp_res, &found_vga)) { u8 io_base_lo; printk(KERN_INFO "Fixing up IO bus %s\n", b->name); if (found_vga) { if (has_vga) { - printk(KERN_WARNING "Skipping VGA, already active on bus segment\n"); + printk(KERN_WARNING "Skipping VGA, already active" + " on bus segment\n"); found_vga = 0; } else has_vga = 1; @@ -962,10 +988,13 @@ pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo); if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) - max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffffffff; + max = ((unsigned long) hose->io_base_virt + - isa_io_base) + 0xffffffff; else - max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffff; - + max = ((unsigned long) hose->io_base_virt + - isa_io_base) + 0xffff; + + *res = tmp_res; res->flags = IORESOURCE_IO; res->name = b->name; @@ -976,10 +1005,12 @@ continue; if ((r->flags & IORESOURCE_IO) == 0) continue; - DBG("Trying to allocate from %08lx, size %08lx from parent res %d: %08lx -> %08lx\n", + DBG("Trying to allocate from %08lx, size %08lx from parent" + " res %d: %08lx -> %08lx\n", res->start, res->end, i, r->start, r->end); - if (allocate_resource(r, res, res->end + 1, res->start, max, res->end + 1, NULL, NULL) < 0) { + if (allocate_resource(r, res, res->end + 1, res->start, max, + res->end + 1, NULL, NULL) < 0) { DBG("Failed !\n"); continue; } @@ -1085,6 +1116,9 @@ return PCI_SLOT(dev->devfn); } +/* Where does that come from ? Doesn't seem to be correct for us, but we + * don't use it anyway so ... -BenH. + */ void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) { diff -uNr linux-2.4.20/arch/ppc/kernel/pci.h linux-2.4.20-ben6/arch/ppc/kernel/pci.h --- linux-2.4.20/arch/ppc/kernel/pci.h 2001-08-12 21:43:26.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/pci.h 2003-02-16 20:21:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pci.h 1.10 08/08/01 16:35:43 paulus + * BK Id: SCCS/s.pci.h 1.11 08/13/01 10:44:12 paulus */ #ifndef __PPC_KERNEL_PCI_H__ diff -uNr linux-2.4.20/arch/ppc/kernel/ppc-stub.c linux-2.4.20-ben6/arch/ppc/kernel/ppc-stub.c --- linux-2.4.20/arch/ppc/kernel/ppc-stub.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/ppc-stub.c 2003-02-16 20:21:04.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc-stub.c 1.6 05/17/01 18:14:21 cort + * BK Id: SCCS/s.ppc-stub.c 1.8 06/05/01 21:22:03 paulus */ /* * ppc-stub.c: KGDB support for the Linux kernel. diff -uNr linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c linux-2.4.20-ben6/arch/ppc/kernel/ppc4xx_pic.c --- linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/ppc4xx_pic.c 2003-02-16 20:20:39.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc4xx_pic.c 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.ppc4xx_pic.c 1.8 08/13/02 20:27:37 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/kernel/ppc8260_pic.c linux-2.4.20-ben6/arch/ppc/kernel/ppc8260_pic.c --- linux-2.4.20/arch/ppc/kernel/ppc8260_pic.c 2002-02-25 20:37:55.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/ppc8260_pic.c 2003-02-16 20:21:05.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc8260_pic.c 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.ppc8260_pic.c 1.9 02/14/02 12:33:42 trini */ #include diff -uNr linux-2.4.20/arch/ppc/kernel/ppc8260_pic.h linux-2.4.20-ben6/arch/ppc/kernel/ppc8260_pic.h --- linux-2.4.20/arch/ppc/kernel/ppc8260_pic.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/ppc8260_pic.h 2003-02-16 20:21:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.ppc8260_pic.h 1.10 08/13/02 20:27:37 paulus */ #ifndef _PPC_KERNEL_PPC8260_H diff -uNr linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.c linux-2.4.20-ben6/arch/ppc/kernel/ppc8xx_pic.c --- linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.c 2002-02-25 20:37:55.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/ppc8xx_pic.c 2003-02-16 20:20:08.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc8xx_pic.c 1.13 12/01/01 17:19:48 trini + * BK Id: SCCS/s.ppc8xx_pic.c 1.14 12/27/01 10:08:50 trini */ #include #include diff -uNr linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.h linux-2.4.20-ben6/arch/ppc/kernel/ppc8xx_pic.h --- linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/ppc8xx_pic.h 2003-02-16 20:20:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.ppc8xx_pic.h 1.10 08/13/02 20:27:38 paulus */ #ifndef _PPC_KERNEL_PPC8xx_H #define _PPC_KERNEL_PPC8xx_H diff -uNr linux-2.4.20/arch/ppc/kernel/ppc_htab.c linux-2.4.20-ben6/arch/ppc/kernel/ppc_htab.c --- linux-2.4.20/arch/ppc/kernel/ppc_htab.c 2001-11-03 02:43:54.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/ppc_htab.c 2003-02-16 20:21:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc_htab.c 1.19 10/16/01 15:58:42 trini + * BK Id: SCCS/s.ppc_htab.c 1.20 11/04/01 22:58:20 paulus */ /* * PowerPC hash table management proc entry. Will show information diff -uNr linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c linux-2.4.20-ben6/arch/ppc/kernel/ppc_ksyms.c --- linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/ppc_ksyms.c 2003-02-16 20:20:33.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.ppc_ksyms.c 1.74 11/23/02 10:51:37 benh */ #include #include @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -317,7 +318,7 @@ EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); #ifdef CONFIG_XMON -extern void xmon_printf(char *fmt, ...); +extern void xmon_printf(const char *fmt, ...); EXPORT_SYMBOL(xmon); EXPORT_SYMBOL(xmon_printf); #endif @@ -348,6 +349,10 @@ EXPORT_SYMBOL(cpm_free_handler); #endif /* CONFIG_8xx */ +/* Those should really be inline */ +EXPORT_SYMBOL(atomic_clear_mask); +EXPORT_SYMBOL(atomic_set_mask); + EXPORT_SYMBOL(ret_to_user_hook); EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); @@ -362,6 +367,10 @@ EXPORT_SYMBOL(ret_from_intercept); EXPORT_SYMBOL(cur_cpu_spec); #if defined(CONFIG_ALL_PPC) +extern int map_page(unsigned long va, unsigned long pa, int flags); + +EXPORT_SYMBOL(map_page); +EXPORT_SYMBOL(get_vm_area); extern unsigned long agp_special_page; EXPORT_SYMBOL_NOVERS(agp_special_page); #endif /* defined(CONFIG_ALL_PPC) */ diff -uNr linux-2.4.20/arch/ppc/kernel/prep_nvram.c linux-2.4.20-ben6/arch/ppc/kernel/prep_nvram.c --- linux-2.4.20/arch/ppc/kernel/prep_nvram.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/prep_nvram.c 2003-02-16 20:20:00.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.prep_nvram.c 1.14 08/13/02 20:27:38 paulus */ /* * arch/ppc/platforms/prep_nvram.c diff -uNr linux-2.4.20/arch/ppc/kernel/process.c linux-2.4.20-ben6/arch/ppc/kernel/process.c --- linux-2.4.20/arch/ppc/kernel/process.c 2001-11-26 14:29:17.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/process.c 2003-02-16 20:20:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.process.c 1.34 11/23/01 16:38:29 paulus + * BK Id: SCCS/s.process.c 1.36 08/20/02 15:26:44 benh */ /* * linux/arch/ppc/kernel/process.c @@ -453,14 +453,19 @@ unsigned long i; printk("Call backtrace: "); + if (sp == NULL) + sp = (unsigned long *)_get_SP(); while (sp) { - if (__get_user( i, &sp[1] )) + if (__get_user(sp, (unsigned long **)sp)) + break; + if (sp == NULL) + break; + if (__get_user(i, &sp[1])) break; if (cnt++ % 7 == 0) printk("\n"); printk("%08lX ", i); - if (cnt > 32) break; - if (__get_user(sp, (unsigned long **)sp)) + if (cnt > 32) break; } printk("\n"); diff -uNr linux-2.4.20/arch/ppc/kernel/prom.c linux-2.4.20-ben6/arch/ppc/kernel/prom.c --- linux-2.4.20/arch/ppc/kernel/prom.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/prom.c 2003-02-16 20:20:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.prom.c 1.59 10/20/02 20:14:45 benh */ /* * Procedures for interfacing to the Open Firmware PROM on diff -uNr linux-2.4.20/arch/ppc/kernel/prom_init.c linux-2.4.20-ben6/arch/ppc/kernel/prom_init.c --- linux-2.4.20/arch/ppc/kernel/prom_init.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/prom_init.c 2003-02-16 20:20:08.000000000 +0100 @@ -266,7 +266,7 @@ { phandle node; ihandle ih; - int i; + int i, j; char type[16], *path; static unsigned char default_colors[] = { 0x00, 0x00, 0x00, @@ -325,26 +325,26 @@ break; } -try_again: /* * Open the first display and set its colormap. */ - if (prom_num_displays > 0) { - path = prom_display_paths[0]; + for (j=0; j 0) - prom_disp_node = prom_display_nodes[0]; - else + if (--prom_num_displays > 0) { + prom_disp_node = prom_display_nodes[j]; + j--; + } else prom_disp_node = NULL; - goto try_again; + continue; } else { prom_print("... ok\n"); /* diff -uNr linux-2.4.20/arch/ppc/kernel/ptrace.c linux-2.4.20-ben6/arch/ppc/kernel/ptrace.c --- linux-2.4.20/arch/ppc/kernel/ptrace.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/ptrace.c 2003-02-16 20:20:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ptrace.c 1.14 01/17/02 23:05:50 paulus + * BK Id: SCCS/s.ptrace.c 1.16 08/13/02 20:27:38 paulus */ /* * linux/arch/ppc/kernel/ptrace.c diff -uNr linux-2.4.20/arch/ppc/kernel/qspan_pci.c linux-2.4.20-ben6/arch/ppc/kernel/qspan_pci.c --- linux-2.4.20/arch/ppc/kernel/qspan_pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/qspan_pci.c 2003-02-16 20:21:03.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.qspan_pci.c 1.9 08/13/02 20:27:38 paulus */ /* * QSpan pci routines. diff -uNr linux-2.4.20/arch/ppc/kernel/semaphore.c linux-2.4.20-ben6/arch/ppc/kernel/semaphore.c --- linux-2.4.20/arch/ppc/kernel/semaphore.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/semaphore.c 2003-02-16 20:21:37.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.semaphore.c 1.12 05/17/01 18:14:22 cort + * BK Id: SCCS/s.semaphore.c 1.14 06/05/01 21:22:03 paulus */ /* * PowerPC-specific semaphore code. diff -uNr linux-2.4.20/arch/ppc/kernel/setup.c linux-2.4.20-ben6/arch/ppc/kernel/setup.c --- linux-2.4.20/arch/ppc/kernel/setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/setup.c 2003-02-16 20:20:13.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.setup.c 1.83 10/29/02 20:27:53 benh */ /* * Common prep/pmac/chrp boot and setup code. @@ -154,7 +154,7 @@ return 0; pvr = cpu_data[i].pvr; lpj = cpu_data[i].loops_per_jiffy; - seq_printf(m, "processor\t: %lu\n", i); + seq_printf(m, "processor\t: %u\n", i); #else pvr = mfspr(PVR); lpj = loops_per_jiffy; @@ -331,6 +331,7 @@ unsigned long r6, unsigned long r7) { #ifdef CONFIG_BOOTX_TEXT + extern int force_printk_to_btext; if (boot_text_mapped) { btext_clearscreen(); btext_welcome(); @@ -417,6 +418,25 @@ } cmd_line[sizeof(cmd_line) - 1] = 0; + /* Debug stuff, do not merge ! */ +#ifdef CONFIG_ADB_PMU + if (strstr(cmd_line, "fake_sleep")) { + extern int __fake_sleep; + __fake_sleep = 1; + } +#endif /* CONFIG_ADB_PMU */ +#ifdef CONFIG_ADB + if (strstr(cmd_line, "adb_sync")) { + extern int __adb_probe_sync; + __adb_probe_sync = 1; + } +#endif /* CONFIG_ADB */ + if (strstr(cmd_line, "nol3") && cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR) + _set_L3CR(0); +#ifdef CONFIG_BOOTX_TEXT + if (strstr(cmd_line, "printkbtext")) + force_printk_to_btext = 1; +#endif switch (_machine) { case _MACH_Pmac: pmac_init(r3, r4, r5, r6, r7); diff -uNr linux-2.4.20/arch/ppc/kernel/signal.c linux-2.4.20-ben6/arch/ppc/kernel/signal.c --- linux-2.4.20/arch/ppc/kernel/signal.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/signal.c 2003-02-16 20:20:14.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.signal.c 1.15 11/27/02 09:12:55 paulus */ /* * linux/arch/ppc/kernel/signal.c diff -uNr linux-2.4.20/arch/ppc/kernel/smp.c linux-2.4.20-ben6/arch/ppc/kernel/smp.c --- linux-2.4.20/arch/ppc/kernel/smp.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/smp.c 2003-02-16 20:20:04.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.smp.c 1.40 03/28/02 16:54:23 hozer + * BK Id: SCCS/s.smp.c 1.43 02/16/03 18:05:50 benh */ /* * Smp support for ppc. @@ -230,6 +230,10 @@ timeout = 1000000; while (atomic_read(&data.started) != cpus) { if (--timeout == 0) { +#ifdef CONFIG_XMON + xmon_printf("smp_call_function on cpu %d: other cpus not responding (%d)\n", + smp_processor_id(), atomic_read(&data.started)); +#endif printk("smp_call_function on cpu %d: other cpus not responding (%d)\n", smp_processor_id(), atomic_read(&data.started)); goto out; @@ -242,6 +246,10 @@ timeout = 1000000; while (atomic_read(&data.finished) != cpus) { if (--timeout == 0) { +#ifdef CONFIG_XMON + xmon_printf("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", + smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); +#endif printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); goto out; @@ -500,6 +508,12 @@ } } +void __init smp_call_init_cpu(int cpu) +{ + if (smp_ops->init_cpu) + smp_ops->init_cpu(cpu); +} + void __init smp_callin(void) { int cpu = current->processor; diff -uNr linux-2.4.20/arch/ppc/kernel/softemu8xx.c linux-2.4.20-ben6/arch/ppc/kernel/softemu8xx.c --- linux-2.4.20/arch/ppc/kernel/softemu8xx.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/softemu8xx.c 2003-02-16 20:21:21.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.softemu8xx.c 1.8 05/17/01 18:14:22 cort + * BK Id: SCCS/s.softemu8xx.c 1.10 06/05/01 21:22:04 paulus */ /* * Software emulation of some PPC instructions for the 8xx core. diff -uNr linux-2.4.20/arch/ppc/kernel/syscalls.c linux-2.4.20-ben6/arch/ppc/kernel/syscalls.c --- linux-2.4.20/arch/ppc/kernel/syscalls.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/kernel/syscalls.c 2003-02-16 20:21:21.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.syscalls.c 1.13 03/13/02 09:12:22 trini + * BK Id: SCCS/s.syscalls.c 1.14 04/16/02 20:08:22 paulus */ /* * linux/arch/ppc/kernel/sys_ppc.c diff -uNr linux-2.4.20/arch/ppc/kernel/time.c linux-2.4.20-ben6/arch/ppc/kernel/time.c --- linux-2.4.20/arch/ppc/kernel/time.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/time.c 2003-02-16 20:19:52.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.time.c 1.36 11/11/02 11:10:25 trini */ /* * Common time routines among all ppc machines. @@ -295,13 +295,11 @@ write_unlock_irqrestore(&xtime_lock, flags); } - +/* This function is only called on the boot processor */ void __init time_init(void) { time_t sec, old_sec; unsigned old_stamp, stamp, elapsed; - /* This function is only called on the boot processor */ - unsigned long flags; if (ppc_md.time_init != NULL) time_offset = ppc_md.time_init(); @@ -318,32 +316,33 @@ /* Now that the decrementer is calibrated, it can be used in case the * clock is stuck, but the fact that we have to handle the 601 * makes things more complex. Repeatedly read the RTC until the - * next second boundary to try to achieve some precision... + * next second boundary to try to achieve some precision. If there + * is no RTC, we still need to set tb_last_stamp and + * last_jiffy_stamp(cpu 0) to the current stamp. */ + stamp = get_native_tbl(); if (ppc_md.get_rtc_time) { - stamp = get_native_tbl(); sec = ppc_md.get_rtc_time(); elapsed = 0; do { old_stamp = stamp; old_sec = sec; stamp = get_native_tbl(); - if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000; + if (__USE_RTC() && stamp < old_stamp) + old_stamp -= 1000000000; elapsed += stamp - old_stamp; sec = ppc_md.get_rtc_time(); } while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy); - if (sec==old_sec) { + if (sec == old_sec) printk("Warning: real time clock seems stuck!\n"); - } - write_lock_irqsave(&xtime_lock, flags); xtime.tv_sec = sec; - last_jiffy_stamp(0) = tb_last_stamp = stamp; xtime.tv_usec = 0; /* No update now, we just read the time from the RTC ! */ last_rtc_update = xtime.tv_sec; - write_unlock_irqrestore(&xtime_lock, flags); } + last_jiffy_stamp(0) = tb_last_stamp = stamp; + /* Not exact, but the timer interrupt takes care of this */ set_dec(tb_ticks_per_jiffy); diff -uNr linux-2.4.20/arch/ppc/kernel/traps.c linux-2.4.20-ben6/arch/ppc/kernel/traps.c --- linux-2.4.20/arch/ppc/kernel/traps.c 2001-11-03 02:43:54.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/kernel/traps.c 2003-02-16 20:21:03.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.traps.c 1.22 10/11/01 10:33:09 paulus + * BK Id: SCCS/s.traps.c 1.25 11/07/02 18:38:50 benh */ /* * linux/arch/ppc/kernel/traps.c @@ -38,6 +38,9 @@ #include #include #include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif extern int fix_alignment(struct pt_regs *); extern void bad_page_fault(struct pt_regs *, unsigned long, int sig); @@ -78,10 +81,25 @@ void die(const char * str, struct pt_regs * fp, long err) { +#ifdef CONFIG_BOOTX_TEXT + extern int force_printk_to_btext; +#endif console_verbose(); spin_lock_irq(&oops_lock); +#ifdef CONFIG_BOOTX_TEXT + force_printk_to_btext = 1; +#endif +#ifdef CONFIG_PMAC_BACKLIGHT + if (_machine == _MACH_Pmac) { + set_backlight_enable(1); + set_backlight_level(BACKLIGHT_MAX); + } +#endif printk("Oops: %s, sig: %ld\n", str, err); show_regs(fp); +#ifdef CONFIG_BOOTX_TEXT + force_printk_to_btext = 0; +#endif spin_unlock_irq(&oops_lock); /* do_exit() should take care of panic'ing from an interrupt * context so we don't handle it here @@ -345,6 +363,7 @@ { printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n", current, regs->gpr[1]); + print_backtrace((unsigned long *)regs->gpr[1]); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) debugger(regs); #endif diff -uNr linux-2.4.20/arch/ppc/lib/Makefile linux-2.4.20-ben6/arch/ppc/lib/Makefile --- linux-2.4.20/arch/ppc/lib/Makefile 2001-11-16 19:10:08.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/lib/Makefile 2003-02-16 20:20:22.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.10 11/08/01 07:57:40 paulus +# BK Id: SCCS/s.Makefile 1.11 11/18/01 16:35:08 paulus # # # Makefile for ppc-specific library files.. diff -uNr linux-2.4.20/arch/ppc/lib/checksum.S linux-2.4.20-ben6/arch/ppc/lib/checksum.S --- linux-2.4.20/arch/ppc/lib/checksum.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/lib/checksum.S 2003-02-16 20:20:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.checksum.S 1.10 08/13/02 20:27:38 paulus */ /* * This file contains assembly-language implementations diff -uNr linux-2.4.20/arch/ppc/lib/locks.c linux-2.4.20-ben6/arch/ppc/lib/locks.c --- linux-2.4.20/arch/ppc/lib/locks.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/lib/locks.c 2003-02-16 20:19:50.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.locks.c 1.15 05/04/02 16:12:57 benh */ /* * Locks for smp ppc @@ -18,8 +18,16 @@ #if SPINLOCK_DEBUG +/* Route debug output to xmon when possible, there are more chances + * for it to work than the console + */ +#ifdef CONFIG_XMON +extern void xmon_printf(const char* fmt,...); +#define printk xmon_printf +#endif + #undef INIT_STUCK -#define INIT_STUCK 200000000 /*0xffffffff*/ +#define INIT_STUCK 0xffffffff /* * Try to acquire a spinlock. @@ -59,6 +67,9 @@ lock, cpu, __builtin_return_address(0), lock->owner_cpu,lock->owner_pc); stuck = INIT_STUCK; +#ifdef CONFIG_XMON +// xmon(NULL); +#endif /* CONFIG_XMON */ /* steal the lock */ /*xchg_u32((void *)&lock->lock,0);*/ } @@ -88,7 +99,7 @@ lp, smp_processor_id(), (int)lp->owner_cpu, lp->owner_pc,lp->lock); lp->owner_pc = lp->owner_cpu = 0; - wmb(); + mb(); lp->lock = 0; } @@ -122,7 +133,7 @@ /* try to get the read lock again */ goto again; } - wmb(); + __asm__ __volatile__ ("isync" : : : "memory"); } void _read_unlock(rwlock_t *rw) @@ -131,7 +142,7 @@ printk("_read_unlock(): %s/%d (nip %08lX) lock %lx\n", current->comm,current->pid,current->thread.regs->nip, rw->lock); - wmb(); + mb(); atomic_dec((atomic_t *) &(rw)->lock); } @@ -172,7 +183,7 @@ } goto again; } - wmb(); + __asm__ __volatile__ ("isync" : : : "memory"); } void _write_unlock(rwlock_t *rw) @@ -181,7 +192,7 @@ printk("_write_lock(): %s/%d (nip %08lX) lock %lx\n", current->comm,current->pid,current->thread.regs->nip, rw->lock); - wmb(); + mb(); clear_bit(31,&(rw)->lock); } diff -uNr linux-2.4.20/arch/ppc/lib/strcase.c linux-2.4.20-ben6/arch/ppc/lib/strcase.c --- linux-2.4.20/arch/ppc/lib/strcase.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/lib/strcase.c 2003-02-16 20:20:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.strcase.c 1.5 05/17/01 18:14:22 cort + * BK Id: SCCS/s.strcase.c 1.7 06/05/01 21:22:04 paulus */ #include diff -uNr linux-2.4.20/arch/ppc/lib/string.S linux-2.4.20-ben6/arch/ppc/lib/string.S --- linux-2.4.20/arch/ppc/lib/string.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/lib/string.S 2003-02-16 20:20:37.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.string.S 1.13 08/13/02 20:27:38 paulus */ /* * String handling functions for PowerPC. diff -uNr linux-2.4.20/arch/ppc/math-emu/Makefile linux-2.4.20-ben6/arch/ppc/math-emu/Makefile --- linux-2.4.20/arch/ppc/math-emu/Makefile 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/Makefile 2003-02-16 20:20:04.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:22 cort +# BK Id: SCCS/s.Makefile 1.5 06/05/01 21:22:04 paulus # # # diff -uNr linux-2.4.20/arch/ppc/math-emu/double.h linux-2.4.20-ben6/arch/ppc/math-emu/double.h --- linux-2.4.20/arch/ppc/math-emu/double.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/double.h 2003-02-16 20:21:06.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.double.h 1.5 05/17/01 18:14:22 cort + * BK Id: SCCS/s.double.h 1.7 06/05/01 21:22:04 paulus */ /* * Definitions for IEEE Double Precision diff -uNr linux-2.4.20/arch/ppc/math-emu/fabs.c linux-2.4.20-ben6/arch/ppc/math-emu/fabs.c --- linux-2.4.20/arch/ppc/math-emu/fabs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fabs.c 2003-02-16 20:21:17.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fabs.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fabs.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fadd.c linux-2.4.20-ben6/arch/ppc/math-emu/fadd.c --- linux-2.4.20/arch/ppc/math-emu/fadd.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fadd.c 2003-02-16 20:21:20.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fadd.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fadd.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fadds.c linux-2.4.20-ben6/arch/ppc/math-emu/fadds.c --- linux-2.4.20/arch/ppc/math-emu/fadds.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fadds.c 2003-02-16 20:21:32.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fadds.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fadds.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fcmpo.c linux-2.4.20-ben6/arch/ppc/math-emu/fcmpo.c --- linux-2.4.20/arch/ppc/math-emu/fcmpo.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fcmpo.c 2003-02-16 20:20:03.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fcmpo.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fcmpo.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fcmpu.c linux-2.4.20-ben6/arch/ppc/math-emu/fcmpu.c --- linux-2.4.20/arch/ppc/math-emu/fcmpu.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fcmpu.c 2003-02-16 20:20:13.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fcmpu.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fcmpu.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fctiw.c linux-2.4.20-ben6/arch/ppc/math-emu/fctiw.c --- linux-2.4.20/arch/ppc/math-emu/fctiw.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fctiw.c 2003-02-16 20:20:37.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fctiw.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fctiw.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fctiwz.c linux-2.4.20-ben6/arch/ppc/math-emu/fctiwz.c --- linux-2.4.20/arch/ppc/math-emu/fctiwz.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fctiwz.c 2003-02-16 20:21:20.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fctiwz.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fctiwz.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fdiv.c linux-2.4.20-ben6/arch/ppc/math-emu/fdiv.c --- linux-2.4.20/arch/ppc/math-emu/fdiv.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fdiv.c 2003-02-16 20:20:25.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fdiv.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fdiv.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fdivs.c linux-2.4.20-ben6/arch/ppc/math-emu/fdivs.c --- linux-2.4.20/arch/ppc/math-emu/fdivs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fdivs.c 2003-02-16 20:20:26.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fdivs.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fdivs.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fmadd.c linux-2.4.20-ben6/arch/ppc/math-emu/fmadd.c --- linux-2.4.20/arch/ppc/math-emu/fmadd.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fmadd.c 2003-02-16 20:20:28.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fmadd.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fmadd.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fmadds.c linux-2.4.20-ben6/arch/ppc/math-emu/fmadds.c --- linux-2.4.20/arch/ppc/math-emu/fmadds.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fmadds.c 2003-02-16 20:21:43.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fmadds.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fmadds.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fmr.c linux-2.4.20-ben6/arch/ppc/math-emu/fmr.c --- linux-2.4.20/arch/ppc/math-emu/fmr.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fmr.c 2003-02-16 20:20:40.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fmr.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fmr.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fmsub.c linux-2.4.20-ben6/arch/ppc/math-emu/fmsub.c --- linux-2.4.20/arch/ppc/math-emu/fmsub.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fmsub.c 2003-02-16 20:19:53.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fmsub.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fmsub.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fmsubs.c linux-2.4.20-ben6/arch/ppc/math-emu/fmsubs.c --- linux-2.4.20/arch/ppc/math-emu/fmsubs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fmsubs.c 2003-02-16 20:21:42.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fmsubs.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fmsubs.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fmul.c linux-2.4.20-ben6/arch/ppc/math-emu/fmul.c --- linux-2.4.20/arch/ppc/math-emu/fmul.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fmul.c 2003-02-16 20:20:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fmul.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fmul.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fmuls.c linux-2.4.20-ben6/arch/ppc/math-emu/fmuls.c --- linux-2.4.20/arch/ppc/math-emu/fmuls.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fmuls.c 2003-02-16 20:20:20.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fmuls.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fmuls.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fnabs.c linux-2.4.20-ben6/arch/ppc/math-emu/fnabs.c --- linux-2.4.20/arch/ppc/math-emu/fnabs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fnabs.c 2003-02-16 20:20:39.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fnabs.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fnabs.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fneg.c linux-2.4.20-ben6/arch/ppc/math-emu/fneg.c --- linux-2.4.20/arch/ppc/math-emu/fneg.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fneg.c 2003-02-16 20:19:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fneg.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fneg.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fnmadd.c linux-2.4.20-ben6/arch/ppc/math-emu/fnmadd.c --- linux-2.4.20/arch/ppc/math-emu/fnmadd.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fnmadd.c 2003-02-16 20:21:26.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fnmadd.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fnmadd.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fnmadds.c linux-2.4.20-ben6/arch/ppc/math-emu/fnmadds.c --- linux-2.4.20/arch/ppc/math-emu/fnmadds.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fnmadds.c 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fnmadds.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fnmadds.c 1.8 06/05/01 21:22:04 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fnmsub.c linux-2.4.20-ben6/arch/ppc/math-emu/fnmsub.c --- linux-2.4.20/arch/ppc/math-emu/fnmsub.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fnmsub.c 2003-02-16 20:21:25.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fnmsub.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fnmsub.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fnmsubs.c linux-2.4.20-ben6/arch/ppc/math-emu/fnmsubs.c --- linux-2.4.20/arch/ppc/math-emu/fnmsubs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fnmsubs.c 2003-02-16 20:21:06.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fnmsubs.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fnmsubs.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fres.c linux-2.4.20-ben6/arch/ppc/math-emu/fres.c --- linux-2.4.20/arch/ppc/math-emu/fres.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fres.c 2003-02-16 20:21:41.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fres.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fres.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/frsp.c linux-2.4.20-ben6/arch/ppc/math-emu/frsp.c --- linux-2.4.20/arch/ppc/math-emu/frsp.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/frsp.c 2003-02-16 20:20:21.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.frsp.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.frsp.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/frsqrte.c linux-2.4.20-ben6/arch/ppc/math-emu/frsqrte.c --- linux-2.4.20/arch/ppc/math-emu/frsqrte.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/frsqrte.c 2003-02-16 20:21:04.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.frsqrte.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.frsqrte.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fsel.c linux-2.4.20-ben6/arch/ppc/math-emu/fsel.c --- linux-2.4.20/arch/ppc/math-emu/fsel.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fsel.c 2003-02-16 20:21:05.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fsel.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fsel.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fsqrt.c linux-2.4.20-ben6/arch/ppc/math-emu/fsqrt.c --- linux-2.4.20/arch/ppc/math-emu/fsqrt.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fsqrt.c 2003-02-16 20:19:50.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fsqrt.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fsqrt.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fsqrts.c linux-2.4.20-ben6/arch/ppc/math-emu/fsqrts.c --- linux-2.4.20/arch/ppc/math-emu/fsqrts.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fsqrts.c 2003-02-16 20:20:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fsqrts.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fsqrts.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fsub.c linux-2.4.20-ben6/arch/ppc/math-emu/fsub.c --- linux-2.4.20/arch/ppc/math-emu/fsub.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fsub.c 2003-02-16 20:20:39.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fsub.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fsub.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/fsubs.c linux-2.4.20-ben6/arch/ppc/math-emu/fsubs.c --- linux-2.4.20/arch/ppc/math-emu/fsubs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/fsubs.c 2003-02-16 20:20:13.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fsubs.c 1.6 05/17/01 18:14:22 cort + * BK Id: SCCS/s.fsubs.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/lfd.c linux-2.4.20-ben6/arch/ppc/math-emu/lfd.c --- linux-2.4.20/arch/ppc/math-emu/lfd.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/lfd.c 2003-02-16 20:20:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.lfd.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.lfd.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/lfs.c linux-2.4.20-ben6/arch/ppc/math-emu/lfs.c --- linux-2.4.20/arch/ppc/math-emu/lfs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/lfs.c 2003-02-16 20:21:47.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.lfs.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.lfs.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/math.c linux-2.4.20-ben6/arch/ppc/math-emu/math.c --- linux-2.4.20/arch/ppc/math-emu/math.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/math.c 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.math.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.math.c 1.8 06/05/01 21:22:05 paulus */ /* * arch/ppc/math-emu/math.c diff -uNr linux-2.4.20/arch/ppc/math-emu/mcrfs.c linux-2.4.20-ben6/arch/ppc/math-emu/mcrfs.c --- linux-2.4.20/arch/ppc/math-emu/mcrfs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/mcrfs.c 2003-02-16 20:19:57.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mcrfs.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.mcrfs.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/mffs.c linux-2.4.20-ben6/arch/ppc/math-emu/mffs.c --- linux-2.4.20/arch/ppc/math-emu/mffs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/mffs.c 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mffs.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.mffs.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/mtfsb0.c linux-2.4.20-ben6/arch/ppc/math-emu/mtfsb0.c --- linux-2.4.20/arch/ppc/math-emu/mtfsb0.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/mtfsb0.c 2003-02-16 20:20:37.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mtfsb0.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.mtfsb0.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/mtfsb1.c linux-2.4.20-ben6/arch/ppc/math-emu/mtfsb1.c --- linux-2.4.20/arch/ppc/math-emu/mtfsb1.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/mtfsb1.c 2003-02-16 20:19:59.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mtfsb1.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.mtfsb1.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/mtfsf.c linux-2.4.20-ben6/arch/ppc/math-emu/mtfsf.c --- linux-2.4.20/arch/ppc/math-emu/mtfsf.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/mtfsf.c 2003-02-16 20:21:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mtfsf.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.mtfsf.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/mtfsfi.c linux-2.4.20-ben6/arch/ppc/math-emu/mtfsfi.c --- linux-2.4.20/arch/ppc/math-emu/mtfsfi.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/mtfsfi.c 2003-02-16 20:21:36.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mtfsfi.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.mtfsfi.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/op-1.h linux-2.4.20-ben6/arch/ppc/math-emu/op-1.h --- linux-2.4.20/arch/ppc/math-emu/op-1.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/op-1.h 2003-02-16 20:20:25.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.op-1.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.op-1.h 1.7 06/05/01 21:22:05 paulus */ /* * Basic one-word fraction declaration and manipulation. diff -uNr linux-2.4.20/arch/ppc/math-emu/op-2.h linux-2.4.20-ben6/arch/ppc/math-emu/op-2.h --- linux-2.4.20/arch/ppc/math-emu/op-2.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/op-2.h 2003-02-16 20:21:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.op-2.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.op-2.h 1.7 06/05/01 21:22:05 paulus */ /* * Basic two-word fraction declaration and manipulation. diff -uNr linux-2.4.20/arch/ppc/math-emu/op-4.h linux-2.4.20-ben6/arch/ppc/math-emu/op-4.h --- linux-2.4.20/arch/ppc/math-emu/op-4.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/op-4.h 2003-02-16 20:21:15.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.op-4.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.op-4.h 1.7 06/05/01 21:22:05 paulus */ /* * Basic four-word fraction declaration and manipulation. diff -uNr linux-2.4.20/arch/ppc/math-emu/op-common.h linux-2.4.20-ben6/arch/ppc/math-emu/op-common.h --- linux-2.4.20/arch/ppc/math-emu/op-common.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/op-common.h 2003-02-16 20:20:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.op-common.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.op-common.h 1.7 06/05/01 21:22:05 paulus */ #define _FP_DECL(wc, X) \ diff -uNr linux-2.4.20/arch/ppc/math-emu/sfp-machine.h linux-2.4.20-ben6/arch/ppc/math-emu/sfp-machine.h --- linux-2.4.20/arch/ppc/math-emu/sfp-machine.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/sfp-machine.h 2003-02-16 20:21:43.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.sfp-machine.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.sfp-machine.h 1.7 06/05/01 21:22:05 paulus */ /* Machine-dependent software floating-point definitions. PPC version. Copyright (C) 1997 Free Software Foundation, Inc. diff -uNr linux-2.4.20/arch/ppc/math-emu/single.h linux-2.4.20-ben6/arch/ppc/math-emu/single.h --- linux-2.4.20/arch/ppc/math-emu/single.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/single.h 2003-02-16 20:20:40.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.single.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.single.h 1.7 06/05/01 21:22:05 paulus */ /* * Definitions for IEEE Single Precision diff -uNr linux-2.4.20/arch/ppc/math-emu/soft-fp.h linux-2.4.20-ben6/arch/ppc/math-emu/soft-fp.h --- linux-2.4.20/arch/ppc/math-emu/soft-fp.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/soft-fp.h 2003-02-16 20:20:37.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.soft-fp.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.soft-fp.h 1.7 06/05/01 21:22:05 paulus */ #ifndef SOFT_FP_H #define SOFT_FP_H diff -uNr linux-2.4.20/arch/ppc/math-emu/stfd.c linux-2.4.20-ben6/arch/ppc/math-emu/stfd.c --- linux-2.4.20/arch/ppc/math-emu/stfd.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/stfd.c 2003-02-16 20:21:48.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.stfd.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.stfd.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/stfiwx.c linux-2.4.20-ben6/arch/ppc/math-emu/stfiwx.c --- linux-2.4.20/arch/ppc/math-emu/stfiwx.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/stfiwx.c 2003-02-16 20:20:05.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.stfiwx.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.stfiwx.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/stfs.c linux-2.4.20-ben6/arch/ppc/math-emu/stfs.c --- linux-2.4.20/arch/ppc/math-emu/stfs.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/stfs.c 2003-02-16 20:21:46.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.stfs.c 1.6 05/17/01 18:14:23 cort + * BK Id: SCCS/s.stfs.c 1.8 06/05/01 21:22:05 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/math-emu/types.c linux-2.4.20-ben6/arch/ppc/math-emu/types.c --- linux-2.4.20/arch/ppc/math-emu/types.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/types.c 2003-02-16 20:21:32.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.types.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.types.c 1.7 06/05/01 21:22:05 paulus */ #include "soft-fp.h" diff -uNr linux-2.4.20/arch/ppc/math-emu/udivmodti4.c linux-2.4.20-ben6/arch/ppc/math-emu/udivmodti4.c --- linux-2.4.20/arch/ppc/math-emu/udivmodti4.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/math-emu/udivmodti4.c 2003-02-16 20:21:17.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.udivmodti4.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.udivmodti4.c 1.7 06/05/01 21:22:05 paulus */ /* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */ diff -uNr linux-2.4.20/arch/ppc/mm/4xx_tlb.c linux-2.4.20-ben6/arch/ppc/mm/4xx_tlb.c --- linux-2.4.20/arch/ppc/mm/4xx_tlb.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/mm/4xx_tlb.c 2003-02-16 20:21:14.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.4xx_tlb.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.4xx_tlb.c 1.7 06/05/01 21:22:05 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/mm/4xx_tlb.h linux-2.4.20-ben6/arch/ppc/mm/4xx_tlb.h --- linux-2.4.20/arch/ppc/mm/4xx_tlb.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/mm/4xx_tlb.h 2003-02-16 20:21:31.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.4xx_tlb.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.4xx_tlb.h 1.7 06/05/01 21:22:05 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/mm/Makefile linux-2.4.20-ben6/arch/ppc/mm/Makefile --- linux-2.4.20/arch/ppc/mm/Makefile 2001-08-28 15:58:33.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/mm/Makefile 2003-02-16 20:21:20.000000000 +0100 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.8 08/16/01 17:25:47 paulus +# BK Id: SCCS/s.Makefile 1.9 08/29/01 08:49:24 paulus # # # Makefile for the linux ppc-specific parts of the memory manager. diff -uNr linux-2.4.20/arch/ppc/mm/extable.c linux-2.4.20-ben6/arch/ppc/mm/extable.c --- linux-2.4.20/arch/ppc/mm/extable.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/mm/extable.c 2003-02-16 20:21:16.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.extable.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.extable.c 1.7 06/05/01 21:22:06 paulus */ /* * linux/arch/ppc/mm/extable.c diff -uNr linux-2.4.20/arch/ppc/mm/fault.c linux-2.4.20-ben6/arch/ppc/mm/fault.c --- linux-2.4.20/arch/ppc/mm/fault.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/mm/fault.c 2003-02-16 20:21:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fault.c 1.15 09/24/01 16:35:10 paulus + * BK Id: SCCS/s.fault.c 1.20 01/23/03 17:54:25 benh */ /* * arch/ppc/mm/fault.c @@ -64,7 +64,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code) { - struct vm_area_struct * vma; + struct vm_area_struct * vma, * prev_vma; struct mm_struct *mm = current->mm; siginfo_t info; int code = SEGV_MAPERR; @@ -111,7 +111,16 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + /* Only allow stack grow on writes */ + if (!is_write) { + printk(KERN_DEBUG "Process %s tried to read below stack\n", + current->comm); + printk(KERN_DEBUG " addr: %08lx, gpr1: %08lx, pc: %08lx, lr: %08lx\n", + address, regs->gpr[1], regs->nip, regs->link); + goto bad_area; + } + vma = find_vma_prev(mm, address, &prev_vma); + if (expand_stack(vma, address, prev_vma)) goto bad_area; good_area: diff -uNr linux-2.4.20/arch/ppc/mm/hashtable.S linux-2.4.20-ben6/arch/ppc/mm/hashtable.S --- linux-2.4.20/arch/ppc/mm/hashtable.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/mm/hashtable.S 2003-02-16 20:20:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.hashtable.S 1.20 08/13/02 20:27:38 paulus */ /* * arch/ppc/kernel/hashtable.S diff -uNr linux-2.4.20/arch/ppc/mm/init.c linux-2.4.20-ben6/arch/ppc/mm/init.c --- linux-2.4.20/arch/ppc/mm/init.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/mm/init.c 2003-02-16 20:19:54.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.init.c 1.43 03/12/02 12:13:51 paulus + * BK Id: SCCS/s.init.c 1.47 06/25/02 17:31:35 benh */ /* * PowerPC version @@ -329,7 +329,7 @@ #ifdef CONFIG_HIGHMEM ioremap_base = PKMAP_BASE; #else - ioremap_base = 0xfe000000UL; /* for now, could be 0xfffff000 */ + ioremap_base = 0xfe000000UL; /* for now, could be 0xfffff000 (or 0 ?)*/ #endif /* CONFIG_HIGHMEM */ ioremap_bot = ioremap_base; @@ -458,6 +458,17 @@ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ + /* Sanity check: did ioremap_bot stomp over vmalloc space ? We keep + * a minimal 16Mb guard though if you only have 16Mb left, you'll + * probably run into trouble, so we also printk something if you + * have less than 64Mb. This is meant to help diagnosing such problems + * as debugging it can be really painful. --BenH. + */ + if (VMALLOC_END < (VMALLOC_START + 0x01000000UL)) + panic("Argh ! Virtual space exhausted !"); + if (VMALLOC_END < (VMALLOC_START + 0x04000000UL)) + printk(KERN_WARNING "Warning ! Virtual space small !"); + totalram_pages += free_all_bootmem(); #ifdef CONFIG_BLK_DEV_INITRD @@ -619,6 +630,10 @@ void clear_user_page(void *page, unsigned long vaddr) { clear_page(page); + /* That should not be necessary, but a glibc "feature" makes + * in important as glibc fails to invalidate blank pages + * properly + */ __flush_dcache_icache(page); } diff -uNr linux-2.4.20/arch/ppc/mm/mem_pieces.c linux-2.4.20-ben6/arch/ppc/mm/mem_pieces.c --- linux-2.4.20/arch/ppc/mm/mem_pieces.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/mm/mem_pieces.c 2003-02-16 20:19:53.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mem_pieces.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.mem_pieces.c 1.7 06/05/01 21:22:06 paulus */ /* * Copyright (c) 1996 Paul Mackerras diff -uNr linux-2.4.20/arch/ppc/mm/mem_pieces.h linux-2.4.20-ben6/arch/ppc/mm/mem_pieces.h --- linux-2.4.20/arch/ppc/mm/mem_pieces.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/mm/mem_pieces.h 2003-02-16 20:21:07.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mem_pieces.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.mem_pieces.h 1.7 06/05/01 21:22:06 paulus */ /* * Copyright (c) 1996 Paul Mackerras diff -uNr linux-2.4.20/arch/ppc/mm/pgtable.c linux-2.4.20-ben6/arch/ppc/mm/pgtable.c --- linux-2.4.20/arch/ppc/mm/pgtable.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/mm/pgtable.c 2003-02-16 20:21:16.000000000 +0100 @@ -248,7 +248,7 @@ total_lowmem = max_low_mem; #ifndef CONFIG_HIGHMEM printk(KERN_INFO "Warning, memory limited to %ld Mb, use CONFIG_HIGHMEM" - " to reach %ld Mb\n", max_low_mem >> 20, total_lowmem >> 20); + " to reach %ld Mb\n", max_low_mem >> 20, (total_lowmem+ram) >> 20); total_memory = total_lowmem; #endif /* CONFIG_HIGHMEM */ } @@ -305,7 +305,7 @@ { int i; - if (virt > KERNELBASE && virt < ioremap_bot) + if (virt > KERNELBASE && (virt < ioremap_bot || !ioremap_bot)) ioremap_bot = ioremap_base = virt; #ifdef HAVE_BATS diff -uNr linux-2.4.20/arch/ppc/platforms/Makefile linux-2.4.20-ben6/arch/ppc/platforms/Makefile --- linux-2.4.20/arch/ppc/platforms/Makefile 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/Makefile 2003-02-16 20:20:41.000000000 +0100 @@ -43,6 +43,9 @@ prep_time.o prep_setup.o pmac_sleep.o \ pmac_nvram.o obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o +ifeq ($(CONFIG_ALL_PPC),y) +obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o +endif obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o diff -uNr linux-2.4.20/arch/ppc/platforms/apus_pci.c linux-2.4.20-ben6/arch/ppc/platforms/apus_pci.c --- linux-2.4.20/arch/ppc/platforms/apus_pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/apus_pci.c 2003-02-16 20:21:31.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.apus_pci.c 1.7 08/31/02 12:27:55 paulus */ /* * Copyright (C) Michel Dänzer diff -uNr linux-2.4.20/arch/ppc/platforms/apus_pci.h linux-2.4.20-ben6/arch/ppc/platforms/apus_pci.h --- linux-2.4.20/arch/ppc/platforms/apus_pci.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/apus_pci.h 2003-02-16 20:21:18.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.apus_pci.h 1.6 08/13/02 21:40:09 paulus */ /* * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer diff -uNr linux-2.4.20/arch/ppc/platforms/apus_setup.c linux-2.4.20-ben6/arch/ppc/platforms/apus_setup.c --- linux-2.4.20/arch/ppc/platforms/apus_setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/apus_setup.c 2003-02-16 20:20:08.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.apus_setup.c 1.34 10/09/02 10:28:18 paulus */ /* * arch/ppc/platforms/apus_setup.c diff -uNr linux-2.4.20/arch/ppc/platforms/bseip.h linux-2.4.20-ben6/arch/ppc/platforms/bseip.h --- linux-2.4.20/arch/ppc/platforms/bseip.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/bseip.h 2003-02-16 20:21:05.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus + * BK Id: SCCS/s.bseip.h 1.13 08/13/02 20:27:38 paulus */ /* diff -uNr linux-2.4.20/arch/ppc/platforms/chrp_pci.c linux-2.4.20-ben6/arch/ppc/platforms/chrp_pci.c --- linux-2.4.20/arch/ppc/platforms/chrp_pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/chrp_pci.c 2003-02-16 20:21:25.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.chrp_pci.c 1.29 09/11/02 14:41:31 paulus */ /* * CHRP pci routines. diff -uNr linux-2.4.20/arch/ppc/platforms/chrp_setup.c linux-2.4.20-ben6/arch/ppc/platforms/chrp_setup.c --- linux-2.4.20/arch/ppc/platforms/chrp_setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/chrp_setup.c 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.chrp_setup.c 1.59 01/20/03 21:59:06 benh */ /* * arch/ppc/platforms/setup.c @@ -56,6 +56,11 @@ #include #include +#ifdef CONFIG_SERIAL +#include +#include +#endif + unsigned long chrp_get_rtc_time(void); int chrp_set_rtc_time(unsigned long nowtime); void chrp_calibrate_decr(void); @@ -411,7 +416,6 @@ chrp_init_irq_openpic(unsigned long intack) { int i; - unsigned char* chrp_int_ack_special = 0; int nmi_irq = -1; unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; @@ -421,12 +425,10 @@ OpenPIC_InitSenses = init_senses; OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS; - if (intack) - chrp_int_ack_special = (unsigned char *) ioremap(intack, 1); - openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq); + openpic_init(1, NUM_8259_INTERRUPTS, 0, nmi_irq); for (i = 0; i < NUM_8259_INTERRUPTS; i++) irq_desc[i].handler = &i8259_pic; - i8259_init(0); + i8259_init(intack); } static void __init @@ -572,6 +574,18 @@ } #endif +#ifdef CONFIG_VT +static void __chrp +dummy_pckbd_leds(unsigned char leds) +{ +} + +static void __init +dummy_pckbd_init_hw(void) +{ +} +#endif /* CONFIG_VT */ + void __init chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -596,6 +610,14 @@ /* Check if it's a briq */ machine = get_property(root, "model", NULL); is_briq = machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0; +#ifdef CONFIG_SERIAL + if (is_briq) { + /* briQ has a different serial clock */ + extern struct serial_state rs_table[]; + rs_table[0].baud_base = (7372800 / 16); + rs_table[1].baud_base = (7372800 / 16); + } +#endif /* CONFIG_SERIAL */ ppc_md.setup_arch = chrp_setup_arch; ppc_md.show_percpuinfo = of_show_percpuinfo; @@ -623,8 +645,8 @@ ppc_md.kbd_getkeycode = pckbd_getkeycode; ppc_md.kbd_translate = pckbd_translate; ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; + ppc_md.kbd_leds = is_briq ? dummy_pckbd_leds : pckbd_leds; + ppc_md.kbd_init_hw = is_briq ? dummy_pckbd_init_hw : pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; SYSRQ_KEY = 0x54; diff -uNr linux-2.4.20/arch/ppc/platforms/chrp_time.c linux-2.4.20-ben6/arch/ppc/platforms/chrp_time.c --- linux-2.4.20/arch/ppc/platforms/chrp_time.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/chrp_time.c 2003-02-16 20:20:03.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.chrp_time.c 1.13 08/13/02 20:27:38 paulus */ /* * arch/ppc/platforms/chrp_time.c diff -uNr linux-2.4.20/arch/ppc/platforms/error_log.c linux-2.4.20-ben6/arch/ppc/platforms/error_log.c --- linux-2.4.20/arch/ppc/platforms/error_log.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/error_log.c 2003-02-16 20:21:46.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort + * BK Id: SCCS/s.error_log.c 1.7 08/13/02 21:31:33 paulus */ /* * arch/ppc/kernel/error_log.c diff -uNr linux-2.4.20/arch/ppc/platforms/error_log.h linux-2.4.20-ben6/arch/ppc/platforms/error_log.h --- linux-2.4.20/arch/ppc/platforms/error_log.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/error_log.h 2003-02-16 20:20:28.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.error_log.h 1.6 08/13/02 21:31:33 paulus */ #ifndef __ERROR_LOG_H__ #define __ERROR_LOG_H__ diff -uNr linux-2.4.20/arch/ppc/platforms/est8260.h linux-2.4.20-ben6/arch/ppc/platforms/est8260.h --- linux-2.4.20/arch/ppc/platforms/est8260.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/est8260.h 2003-02-16 20:19:52.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort + * BK Id: SCCS/s.est8260.h 1.9 08/13/02 20:27:38 paulus */ /* Board information for the EST8260, which should be generic for diff -uNr linux-2.4.20/arch/ppc/platforms/fads.h linux-2.4.20-ben6/arch/ppc/platforms/fads.h --- linux-2.4.20/arch/ppc/platforms/fads.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/fads.h 2003-02-16 20:20:23.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini + * BK Id: SCCS/s.fads.h 1.17 08/13/02 20:27:38 paulus */ /* diff -uNr linux-2.4.20/arch/ppc/platforms/gemini.h linux-2.4.20-ben6/arch/ppc/platforms/gemini.h --- linux-2.4.20/arch/ppc/platforms/gemini.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/gemini.h 2003-02-16 20:20:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.gemini.h 1.7 08/31/02 12:27:55 paulus */ /* * arch/ppc/platforms/gemini.h diff -uNr linux-2.4.20/arch/ppc/platforms/gemini_pci.c linux-2.4.20-ben6/arch/ppc/platforms/gemini_pci.c --- linux-2.4.20/arch/ppc/platforms/gemini_pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/gemini_pci.c 2003-02-16 20:21:05.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.gemini_pci.c 1.8 08/13/02 21:40:09 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/platforms/gemini_prom.S linux-2.4.20-ben6/arch/ppc/platforms/gemini_prom.S --- linux-2.4.20/arch/ppc/platforms/gemini_prom.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/gemini_prom.S 2003-02-16 20:20:13.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.gemini_prom.S 1.7 08/13/02 21:40:09 paulus */ /* * arch/ppc/kernel/gemini_prom.S diff -uNr linux-2.4.20/arch/ppc/platforms/gemini_serial.h linux-2.4.20-ben6/arch/ppc/platforms/gemini_serial.h --- linux-2.4.20/arch/ppc/platforms/gemini_serial.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/gemini_serial.h 2003-02-16 20:20:25.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.gemini_serial.h 1.7 08/13/02 21:40:09 paulus */ #ifdef __KERNEL__ #ifndef __ASMPPC_GEMINI_SERIAL_H diff -uNr linux-2.4.20/arch/ppc/platforms/gemini_setup.c linux-2.4.20-ben6/arch/ppc/platforms/gemini_setup.c --- linux-2.4.20/arch/ppc/platforms/gemini_setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/gemini_setup.c 2003-02-16 20:21:15.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.gemini_setup.c 1.22 09/30/02 15:08:18 paulus */ /* * arch/ppc/platforms/setup.c diff -uNr linux-2.4.20/arch/ppc/platforms/ivms8.h linux-2.4.20-ben6/arch/ppc/platforms/ivms8.h --- linux-2.4.20/arch/ppc/platforms/ivms8.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/ivms8.h 2003-02-16 20:20:41.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini + * BK Id: SCCS/s.ivms8.h 1.9 08/13/02 21:33:06 paulus */ /* * Speech Design Integrated Voicemail board specific definitions diff -uNr linux-2.4.20/arch/ppc/platforms/mbx.h linux-2.4.20-ben6/arch/ppc/platforms/mbx.h --- linux-2.4.20/arch/ppc/platforms/mbx.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/mbx.h 2003-02-16 20:20:02.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus + * BK Id: SCCS/s.mbx.h 1.14 08/13/02 20:27:38 paulus */ /* * A collection of structures, addresses, and values associated with diff -uNr linux-2.4.20/arch/ppc/platforms/oak.h linux-2.4.20-ben6/arch/ppc/platforms/oak.h --- linux-2.4.20/arch/ppc/platforms/oak.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/oak.h 2003-02-16 20:21:21.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.oak.h 1.12 10/11/01 13:05:07 trini + * BK Id: SCCS/s.oak.h 1.15 08/13/02 20:27:39 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/platforms/oak_setup.c linux-2.4.20-ben6/arch/ppc/platforms/oak_setup.c --- linux-2.4.20/arch/ppc/platforms/oak_setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/oak_setup.c 2003-02-16 20:21:26.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.oak_setup.c 1.16 08/29/02 13:07:58 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/platforms/oak_setup.h linux-2.4.20-ben6/arch/ppc/platforms/oak_setup.h --- linux-2.4.20/arch/ppc/platforms/oak_setup.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/oak_setup.h 2003-02-16 20:20:13.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.oak_setup.h 1.9 08/13/02 20:27:39 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_backlight.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_backlight.c --- linux-2.4.20/arch/ppc/platforms/pmac_backlight.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_backlight.c 2003-02-16 20:20:13.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_backlight.c 1.10 12/01/01 20:09:06 benh + * BK Id: SCCS/s.pmac_backlight.c 1.13 08/13/02 20:27:39 paulus */ /* * Miscellaneous procedures for dealing with the PowerMac hardware. diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_cpufreq.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_cpufreq.c --- linux-2.4.20/arch/ppc/platforms/pmac_cpufreq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_cpufreq.c 2003-02-16 20:21:35.000000000 +0100 @@ -0,0 +1,350 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG_FREQ + +extern void low_choose_750fx_pll(int pll); +extern void low_sleep_handler(void); +extern void openpic_sleep_save_intrs(void); +extern void openpic_sleep_restore_intrs(void); +extern void enable_kernel_altivec(void); +extern void enable_kernel_fp(void); + +static unsigned int low_freq; +static unsigned int hi_freq; +static unsigned int cur_freq; +static int cpufreq_uses_pmu; + +#define PMAC_CPU_LOW_SPEED 1 +#define PMAC_CPU_HIGH_SPEED 0 + +static inline void +wakeup_decrementer(void) +{ + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + * so use get_tbl, not native + */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); +} + +#ifdef DEBUG_FREQ +static inline void +debug_calc_bogomips(void) +{ + /* This will cause a recalc of bogomips and display the + * result. We backup/restore the value to avoid affecting the + * core cpufreq framework's own calculation. + */ + extern void calibrate_delay(void); + + unsigned long save_lpj = loops_per_jiffy; + calibrate_delay(); + loops_per_jiffy = save_lpj; +} +#endif + +/* Switch CPU speed under 750FX CPU control + */ +static int __pmac +cpu_750fx_cpu_speed(int low_speed) +{ +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); +#endif + low_choose_750fx_pll(low_speed); +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); + debug_calc_bogomips(); +#endif + + return 0; +} + +/* Switch CPU speed under PMU control + */ +static int __pmac +pmu_set_cpu_speed(unsigned int low_speed) +{ + struct adb_request req; + unsigned long save_l2cr; + unsigned long save_l3cr; + +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); +#endif + /* Disable all interrupt sources on openpic */ + openpic_sleep_save_intrs(); + + /* Make sure the PMU is idle */ + pmu_suspend(); + + /* Make sure the decrementer won't interrupt us */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* We can now disable MSR_EE */ + local_irq_disable(); + + /* Giveup the FPU & vec */ + enable_kernel_fp(); + +#ifdef CONFIG_ALTIVEC + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + enable_kernel_altivec(); +#endif /* CONFIG_ALTIVEC */ + + /* Save & disable L2 and L3 caches */ + save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ + save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ + if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) + _set_L3CR(save_l3cr & 0x7fffffff); + if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) + _set_L2CR(save_l2cr & 0x7fffffff); + + /* Send the new speed command. My assumption is that this command + * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep + */ + pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed); + while (!req.complete) + pmu_poll(); + + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1); + + low_sleep_handler(); + + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0); + + /* Restore L2 cache */ + if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) + _set_L2CR(save_l2cr); + /* Restore L3 cache */ + if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) + _set_L3CR(save_l3cr); + + /* Restore userland MMU context */ + set_context(current->active_mm->context, current->active_mm->pgd); + +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); +#endif + + /* Restore decrementer */ + wakeup_decrementer(); + + /* Restore interrupts */ + openpic_sleep_restore_intrs(); + + pmu_resume(); + + /* Let interrupts flow again ... */ + local_irq_enable(); + +#ifdef DEBUG_FREQ + debug_calc_bogomips(); +#endif + + return 0; +} + +static int __pmac +do_set_cpu_speed(int speed_mode) +{ + struct cpufreq_freqs freqs; + int rc; + + freqs.old = cur_freq; + freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; + freqs.cpu = CPUFREQ_ALL_CPUS; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + if (cpufreq_uses_pmu) + rc = pmu_set_cpu_speed(speed_mode); + else + rc = cpu_750fx_cpu_speed(speed_mode); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; + + return rc; +} + +static int __pmac +pmac_cpufreq_verify(struct cpufreq_policy *policy) +{ + if (!policy) + return -EINVAL; + + policy->cpu = 0; /* UP only */ + + cpufreq_verify_within_limits(policy, low_freq, hi_freq); + + if ((policy->min > low_freq) && + (policy->max < hi_freq)) + policy->max = hi_freq; + + return 0; +} + +static int __pmac +pmac_cpufreq_setpolicy(struct cpufreq_policy *policy) +{ + int rc; + + if (!policy) + return -EINVAL; + if (policy->min > low_freq) + rc = do_set_cpu_speed(PMAC_CPU_HIGH_SPEED); + else if (policy->max < hi_freq) + rc = do_set_cpu_speed(PMAC_CPU_LOW_SPEED); + else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) + rc = do_set_cpu_speed(PMAC_CPU_LOW_SPEED); + else + rc = do_set_cpu_speed(PMAC_CPU_HIGH_SPEED); + + return rc; +} + +unsigned int __pmac +pmac_get_cur_cpufreq(void) +{ + return cur_freq; +} + + +/* Currently, we support the following machines: + * + * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) + * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) + * - iBook2 500 (PMU based, 400Mhz & 500Mhz) + * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) + */ +static int __init +pmac_cpufreq_setup(void) +{ + struct device_node *cpunode; + struct cpufreq_driver *driver; + u32 *value; + int has_freq_ctl = 0; + int rc; + + memset(&driver, 0, sizeof(driver)); + + /* Assume only one CPU */ + cpunode = find_type_devices("cpu"); + if (!cpunode) + goto out; + + /* Get current cpu clock freq */ + value = (u32 *)get_property(cpunode, "clock-frequency", NULL); + if (!value) + goto out; + cur_freq = (*value) / 1000; + + /* Check for newer machines */ + if (machine_is_compatible("PowerBook3,4") || + machine_is_compatible("PowerBook3,5") || + machine_is_compatible("MacRISC3")) { + value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); + if (!value) + goto out; + low_freq = (*value) / 1000; + /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree + * here */ + if (low_freq < 100000) + low_freq *= 10; + + value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); + if (!value) + goto out; + hi_freq = (*value) / 1000; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; + } + /* Else check for iBook2 500 */ + else if (machine_is_compatible("PowerBook4,1")) { + /* We only know about 500Mhz model */ + if (cur_freq < 450000 || cur_freq > 550000) + goto out; + hi_freq = cur_freq; + low_freq = 400000; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; + } + /* Else check for TiPb 500 */ + else if (machine_is_compatible("PowerBook3,2")) { + /* We only know about 500Mhz model */ + if (cur_freq < 450000 || cur_freq > 550000) + goto out; + hi_freq = cur_freq; + low_freq = 300000; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; + } + /* Else check for 750FX */ + else if (PVR_VER(mfspr(PVR)) == 0x7000) { + if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) + goto out; + hi_freq = cur_freq; + value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL); + if (!value) + goto out; + low_freq = (*value) / 1000; + cpufreq_uses_pmu = 0; + has_freq_ctl = 1; + } +out: + if (!has_freq_ctl) + return -ENODEV; + + /* initialization of main "cpufreq" code*/ + driver = kmalloc(sizeof(struct cpufreq_driver) + + NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); + if (!driver) + return -ENOMEM; + + driver->policy = (struct cpufreq_policy *) (driver + 1); + +#ifdef CONFIG_CPU_FREQ_24_API + driver->cpu_min_freq[0] = low_freq; + driver->cpu_cur_freq[0] = cur_freq; +#endif + + driver->verify = &pmac_cpufreq_verify; + driver->setpolicy = &pmac_cpufreq_setpolicy; + + driver->policy[0].cpu = 0; + driver->policy[0].min = low_freq; + driver->policy[0].max = cur_freq; + driver->policy[0].max_cpu_freq = hi_freq; + driver->policy[0].policy = (cur_freq == low_freq) ? + CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE; + + rc = cpufreq_register(driver); + if (rc) + kfree(driver); + return rc; +} + +__initcall(pmac_cpufreq_setup); + diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_feature.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_feature.c --- linux-2.4.20/arch/ppc/platforms/pmac_feature.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_feature.c 2003-02-16 20:21:36.000000000 +0100 @@ -17,6 +17,8 @@ * - Replace mdelay with some schedule loop if possible * - Shorten some obfuscated delays on some routines (like modem * power) + * - Refcount some clocks (see darwin) + * - Split split split... * */ #include @@ -79,7 +81,8 @@ macio_gatwick, macio_paddington, macio_keylargo, - macio_pangea + macio_pangea, + macio_intrepid, }; static const char* macio_names[] __pmacdata = @@ -92,7 +95,8 @@ "Gatwick", "Paddington", "Keylargo", - "Pangea" + "Pangea", + "Intrepid" }; static struct macio_chip @@ -538,7 +542,7 @@ return 0; } -static u32 save_fcr[5] __pmacdata; +static u32 save_fcr[6] __pmacdata; static u32 save_mbcr __pmacdata; static u32 save_gpio_levels[2] __pmacdata; static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata; @@ -814,8 +818,96 @@ } static int __pmac +pangea_modem_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + /* Hack for internal USB modem */ + if (node == NULL) { + if (macio_chips[0].type != macio_pangea && + macio_chips[0].type != macio_intrepid) + return -ENODEV; + node = macio_chips[0].of_node; + } + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); + gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; + gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; + + if (!value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + mdelay(250); + } + LOCK(flags); + if (value) { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR2); + mdelay(250); + } else { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + UNLOCK(flags); + } + if (value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); + } + return 0; +} + +static int __pmac +core99_ata100_enable(struct device_node* node, int value) +{ + unsigned long flags; + struct pci_dev *pdev = NULL; + u8 pbus, pid; + + if (uninorth_rev < 0x24) + return -ENODEV; + + LOCK(flags); + if (value) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100); + (void)UN_IN(UNI_N_CLOCK_CNTL); + UNLOCK(flags); + udelay(20); + + if (value) { + if (pci_device_from_OF_node(node, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + if (pdev == NULL) + return 0; + pci_enable_device(pdev); + pci_set_master(pdev); + } + return 0; +} + +static int __pmac core99_ide_enable(struct device_node* node, int param, int value) { + /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2 + * based ata-100 + */ switch(param) { case 0: return simple_feature_tweak(node, macio_unknown, @@ -826,6 +918,8 @@ case 2: return simple_feature_tweak(node, macio_unknown, KEYLARGO_FCR1, KL1_UIDE_ENABLE, value); + case 3: + return core99_ata100_enable(node, value); default: return -ENODEV; } @@ -873,7 +967,8 @@ struct macio_chip* macio; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; LOCK(flags); @@ -1010,40 +1105,14 @@ static int __pmac core99_reset_cpu(struct device_node* node, int param, int value) { - const int reset_lines[] = { KL_GPIO_RESET_CPU0, - KL_GPIO_RESET_CPU1, - KL_GPIO_RESET_CPU2, - KL_GPIO_RESET_CPU3 }; - int reset_io; - unsigned long flags; - struct macio_chip* macio; - - macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) - return -ENODEV; - if (param > 3 || param < 0) - return -ENODEV; - - reset_io = reset_lines[param]; - - LOCK(flags); - MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); - (void)MACIO_IN8(reset_io); - udelay(1); - MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - (void)MACIO_IN8(reset_io); - UNLOCK(flags); - - return 0; -} - -static int __pmac -rackmac_reset_cpu(struct device_node* node, int param, int value) -{ - int reset_io; + unsigned int reset_io = 0; unsigned long flags; struct macio_chip* macio; struct device_node* np; + const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0, + KL_GPIO_RESET_CPU1, + KL_GPIO_RESET_CPU2, + KL_GPIO_RESET_CPU3 }; macio = &macio_chips[0]; if (macio->type != macio_keylargo) @@ -1062,14 +1131,14 @@ break; } } - if (np == NULL) - return -ENODEV; + if (np == NULL || reset_io == 0) + reset_io = dflt_reset_lines[param]; LOCK(flags); MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); (void)MACIO_IN8(reset_io); udelay(1); - MACIO_OUT8(reset_io, 0); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTOUT_DATA | KEYLARGO_GPIO_OUTPUT_ENABLE); (void)MACIO_IN8(reset_io); UNLOCK(flags); @@ -1087,15 +1156,19 @@ u32 reg; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; - + + /* XXX Fix handling of 3rd USB controller in Intrepid, move the + * port connect stuff (KL4_*) to the sleep code eventually + */ prop = (char *)get_property(node, "AAPL,clock-id", NULL); if (!prop) return -ENODEV; - if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0) + if (strncmp(prop, "usb0u048", 8) == 0) number = 0; - else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0) + else if (strncmp(prop, "usb1u148", 8) == 0) number = 2; else return -ENODEV; @@ -1166,7 +1239,8 @@ struct macio_chip* macio; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) return -ENODEV; @@ -1195,7 +1269,8 @@ if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0) return -ENODEV; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) return -ENODEV; @@ -1234,23 +1309,24 @@ } static void __pmac -keylargo_shutdown(struct macio_chip* macio, int restart) +keylargo_shutdown(struct macio_chip* macio, int sleep_mode) { u32 temp; - mdelay(1); - MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); - (void)MACIO_IN32(KEYLARGO_FCR0); - mdelay(100); + if (sleep_mode) { + mdelay(1); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(1); + } MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | KL0_SCC_CELL_ENABLE | KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE); - - (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); + MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); - (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); MACIO_BIC(KEYLARGO_FCR1, KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | @@ -1261,27 +1337,33 @@ KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N | KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N | KL1_UIDE_ENABLE); - (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); - udelay(10); MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE); - udelay(10); + temp = MACIO_IN32(KEYLARGO_FCR3); - if (macio->rev >= 2) - temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL); - + if (macio->rev >= 2) { + temp |= KL3_SHUTDOWN_PLL2X; + if (sleep_mode) + temp |= KL3_SHUTDOWN_PLL_TOTAL; + } + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | - KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12; + KL3_SHUTDOWN_PLLKW35; + if (sleep_mode) + temp |= KL3_SHUTDOWN_PLLKW12; temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE - | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE - | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + | KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); MACIO_OUT32(KEYLARGO_FCR3, temp); - (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); } static void __pmac -pangea_shutdown(struct macio_chip* macio, int restart) +pangea_shutdown(struct macio_chip* macio, int sleep_mode) { u32 temp; @@ -1289,10 +1371,6 @@ KL0_SCC_CELL_ENABLE | KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); - (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); - MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); - (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); - MACIO_BIC(KEYLARGO_FCR1, KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | @@ -1300,18 +1378,54 @@ KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | KL1_UIDE_ENABLE); - (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); + if (pmac_mb.board_flags & PMAC_MB_MOBILE) + MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N); MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); - udelay(10); + temp = MACIO_IN32(KEYLARGO_FCR3); temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | KL3_SHUTDOWN_PLLKW35; - temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE - | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE - | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE); MACIO_OUT32(KEYLARGO_FCR3, temp); - (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); +} + +static void __pmac +intrepid_shutdown(struct macio_chip* macio, int sleep_mode) +{ + u32 temp; + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); + + MACIO_BIC(KEYLARGO_FCR1, + KL1_USB2_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE); + if (pmac_mb.board_flags & PMAC_MB_MOBILE) + MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N); + + MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + + temp = MACIO_IN32(KEYLARGO_FCR3); + temp |= KL3_IT_SHUTDOWN_PLL1 | KL3_IT_SHUTDOWN_PLL2 | + KL3_IT_SHUTDOWN_PLL3; + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | + KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); } static int __pmac @@ -1321,7 +1435,8 @@ int i; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; /* We power off the wireless slot in case it was not done @@ -1337,7 +1452,11 @@ } /* We make sure int. modem is off (in case driver lost it) */ - core99_modem_enable(macio->of_node, 0, 0); + if (macio->type == macio_keylargo) + core99_modem_enable(macio->of_node, 0, 0); + else + pangea_modem_enable(macio->of_node, 0, 0); + /* We make sure the sound is off as well */ core99_sound_chip_enable(macio->of_node, 0, 0); @@ -1354,12 +1473,15 @@ save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i); /* Save the FCRs */ - save_mbcr = MACIO_IN32(KEYLARGO_MBCR); + if (macio->type == macio_keylargo) + save_mbcr = MACIO_IN32(KEYLARGO_MBCR); save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0); save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1); save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2); save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3); save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4); + if (macio->type == macio_pangea || macio->type == macio_intrepid) + save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5); /* Save state & config of DBDMA channels */ dbdma_save(macio, save_dbdma); @@ -1368,9 +1490,11 @@ * Turn off as much as we can */ if (macio->type == macio_pangea) - pangea_shutdown(macio, 0); + pangea_shutdown(macio, 1); + else if (macio->type == macio_intrepid) + intrepid_shutdown(macio, 1); else if (macio->type == macio_keylargo) - keylargo_shutdown(macio, 0); + keylargo_shutdown(macio, 1); /* * Put the host bridge to sleep @@ -1400,7 +1524,8 @@ int i; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; /* @@ -1414,9 +1539,11 @@ /* * Restore KeyLargo */ - - MACIO_OUT32(KEYLARGO_MBCR, save_mbcr); - (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + + if (macio->type == macio_keylargo) { + MACIO_OUT32(KEYLARGO_MBCR, save_mbcr); + (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + } MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]); (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]); @@ -1427,6 +1554,10 @@ (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]); (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10); + if (macio->type == macio_pangea || macio->type == macio_intrepid) { + MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]); + (void)MACIO_IN32(KEYLARGO_FCR5); udelay(10); + } dbdma_restore(macio, save_dbdma); @@ -1477,61 +1608,6 @@ } static int __pmac -pangea_modem_enable(struct device_node* node, int param, int value) -{ - struct macio_chip* macio; - u8 gpio; - unsigned long flags; - - /* Hack for internal USB modem */ - if (node == NULL) { - if (macio_chips[0].type != macio_pangea) - return -ENODEV; - node = macio_chips[0].of_node; - } - macio = macio_find(node, 0); - if (!macio) - return -ENODEV; - gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); - gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; - gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; - - if (!value) { - LOCK(flags); - MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); - UNLOCK(flags); - (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - mdelay(250); - } - LOCK(flags); - if (value) { - MACIO_OUT8(KL_GPIO_MODEM_POWER, - KEYLARGO_GPIO_OUTPUT_ENABLE); - UNLOCK(flags); - (void)MACIO_IN32(KEYLARGO_FCR2); - mdelay(250); - } else { - MACIO_OUT8(KL_GPIO_MODEM_POWER, - KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - UNLOCK(flags); - } - if (value) { - LOCK(flags); - MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); - (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); - MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); - (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); - MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); - (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); - } - return 0; -} - - -static int __pmac generic_get_mb_info(struct device_node* node, int param, int value) { switch(param) { @@ -1547,7 +1623,6 @@ return 0; } - /* * Table definitions */ @@ -1657,7 +1732,7 @@ { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, #ifdef CONFIG_SMP - { PMAC_FTR_RESET_CPU, rackmac_reset_cpu }, + { PMAC_FTR_RESET_CPU, core99_reset_cpu }, #endif /* CONFIG_SMP */ { PMAC_FTR_READ_GPIO, core99_read_gpio }, { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, @@ -1683,6 +1758,26 @@ { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, { 0, NULL } }; + +/* Intrepid features + */ +static struct feature_table_entry intrepid_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable }, + { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { /* Warning: ordering is important as some models may claim @@ -1714,11 +1809,11 @@ }, { "AAPL,3400/2400", "PowerBook 3400", PMAC_TYPE_HOOPER, ohare_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE }, { "AAPL,3500", "PowerBook 3500", PMAC_TYPE_KANGA, ohare_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE }, { "AAPL,Gossamer", "PowerMac G3 (Gossamer)", PMAC_TYPE_GOSSAMER, heathrow_desktop_features, @@ -1730,11 +1825,11 @@ }, { "AAPL,PowerBook1998", "PowerBook Wallstreet", PMAC_TYPE_WALLSTREET, heathrow_laptop_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE }, { "PowerBook1,1", "PowerBook 101 (Lombard)", PMAC_TYPE_101_PBOOK, paddington_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE }, { "iMac,1", "iMac (first generation)", PMAC_TYPE_ORIG_IMAC, paddington_features, @@ -1746,15 +1841,15 @@ }, { "PowerBook4,3", "iBook 2 rev. 2", PMAC_TYPE_IBOOK2, pangea_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "PowerBook4,2", "iBook 2", PMAC_TYPE_IBOOK2, pangea_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "PowerBook4,1", "iBook 2", PMAC_TYPE_IBOOK2, pangea_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "PowerMac4,4", "eMac", PMAC_TYPE_EMAC, core99_features, @@ -1774,7 +1869,7 @@ }, { "PowerBook2,1", "iBook (first generation)", PMAC_TYPE_ORIG_IBOOK, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 + PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE }, { "PowerMac3,1", "PowerMac G4 AGP Graphics", PMAC_TYPE_SAWTOOTH, core99_features, @@ -1798,7 +1893,7 @@ }, { "PowerBook2,2", "iBook FireWire", PMAC_TYPE_FW_IBOOK, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE }, { "PowerMac5,1", "PowerMac G4 Cube", PMAC_TYPE_CUBE, core99_features, @@ -1814,19 +1909,23 @@ }, { "PowerBook3,1", "PowerBook Pismo", PMAC_TYPE_PISMO, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE }, { "PowerBook3,2", "PowerBook Titanium", PMAC_TYPE_TITANIUM, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "PowerBook3,3", "PowerBook Titanium II", PMAC_TYPE_TITANIUM2, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "PowerBook3,4", "PowerBook Titanium III", PMAC_TYPE_TITANIUM3, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook3,5", "PowerBook Titanium IV", + PMAC_TYPE_TITANIUM4, core99_features, + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "RackMac1,1", "XServe", PMAC_TYPE_RACKMAC, rackmac_features, @@ -1836,6 +1935,10 @@ PMAC_TYPE_WINDTUNNEL, rackmac_features, 0, }, + { "PowerMac6,1", "PowerBook G4 12\"", + PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features, + PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE, + }, }; /* @@ -1931,6 +2034,11 @@ pmac_mb.model_name = "Unknown Pangea-based"; pmac_mb.features = pangea_features; break; + case macio_intrepid: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID; + pmac_mb.model_name = "Unknown Intrepid-based"; + pmac_mb.features = intrepid_features; + break; default: return -ENODEV; } @@ -1977,6 +2085,12 @@ * NAP mode */ powersave_lowspeed = 1; + + /* Check for "mobile" machine */ + if (model && (strncmp(model, "PowerBook", 9) == 0 + || strncmp(model, "iBook", 5) == 0)) + pmac_mb.board_flags |= PMAC_MB_MOBILE; + printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); return 0; @@ -2060,6 +2174,8 @@ u32* did = (u32 *)get_property(node, "device-id", NULL); if (*did == 0x00000025) type = macio_pangea; + if (*did == 0x0000003e) + type = macio_intrepid; } macio_chips[i].of_node = node; macio_chips[i].type = type; @@ -2154,7 +2270,8 @@ } if (macio_chips[0].type == macio_keylargo || - macio_chips[0].type == macio_pangea) { + macio_chips[0].type == macio_pangea || + macio_chips[0].type == macio_intrepid) { /* Enable GMAC for now for PCI probing. It will be disabled * later on after PCI probe */ @@ -2185,6 +2302,17 @@ np = np->next; } + /* Enable ATA-100 before PCI probe. */ + np = find_devices("ata-6"); + while(np) { + if (np->parent + && device_is_compatible(np->parent, "uni-north") + && device_is_compatible(np, "kauai-ata")) { + core99_ata100_enable(np, 1); + } + np = np->next; + } + /* Switch airport off */ np = find_devices("radio"); while(np) { diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_nvram.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_nvram.c --- linux-2.4.20/arch/ppc/platforms/pmac_nvram.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_nvram.c 2003-02-16 20:21:06.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh + * BK Id: SCCS/s.pmac_nvram.c 1.20 08/13/02 20:27:39 paulus */ /* * Miscellaneous procedures for dealing with the PowerMac hardware. diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_pci.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_pci.c --- linux-2.4.20/arch/ppc/platforms/pmac_pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_pci.c 2003-02-16 20:21:19.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.pmac_pci.c 1.38 08/13/02 20:27:39 paulus */ /* * Support for PCI bridges found on Power Macintoshes. diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_pic.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_pic.c --- linux-2.4.20/arch/ppc/platforms/pmac_pic.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_pic.c 2003-02-16 20:20:04.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_pic.c 1.24 12/19/01 10:53:01 paulus + * BK Id: SCCS/s.pmac_pic.c 1.27 08/13/02 20:27:39 paulus */ #include #include diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_pic.h linux-2.4.20-ben6/arch/ppc/platforms/pmac_pic.h --- linux-2.4.20/arch/ppc/platforms/pmac_pic.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_pic.h 2003-02-16 20:19:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.pmac_pic.h 1.12 08/13/02 20:27:39 paulus */ #ifndef __PPC_PLATFORMS_PMAC_PIC_H #define __PPC_PLATFORMS_PMAC_PIC_H diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_setup.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_setup.c --- linux-2.4.20/arch/ppc/platforms/pmac_setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_setup.c 2003-02-16 20:20:03.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.pmac_setup.c 1.66 10/04/02 15:02:22 benh */ /* * arch/ppc/platforms/setup.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -155,6 +156,14 @@ struct device_node *cpu_node; int *fp, s; +#ifdef CONFIG_CPU_FREQ_PMAC + extern unsigned int pmac_get_cur_cpufreq(void); + unsigned int freq = pmac_get_cur_cpufreq(); + if (freq != 0) { + seq_printf(m, "clock\t\t: %dMHz\n", freq/1000); + return 0; + } +#endif /* CONFIG_CPU_FREQ_PMAC */ cpu_node = find_type_devices("cpu"); if (!cpu_node) return 0; @@ -207,6 +216,18 @@ /* print parsed model */ seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); seq_printf(m, "pmac flags\t: %08x\n", mbflags); +#if 0 +{ + extern long nap_return_count; + extern long nap_enter_count; + extern long nap_save_msscr0; + extern long dbg_nap_ret; + seq_printf(m, "nap_return_count: %d\n", nap_return_count); + seq_printf(m, "nap_enter_count\t: %d\n", nap_enter_count); + seq_printf(m, "nap_save_msscr0\t: %x\n", nap_save_msscr0); + seq_printf(m, "dbg_nap_ret\t: %x\n", dbg_nap_ret); +} +#endif /* find l2 cache info */ np = find_devices("l2-cache"); @@ -313,6 +334,14 @@ sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); ohare_init(); + /* Check & display some CPU config registers for diagnostic */ + if (pvr == 0x8000 || pvr == 0x8001) { /* 745x */ + printk(KERN_INFO "CPU MSCCR0 : 0x%08x\n", mfspr(SPRN_MSSCR0)); + printk(KERN_INFO "CPU HID1 : 0x%08x\n", mfspr(SPRN_HID1)); + } + if (pvr == 0x0008 || pvr == 0x7000) /* 750's */ + printk(KERN_INFO "CPU HID1 : 0x%08x\n", mfspr(SPRN_HID1)); + /* Lookup PCI hosts */ pmac_find_bridges(); @@ -333,6 +362,9 @@ } } +#if 0 + printk("MSSCR0: %x\n", mfspr(SPRN_MSSCR0)); +#endif if (ppc_override_l2cr) printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_sleep.S linux-2.4.20-ben6/arch/ppc/platforms/pmac_sleep.S --- linux-2.4.20/arch/ppc/platforms/pmac_sleep.S 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_sleep.S 2003-02-16 20:19:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.pmac_sleep.S 1.33 10/20/02 20:14:45 benh */ /* * This file contains sleep low-level functions for PowerBook G3. @@ -55,7 +55,7 @@ .text .align 5 -#if defined(CONFIG_PMAC_PBOOK) +#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC) /* This gets called by via-pmu.c late during the sleep process. * The PMU was already send the sleep command and will shut us down @@ -477,7 +477,60 @@ isync rfi -#endif /* defined(CONFIG_PMAC_PBOOK) */ +#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */ + +#ifdef CONFIG_CPU_FREQ_PMAC + +/* This gets called by via-pmu.c to switch the PLL selection + * on 750fx CPU. This function should really be moved to some + * other place (as most of the cpufreq code in via-pmu + */ +_GLOBAL(low_choose_750fx_pll) + /* Clear MSR:EE */ + mfmsr r7 + rlwinm r0,r7,0,17,15 + mtmsr r0 + + /* If switching to PLL1, disable HID0:BTIC */ + cmpli cr0,r3,0 + beq 1f + mfspr r5,HID0 + rlwinm r5,r5,0,27,25 + sync + mtspr HID0,r5 + isync + sync + +1: + /* Calc new HID1 value */ + mfspr r4,SPRN_HID1 /* Build a HID1:PS bit from parameter */ + rlwinm r5,r3,16,15,15 /* Clear out HID1:PS from value read */ + rlwinm r4,r4,0,16,14 /* Could have I used rlwimi here ? */ + or r4,r4,r5 + mtspr SPRN_HID1,r4 + + /* Store new HID1 image */ + lwz r6,PROCESSOR(r2) + slwi r6,r6,2 + addis r6,r6,nap_save_hid1@ha + stw r4,nap_save_hid1@l(r6) + + /* If switching to PLL0, enable HID0:BTIC */ + cmpli cr0,r3,0 + bne 1f + mfspr r5,HID0 + ori r5,r5,HID0_BTIC + sync + mtspr HID0,r5 + isync + sync + +1: + /* Return */ + mtmsr r7 + blr + +#endif /* CONFIG_CPU_FREQ_PMAC */ .data .globl sleep_storage diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_smp.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_smp.c --- linux-2.4.20/arch/ppc/platforms/pmac_smp.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_smp.c 2003-02-16 20:21:47.000000000 +0100 @@ -6,6 +6,12 @@ * * We support both the old "powersurge" SMP architecture * and the current Core99 (G4 PowerMac) machines. + * + * Note that we don't support the very first rev. of + * Apple/DayStar 2 CPUs board, the one with the funky + * watchdog. Hopefully, none of these should be there except + * maybe internally to Apple. I should probably still add some + * code to detect this card though and disable SMP. --BenH. * * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net) * and Ben Herrenschmidt . @@ -154,26 +160,21 @@ #define reg_ldstdb 6 #define reg_count 7 -#define stringify __stringify - static unsigned long cpu_regs[reg_count]; static void __pmac cpu_setup_grab(void) { - unsigned int pvers = mfspr(SPRN_PVR)>>16; - - /* Read cache setting of CPU 0 */ - core99_init_caches(); + const unsigned int pvers = mfspr(SPRN_PVR)>>16; - /* 7400/7410/7450 */ - if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) { + /* 7400/7410/7450/7455 */ + if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c || pvers == 0x8001) { cpu_regs[reg_hid0] = mfspr(SPRN_HID0); cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0); cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0); } - /* 7450 only */ - if (pvers == 0x8000) { + /* 745x only */ + if (pvers == 0x8000 || pvers == 0x8001) { cpu_regs[reg_hid1] = mfspr(SPRN_HID1); cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL); cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR); @@ -185,15 +186,14 @@ static void __pmac cpu_setup_apply(int cpu_nr) { - unsigned int pvers = mfspr(SPRN_PVR)>>16; + const unsigned int pvers = mfspr(SPRN_PVR)>>16; - /* Apply cache setting from CPU 0 */ - core99_init_caches(); - - /* 7400/7410/7450 */ - if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) { + /* 7400/7410/7450/7455 */ + if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c || pvers == 0x8001) { unsigned long tmp; __asm__ __volatile__ ( + "li %0,0\n" + "mtspr "stringify(SPRN_L2CR)", %0\n" "lwz %0,4*"stringify(reg_hid0)"(%1)\n" "sync\n" "mtspr "stringify(SPRN_HID0)", %0\n" @@ -202,12 +202,18 @@ "sync\n" "mtspr "stringify(SPRN_MSSCR0)", %0\n" "isync;sync\n" -// "lwz %0, "stringify(reg_msssr0)"(%1)\n" -// "sync\n" -// "mtspr "stringify(SPRN_MSSSR0)", %0\n" -// "isync;sync\n" : "=&r" (tmp) : "r" (cpu_regs)); } + /* 7400/7410 only */ + if (pvers == 0x000c || pvers == 0x800c) { + unsigned long tmp; + __asm__ __volatile__ ( + "lwz %0, 4*"stringify(reg_msssr0)"(%1)\n" + "isync;sync\n" + "mtspr "stringify(SPRN_MSSSR0)", %0\n" + "isync;sync\n" + : "=&r" (tmp) : "r" (cpu_regs)); + } /* 7410 only */ if (pvers == 0x800c) { unsigned long tmp; @@ -218,8 +224,8 @@ "isync;sync\n" : "=&r" (tmp)); } - /* 7450 only */ - if (pvers == 0x8000) { + /* 745x only */ + if (pvers == 0x8000 || pvers == 0x8001) { unsigned long tmp; __asm__ __volatile__ ( "lwz %0, 4*"stringify(reg_hid1)"(%1)\n" @@ -531,6 +537,8 @@ smp_hw_index[i] = i; powersave_nap = 0; cpu_setup_grab(); + /* Read cache setting of CPU 0 */ + core99_init_caches(); } return ncpus; @@ -592,12 +600,19 @@ } static void __init +smp_core99_init_cpu(int cpu_nr) +{ + /* Setup some critical registers */ + cpu_setup_apply(cpu_nr); +} + +static void __init smp_core99_setup_cpu(int cpu_nr) { - /* Setup some registers */ + /* Apply cache setting from CPU 0 */ if (cpu_nr != 0) - cpu_setup_apply(cpu_nr); - + core99_init_caches(); + /* Setup openpic */ do_openpic_setup_cpu(); @@ -608,16 +623,17 @@ /* PowerSurge-style Macs */ struct smp_ops_t psurge_smp_ops __pmacdata = { - smp_psurge_message_pass, - smp_psurge_probe, - smp_psurge_kick_cpu, - smp_psurge_setup_cpu, + .message_pass = smp_psurge_message_pass, + .probe = smp_psurge_probe, + .kick_cpu = smp_psurge_kick_cpu, + .setup_cpu = smp_psurge_setup_cpu, }; /* Core99 Macs (dual G4s) */ struct smp_ops_t core99_smp_ops __pmacdata = { - smp_openpic_message_pass, - smp_core99_probe, - smp_core99_kick_cpu, - smp_core99_setup_cpu, + .message_pass = smp_openpic_message_pass, + .probe = smp_core99_probe, + .kick_cpu = smp_core99_kick_cpu, + .setup_cpu = smp_core99_setup_cpu, + .init_cpu = smp_core99_init_cpu, }; diff -uNr linux-2.4.20/arch/ppc/platforms/pmac_time.c linux-2.4.20-ben6/arch/ppc/platforms/pmac_time.c --- linux-2.4.20/arch/ppc/platforms/pmac_time.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/pmac_time.c 2003-02-16 20:21:43.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.pmac_time.c 1.27 10/20/02 20:14:45 benh */ /* * Support for periodic interrupts (100 per second) and for getting @@ -206,7 +206,7 @@ printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", tb_ticks_per_jiffy, dstart - dend); - iounmap(via); + iounmap((void*)via); return 1; } diff -uNr linux-2.4.20/arch/ppc/platforms/prep_pci.c linux-2.4.20-ben6/arch/ppc/platforms/prep_pci.c --- linux-2.4.20/arch/ppc/platforms/prep_pci.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/prep_pci.c 2003-02-16 20:21:16.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prep_pci.c 1.33 12/20/01 15:36:12 trini + * BK Id: SCCS/s.prep_pci.c 1.36 08/13/02 20:27:39 paulus */ /* * PReP pci functions. diff -uNr linux-2.4.20/arch/ppc/platforms/prep_setup.c linux-2.4.20-ben6/arch/ppc/platforms/prep_setup.c --- linux-2.4.20/arch/ppc/platforms/prep_setup.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/prep_setup.c 2003-02-16 20:20:24.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.prep_setup.c 1.59 11/07/02 11:46:58 trini */ /* * linux/arch/ppc/kernel/setup.c @@ -59,6 +59,7 @@ #include #include #include +#include #if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) #include <../drivers/sound/sound_config.h> @@ -621,12 +622,24 @@ prep_init_IRQ(void) { int i; + unsigned int pci_viddid, pci_did; if (OpenPIC_Addr != NULL) openpic_init(1, NUM_8259_INTERRUPTS, 0, -1); for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) irq_desc[i].handler = &i8259_pic; - i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */ + /* If we are on an MPC10x, we want to use the int-ack, + * otherwise we poll. */ + early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &pci_viddid); + pci_did = (pci_viddid & 0xffff0000) >> 16; + if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA) + && ((pci_did == PCI_DEVICE_ID_MOTOROLA_MPC105) + || (pci_did == PCI_DEVICE_ID_MOTOROLA_MPC106) + || (pci_did == PCI_DEVICE_ID_MOTOROLA_MPC107))) + /* PCI interrupt ack address for MPC105 and 106 */ + i8259_init(0xbffffff0); + else + i8259_init(0); } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -uNr linux-2.4.20/arch/ppc/platforms/prep_time.c linux-2.4.20-ben6/arch/ppc/platforms/prep_time.c --- linux-2.4.20/arch/ppc/platforms/prep_time.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/prep_time.c 2003-02-16 20:21:38.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.prep_time.c 1.13 08/13/02 20:27:40 paulus */ /* * arch/ppc/platforms/prep_time.c diff -uNr linux-2.4.20/arch/ppc/platforms/proc_rtas.c linux-2.4.20-ben6/arch/ppc/platforms/proc_rtas.c --- linux-2.4.20/arch/ppc/platforms/proc_rtas.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/proc_rtas.c 2003-02-16 20:21:05.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort + * BK Id: SCCS/s.proc_rtas.c 1.6 08/13/02 21:32:03 paulus */ /* * arch/ppc/kernel/proc_rtas.c diff -uNr linux-2.4.20/arch/ppc/platforms/residual.c linux-2.4.20-ben6/arch/ppc/platforms/residual.c --- linux-2.4.20/arch/ppc/platforms/residual.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/residual.c 2003-02-16 20:21:46.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini + * BK Id: SCCS/s.residual.c 1.18 08/13/02 20:27:40 paulus */ /* * Code to deal with the PReP residual data. diff -uNr linux-2.4.20/arch/ppc/platforms/rpxclassic.h linux-2.4.20-ben6/arch/ppc/platforms/rpxclassic.h --- linux-2.4.20/arch/ppc/platforms/rpxclassic.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/rpxclassic.h 2003-02-16 20:21:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.rpxclassic.h 1.14 08/13/02 20:27:40 paulus */ /* diff -uNr linux-2.4.20/arch/ppc/platforms/rpxhiox.h linux-2.4.20-ben6/arch/ppc/platforms/rpxhiox.h --- linux-2.4.20/arch/ppc/platforms/rpxhiox.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/rpxhiox.h 2003-02-16 20:21:14.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort + * BK Id: SCCS/s.rpxhiox.h 1.4 08/13/02 21:33:06 paulus */ /* diff -uNr linux-2.4.20/arch/ppc/platforms/rpxlite.h linux-2.4.20-ben6/arch/ppc/platforms/rpxlite.h --- linux-2.4.20/arch/ppc/platforms/rpxlite.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/rpxlite.h 2003-02-16 20:21:17.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.rpxlite.h 1.14 08/13/02 20:27:41 paulus */ /* diff -uNr linux-2.4.20/arch/ppc/platforms/spd8xx.h linux-2.4.20-ben6/arch/ppc/platforms/spd8xx.h --- linux-2.4.20/arch/ppc/platforms/spd8xx.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/spd8xx.h 2003-02-16 20:20:13.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini + * BK Id: SCCS/s.spd8xx.h 1.9 08/13/02 21:33:06 paulus */ /* * Speech Design SPD8xxTS board specific definitions diff -uNr linux-2.4.20/arch/ppc/platforms/tqm8xx.h linux-2.4.20-ben6/arch/ppc/platforms/tqm8xx.h --- linux-2.4.20/arch/ppc/platforms/tqm8xx.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/tqm8xx.h 2003-02-16 20:21:11.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini + * BK Id: SCCS/s.tqm8xx.h 1.9 08/13/02 21:33:06 paulus */ /* * TQM8xx(L) board specific definitions diff -uNr linux-2.4.20/arch/ppc/platforms/walnut.c linux-2.4.20-ben6/arch/ppc/platforms/walnut.c --- linux-2.4.20/arch/ppc/platforms/walnut.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/walnut.c 2003-02-16 20:20:14.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.walnut_setup.c 1.10 11/13/01 21:26:07 paulus + * BK Id: SCCS/s.walnut.c 1.13 08/13/02 20:27:41 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/platforms/walnut.h linux-2.4.20-ben6/arch/ppc/platforms/walnut.h --- linux-2.4.20/arch/ppc/platforms/walnut.h 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/platforms/walnut.h 2003-02-16 20:21:20.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort + * BK Id: SCCS/s.walnut.h 1.9 08/13/02 20:27:41 paulus */ /* * diff -uNr linux-2.4.20/arch/ppc/xmon/Makefile linux-2.4.20-ben6/arch/ppc/xmon/Makefile --- linux-2.4.20/arch/ppc/xmon/Makefile 2001-07-02 23:34:57.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/Makefile 2003-02-16 20:21:04.000000000 +0100 @@ -1,9 +1,11 @@ -# BK Id: SCCS/s.Makefile 1.6 06/27/01 14:49:58 trini +# BK Id: SCCS/s.Makefile 1.8 06/25/02 16:33:15 trini # # Makefile for xmon O_TARGET := x.o +CFLAGS_xmon.o += -I$(TOPDIR)/arch/$(ARCH)/mm + ifdef CONFIG_8xx obj-y := start_8xx.o else diff -uNr linux-2.4.20/arch/ppc/xmon/adb.c linux-2.4.20-ben6/arch/ppc/xmon/adb.c --- linux-2.4.20/arch/ppc/xmon/adb.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/adb.c 2003-02-16 20:21:52.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.adb.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.adb.c 1.7 06/05/01 21:22:06 paulus */ /* * Copyright (C) 1996 Paul Mackerras. diff -uNr linux-2.4.20/arch/ppc/xmon/ansidecl.h linux-2.4.20-ben6/arch/ppc/xmon/ansidecl.h --- linux-2.4.20/arch/ppc/xmon/ansidecl.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/ansidecl.h 2003-02-16 20:20:25.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ansidecl.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.ansidecl.h 1.7 06/05/01 21:22:06 paulus */ /* ANSI and traditional C compatability macros Copyright 1991, 1992 Free Software Foundation, Inc. diff -uNr linux-2.4.20/arch/ppc/xmon/nonstdio.h linux-2.4.20-ben6/arch/ppc/xmon/nonstdio.h --- linux-2.4.20/arch/ppc/xmon/nonstdio.h 2002-02-25 20:37:55.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/xmon/nonstdio.h 2003-02-16 20:19:52.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.nonstdio.h 1.8 12/01/01 20:09:07 benh + * BK Id: SCCS/s.nonstdio.h 1.9 12/27/01 10:08:51 trini */ typedef int FILE; extern FILE *xmon_stdin, *xmon_stdout; diff -uNr linux-2.4.20/arch/ppc/xmon/ppc-dis.c linux-2.4.20-ben6/arch/ppc/xmon/ppc-dis.c --- linux-2.4.20/arch/ppc/xmon/ppc-dis.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/ppc-dis.c 2003-02-16 20:21:27.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc-dis.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.ppc-dis.c 1.7 06/05/01 21:22:06 paulus */ /* ppc-dis.c -- Disassemble PowerPC instructions Copyright 1994 Free Software Foundation, Inc. diff -uNr linux-2.4.20/arch/ppc/xmon/ppc-opc.c linux-2.4.20-ben6/arch/ppc/xmon/ppc-opc.c --- linux-2.4.20/arch/ppc/xmon/ppc-opc.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/ppc-opc.c 2003-02-16 20:20:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc-opc.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.ppc-opc.c 1.7 06/05/01 21:22:06 paulus */ /* ppc-opc.c -- PowerPC opcode list Copyright 1994 Free Software Foundation, Inc. diff -uNr linux-2.4.20/arch/ppc/xmon/ppc.h linux-2.4.20-ben6/arch/ppc/xmon/ppc.h --- linux-2.4.20/arch/ppc/xmon/ppc.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/ppc.h 2003-02-16 20:21:06.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.ppc.h 1.7 06/05/01 21:22:06 paulus */ /* ppc.h -- Header file for PowerPC opcode table Copyright 1994 Free Software Foundation, Inc. diff -uNr linux-2.4.20/arch/ppc/xmon/privinst.h linux-2.4.20-ben6/arch/ppc/xmon/privinst.h --- linux-2.4.20/arch/ppc/xmon/privinst.h 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/privinst.h 2003-02-16 20:21:11.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.privinst.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.privinst.h 1.7 06/05/01 21:22:06 paulus */ /* * Copyright (C) 1996 Paul Mackerras. diff -uNr linux-2.4.20/arch/ppc/xmon/setjmp.c linux-2.4.20-ben6/arch/ppc/xmon/setjmp.c --- linux-2.4.20/arch/ppc/xmon/setjmp.c 2001-05-22 02:04:47.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/setjmp.c 2003-02-16 20:20:35.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.setjmp.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.setjmp.c 1.7 06/05/01 21:22:06 paulus */ /* * Copyright (C) 1996 Paul Mackerras. diff -uNr linux-2.4.20/arch/ppc/xmon/start.c linux-2.4.20-ben6/arch/ppc/xmon/start.c --- linux-2.4.20/arch/ppc/xmon/start.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/start.c 2003-02-16 20:20:04.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.start.c 1.20 04/09/02 21:01:58 paulus + * BK Id: SCCS/s.start.c 1.24 05/21/02 16:23:20 benh */ /* * Copyright (C) 1996 Paul Mackerras. @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -25,10 +26,13 @@ #include #endif +#define CONFIG_XMON_FW + static volatile unsigned char *sccc, *sccd; unsigned long TXRDY, RXRDY; extern void xmon_printf(const char *fmt, ...); static int xmon_expect(const char *str, unsigned int timeout); +extern char cmd_line[512]; static int console; static int use_screen; @@ -36,6 +40,21 @@ static int xmon_use_sccb; static struct device_node *channel_node; +/* There are used when hooked via firewire */ +#ifdef CONFIG_XMON_FW +volatile unsigned int xmon_fw_outbuf_size; +volatile unsigned char xmon_fw_outbuf[1024]; +volatile unsigned int xmon_fw_oflags; +volatile unsigned int xmon_fw_iflags; +volatile unsigned int xmon_fw_idata; +#define XMON_FW_FLAGS_OUT_ENTERED 0x00000001 +#define XMON_FW_FLAGS_OUT_DATA 0x00000002 +#define XMON_FW_FLAGS_OUT_ACK 0x00000004 +#define XMON_FW_FLAGS_IN_ATTACHED 0x00000001 +#define XMON_FW_FLAGS_IN_DATA 0x00000002 +#define XMON_FW_FLAGS_IN_ACK 0x00000004 +#endif + #define TB_SPEED 25000000 static inline unsigned int readtb(void) @@ -61,7 +80,9 @@ volatile unsigned char *base; use_screen = 0; - + /* Typically used for firewire debugging */ + if (strstr(cmd_line, "xmon_noio")) + return; if (_machine == _MACH_Pmac) { struct device_node *np; unsigned long addr; @@ -173,6 +194,114 @@ #endif /* CONFIG_ADB_CUDA */ } +#if 0 +static void +bx_printf(const char* fmt, ...) +{ + static char dbgbuf[2048]; + va_list ap; + int n; + + va_start(ap, fmt); + n = vsprintf(dbgbuf, fmt, ap); + va_end(ap); + btext_drawstring(dbgbuf); +} +#endif + +#ifdef CONFIG_XMON_FW +static int +xmon_fw_write(void* ptr, int nb) +{ + char* p = (char *)ptr; + int c, i; + + while (nb && (xmon_fw_iflags & XMON_FW_FLAGS_IN_ATTACHED)) { + c = (nb > 1024) ? 1024 : nb; + memcpy((void *)xmon_fw_outbuf, p, c); + xmon_fw_outbuf_size = c; + wmb(); + xmon_fw_oflags |= XMON_FW_FLAGS_OUT_DATA; + wmb(); + for (i=0; i<1000; i++) { + rmb(); + if (xmon_fw_iflags & XMON_FW_FLAGS_IN_ACK) + break; + mdelay(1); + } + xmon_fw_oflags &= ~XMON_FW_FLAGS_OUT_DATA; + wmb(); + if ((xmon_fw_iflags & XMON_FW_FLAGS_IN_ACK) == 0) { + xmon_fw_iflags = 0; + break; + } + for (i=0; i<1000; i++) { + rmb(); + if ((xmon_fw_iflags & XMON_FW_FLAGS_IN_ACK) == 0) + break; + mdelay(1); + } + if ((xmon_fw_iflags & XMON_FW_FLAGS_IN_ACK) != 0) { + xmon_fw_iflags = 0; + break; + } + nb -= c; + p += c; + } + return (xmon_fw_iflags & XMON_FW_FLAGS_IN_ATTACHED) != 0; +} + +static int +xmon_fw_read(void* ptr, int nb) +{ + int t, on, i; + unsigned int k; + char c[3]; + char* p = (char *)ptr; + + while (nb) { + t = 0; + on = 0; + while(xmon_fw_iflags & XMON_FW_FLAGS_IN_ATTACHED) { + if (xmon_fw_iflags & XMON_FW_FLAGS_IN_DATA) + break; + if (--t < 0) { + on = 1 - on; + c[0] = on? 0xdb: 0x20; + c[1] = '\b'; + if (!xmon_fw_write(c, 2)) + break; + t = 2000000; + } + rmb(); + } + k = xmon_fw_idata & 0xff; + xmon_fw_oflags |= XMON_FW_FLAGS_OUT_ACK; + wmb(); + for (i=0; i<1000; i++) { + rmb(); + if ((xmon_fw_iflags & XMON_FW_FLAGS_IN_DATA) == 0) + break; + mdelay(1); + } + if (xmon_fw_iflags & XMON_FW_FLAGS_IN_DATA) { + xmon_fw_iflags = 0; + break; + } + xmon_fw_oflags &= ~XMON_FW_FLAGS_OUT_ACK; + wmb(); + if (on) { + c[0] = 0x20; c[1] = '\b'; + xmon_fw_write(c, 2); + } + *(p++) = k; + nb--; + } + return (xmon_fw_iflags & XMON_FW_FLAGS_IN_ATTACHED) != 0; +} + +#endif /* CONFIG_XMON_FW */ + int xmon_write(void *handle, void *ptr, int nb) { @@ -188,9 +317,17 @@ if (--lock_wait == 0) break; #endif - +#ifdef CONFIG_XMON_FW + if (xmon_fw_write(ptr, nb)) + goto out; +#endif /* CONFIG_XMON_FW */ #ifdef CONFIG_BOOTX_TEXT - if (use_screen) { +#ifdef CONFIG_MORE_DEBUG + if (1) +#else + if (use_screen) +#endif + { /* write it on the screen */ for (i = 0; i < nb; ++i) btext_drawchar(*p++); @@ -199,6 +336,9 @@ #endif if (!scc_initialized) xmon_init_scc(); + if (!sccd) + goto out; + ct = 0; for (i = 0; i < nb; ++i) { while ((*sccc & TXRDY) == 0) @@ -293,6 +433,10 @@ char *p = ptr; int i; +#ifdef CONFIG_XMON_FW + if (xmon_fw_read(ptr, nb)) + return nb; +#endif /* CONFIG_XMON_FW */ #ifdef CONFIG_BOOTX_TEXT if (use_screen) { for (i = 0; i < nb; ++i) @@ -302,6 +446,8 @@ #endif if (!scc_initialized) xmon_init_scc(); + if (sccd == NULL) + return 0; for (i = 0; i < nb; ++i) { while ((*sccc & RXRDY) == 0) do_poll_adb(); @@ -324,7 +470,8 @@ static unsigned char scc_inittab[] = { 13, 0, /* set baud rate divisor */ - 12, 1, +// 12, 1, + 12, 0, 14, 1, /* baud rate gen enable, src=rtxc */ 11, 0x50, /* clocks = br gen */ 5, 0xea, /* tx 8 bits, assert DTR & RTS */ @@ -335,6 +482,8 @@ void xmon_init_scc() { + if (sccd == NULL && channel_node == NULL) + return; if ( _machine == _MACH_chrp ) { sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ @@ -573,11 +722,19 @@ pmu_suspend(); } #endif +#ifdef CONFIG_XMON_FW + xmon_fw_oflags |= XMON_FW_FLAGS_OUT_ENTERED; + wmb(); +#endif /* CONFIG_XMON_FW */ } void xmon_leave(void) { +#ifdef CONFIG_XMON_FW + xmon_fw_oflags &= ~XMON_FW_FLAGS_OUT_ENTERED; + wmb(); +#endif /* CONFIG_XMON_FW */ #ifdef CONFIG_ADB_PMU if (_machine == _MACH_Pmac) { pmu_resume(); diff -uNr linux-2.4.20/arch/ppc/xmon/start_8xx.c linux-2.4.20-ben6/arch/ppc/xmon/start_8xx.c --- linux-2.4.20/arch/ppc/xmon/start_8xx.c 2001-10-08 20:40:13.000000000 +0200 +++ linux-2.4.20-ben6/arch/ppc/xmon/start_8xx.c 2003-02-16 20:21:36.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.start_8xx.c 1.10 09/14/01 18:01:17 trini + * BK Id: SCCS/s.start_8xx.c 1.11 10/08/01 16:49:27 trini */ /* * Copyright (C) 1996 Paul Mackerras. diff -uNr linux-2.4.20/arch/ppc/xmon/subr_prf.c linux-2.4.20-ben6/arch/ppc/xmon/subr_prf.c --- linux-2.4.20/arch/ppc/xmon/subr_prf.c 2002-02-25 20:37:55.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/xmon/subr_prf.c 2003-02-16 20:19:51.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.subr_prf.c 1.8 12/01/01 20:09:07 benh + * BK Id: SCCS/s.subr_prf.c 1.9 12/27/01 10:08:51 trini */ /* * Written by Cort Dougan to replace the version originally used diff -uNr linux-2.4.20/arch/ppc/xmon/xmon.c linux-2.4.20-ben6/arch/ppc/xmon/xmon.c --- linux-2.4.20/arch/ppc/xmon/xmon.c 2002-02-25 20:37:55.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc/xmon/xmon.c 2003-02-16 20:19:52.000000000 +0100 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.xmon.c 1.18 12/01/01 20:09:07 benh + * BK Id: SCCS/s.xmon.c 1.24 11/07/02 18:38:50 benh */ /* * Routines providing a simple monitor for use on the PowerMac. @@ -14,6 +14,10 @@ #include #include #include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif +#include "mmu_decl.h" #include "nonstdio.h" #include "privinst.h" @@ -203,6 +207,18 @@ */ #endif /* CONFIG_SMP */ remove_bpts(); +#ifdef CONFIG_PMAC_BACKLIGHT + if (_machine == _MACH_Pmac) { + if( setjmp(bus_error_jmp) == 0 ) { + debugger_fault_handler = handle_fault; + sync(); + set_backlight_enable(1); + set_backlight_level(BACKLIGHT_MAX); + sync(); + } + debugger_fault_handler = 0; + } +#endif /* CONFIG_PMAC_BACKLIGHT */ cmd = cmds(excp); if (cmd == 's') { xmon_trace[smp_processor_id()] = SSTEP; @@ -925,7 +941,6 @@ static void dump_hash_table_seg(unsigned seg, unsigned start, unsigned end) { - extern void *Hash; extern unsigned long Hash_size; unsigned *htab = Hash; unsigned hsize = Hash_size; @@ -984,7 +999,6 @@ static void dump_hash_table_seg(unsigned seg, unsigned start, unsigned end) { - extern void *Hash; extern unsigned long Hash_size; unsigned *htab = Hash; unsigned hsize = Hash_size; @@ -1050,6 +1064,8 @@ int seg; unsigned seg_start, seg_end; + if (Hash == NULL) + return; hash_ctx = 0; hash_start = 0; hash_end = 0xfffff000; diff -uNr linux-2.4.20/arch/ppc64/config.in linux-2.4.20-ben6/arch/ppc64/config.in --- linux-2.4.20/arch/ppc64/config.in 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/ppc64/config.in 2003-02-16 20:20:08.000000000 +0100 @@ -8,6 +8,7 @@ define_bool CONFIG_GENERIC_BUST_SPINLOCK n define_bool CONFIG_GENERIC_ISA_DMA y define_bool CONFIG_HAVE_DEC_LOCK y +define_bool CONFIG_PPC_ISATIMER y mainmenu_name "64 bit PowerPC Linux Kernel Configuration" diff -uNr linux-2.4.20/arch/s390/mm/fault.c linux-2.4.20-ben6/arch/s390/mm/fault.c --- linux-2.4.20/arch/s390/mm/fault.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/s390/mm/fault.c 2003-02-16 20:20:12.000000000 +0100 @@ -210,7 +210,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -uNr linux-2.4.20/arch/s390x/mm/fault.c linux-2.4.20-ben6/arch/s390x/mm/fault.c --- linux-2.4.20/arch/s390x/mm/fault.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/s390x/mm/fault.c 2003-02-16 20:19:53.000000000 +0100 @@ -210,7 +210,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -uNr linux-2.4.20/arch/sh/mm/fault.c linux-2.4.20-ben6/arch/sh/mm/fault.c --- linux-2.4.20/arch/sh/mm/fault.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.20-ben6/arch/sh/mm/fault.c 2003-02-16 20:21:31.000000000 +0100 @@ -74,7 +74,7 @@ check_stack: if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, start) == 0) + if (expand_stack(vma, start, NULL) == 0) goto good_area; bad_area: @@ -114,7 +114,7 @@ goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -uNr linux-2.4.20/arch/sparc/mm/fault.c linux-2.4.20-ben6/arch/sparc/mm/fault.c --- linux-2.4.20/arch/sparc/mm/fault.c 2001-12-21 18:41:53.000000000 +0100 +++ linux-2.4.20-ben6/arch/sparc/mm/fault.c 2003-02-16 20:20:38.000000000 +0100 @@ -251,7 +251,7 @@ goto good_area; if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if(expand_stack(vma, address)) + if(expand_stack(vma, address, NULL)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so @@ -498,7 +498,7 @@ goto good_area; if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if(expand_stack(vma, address)) + if(expand_stack(vma, address, NULL)) goto bad_area; good_area: info.si_code = SEGV_ACCERR; diff -uNr linux-2.4.20/arch/sparc64/mm/fault.c linux-2.4.20-ben6/arch/sparc64/mm/fault.c --- linux-2.4.20/arch/sparc64/mm/fault.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/arch/sparc64/mm/fault.c 2003-02-16 20:21:15.000000000 +0100 @@ -389,7 +389,7 @@ goto bad_area; } } - if (expand_stack(vma, address)) + if (expand_stack(vma, address, NULL)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so diff -uNr linux-2.4.20/drivers/char/Config.in linux-2.4.20-ben6/drivers/char/Config.in --- linux-2.4.20/drivers/char/Config.in 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/Config.in 2003-02-16 20:19:51.000000000 +0100 @@ -152,6 +152,9 @@ if [ "$CONFIG_PPC64" ] ; then bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE fi +if [ "$CONFIG_ALL_PPC" = "y" ]; then + tristate 'Total Impact briQ front panel driver' CONFIG_BRIQ_PANEL +fi source drivers/i2c/Config.in @@ -291,6 +294,7 @@ if [ "$CONFIG_IA64" = "y" ]; then bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 fi + dep_bool ' Apple UniNorth support' CONFIG_AGP_UNINORTH $CONFIG_ALL_PPC fi bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM diff -uNr linux-2.4.20/drivers/char/Makefile linux-2.4.20-ben6/drivers/char/Makefile --- linux-2.4.20/drivers/char/Makefile 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/Makefile 2003-02-16 20:21:21.000000000 +0100 @@ -232,6 +232,7 @@ obj-$(CONFIG_INTEL_RNG) += i810_rng.o obj-$(CONFIG_AMD_RNG) += amd768_rng.o obj-$(CONFIG_AMD_PM768) += amd76x_pm.o +obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o obj-$(CONFIG_ITE_GPIO) += ite_gpio.o obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o diff -uNr linux-2.4.20/drivers/char/agp/agpgart_be.c linux-2.4.20-ben6/drivers/char/agp/agpgart_be.c --- linux-2.4.20/drivers/char/agp/agpgart_be.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/agp/agpgart_be.c 2003-02-16 20:20:22.000000000 +0100 @@ -44,6 +44,10 @@ #include #include +#ifdef CONFIG_AGP_UNINORTH +#include +#endif + #include #include "agp.h" @@ -71,7 +75,7 @@ { #if defined(__i386__) || defined(__x86_64__) asm volatile ("wbinvd":::"memory"); -#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__) +#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__) || defined(__powerpc__) /* ??? I wonder if we'll really need to flush caches, or if the core logic can manage to keep the system coherent. The ARM speaks only of using `cflush' to get things in memory in @@ -4391,6 +4395,437 @@ #endif /* CONFIG_AGP_HP_ZX1 */ +#ifdef CONFIG_AGP_UNINORTH + +static int uninorth_fetch_size(void) +{ + int i; + u32 temp; + aper_size_info_32 *values; + + pci_read_config_dword(agp_bridge.dev, UNI_N_CFG_GART_BASE, &temp); + temp &= ~(0xfffff000); + values = A_SIZE_32(agp_bridge.aperture_sizes); + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + 1); + agp_bridge.aperture_size_idx = 1; + return values[1].size; + + return 0; +} + +static void uninorth_tlbflush(agp_memory * mem) +{ + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, + UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL); + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, + UNI_N_CFG_GART_ENABLE); + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, + UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET); + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, + UNI_N_CFG_GART_ENABLE); +} + +static void uninorth_cleanup(void) +{ + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, + UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL); + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, + 0); + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, + UNI_N_CFG_GART_2xRESET); + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, + 0); +} + +static int uninorth_configure(void) +{ + aper_size_info_32 *current_size; + + current_size = A_SIZE_32(agp_bridge.current_size); + + printk("agp: configuring for size idx: %d\n", current_size->size_value); + + /* aperture size and gatt addr */ + pci_write_config_dword(agp_bridge.dev, + UNI_N_CFG_GART_BASE, + (agp_bridge.gatt_bus_addr & 0xfffff000) + | current_size->size_value); + + /* HACK ALERT + * UniNorth seem to be buggy enough not to handle properly when + * the AGP aperture isn't mapped at bus physical address 0 + */ + agp_bridge.gart_bus_addr = 0; + pci_write_config_dword(agp_bridge.dev, + UNI_N_CFG_AGP_BASE, agp_bridge.gart_bus_addr); + + return 0; +} + +static unsigned long uninorth_mask_memory(unsigned long addr, int type) +{ + return addr;/* | agp_bridge.masks[0].mask;*/ +} + +static int uninorth_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + void *temp; + + temp = agp_bridge.current_size; + num_entries = A_SIZE_32(temp)->num_entries; + + if (type != 0 || mem->type != 0) { + /* The generic routines know nothing of memory types */ + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + j = pg_start; + + while (j < (pg_start + mem->page_count)) { + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + agp_bridge.gatt_table[j] = cpu_to_le32((mem->memory[i] & 0xfffff000) | 0x00000001UL); + flush_dcache_range(__va(mem->memory[i]), __va(mem->memory[i])+0x1000); + } + (void)in_le32((volatile u32*)&agp_bridge.gatt_table[pg_start]); + mb(); + flush_dcache_range((unsigned long)&agp_bridge.gatt_table[pg_start], + (unsigned long)&agp_bridge.gatt_table[pg_start + mem->page_count]); + + agp_bridge.tlb_flush(mem); + return 0; +} + +static void uninorth_agp_enable(u32 mode) +{ + struct pci_dev *device = NULL; + u32 command, scratch, cap_id; + u8 cap_ptr; + + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + 4, + &command); + + /* + * PASS1: go throu all devices that claim to be + * AGP devices and collect their data. + */ + + while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, + device)) != NULL) { + pci_read_config_dword(device, 0x04, &scratch); + + if (!(scratch & 0x00100000)) + continue; + + pci_read_config_byte(device, 0x34, &cap_ptr); + + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(device, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr != 0x00) { + /* + * Ok, here we have a AGP device. Disable impossible + * settings, and adjust the readqueue to the minimum. + */ + + pci_read_config_dword(device, cap_ptr + 4, &scratch); + + /* adjust RQ depth */ + command = + ((command & ~0xff000000) | + min_t(u32, (mode & 0xff000000), + min_t(u32, (command & 0xff000000), + (scratch & 0xff000000)))); + + /* disable SBA if it's not supported */ + if (!((command & 0x00000200) && + (scratch & 0x00000200) && + (mode & 0x00000200))) + command &= ~0x00000200; + + /* disable FW if it's not supported */ + if (!((command & 0x00000010) && + (scratch & 0x00000010) && + (mode & 0x00000010))) + command &= ~0x00000010; + + if (!((command & 4) && + (scratch & 4) && + (mode & 4))) + command &= ~0x00000004; + + if (!((command & 2) && + (scratch & 2) && + (mode & 2))) + command &= ~0x00000002; + + if (!((command & 1) && + (scratch & 1) && + (mode & 1))) + command &= ~0x00000001; + } + } + /* + * PASS2: Figure out the 4X/2X/1X setting and enable the + * target (our motherboard chipset). + */ + + if (command & 4) { + command &= ~3; /* 4X */ + } + if (command & 2) { + command &= ~5; /* 2X */ + } + if (command & 1) { + command &= ~6; /* 1X */ + } + command |= 0x00000100; + + uninorth_tlbflush(NULL); + + do { + pci_write_config_dword(agp_bridge.dev, + agp_bridge.capndx + 8, + command); + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + 8, + &scratch); + } while((scratch & 0x100) == 0); + + /* + * PASS3: Go throu all AGP devices and update the + * command registers. + */ + + while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, + device)) != NULL) { + pci_read_config_dword(device, 0x04, &scratch); + + if (!(scratch & 0x00100000)) + continue; + + pci_read_config_byte(device, 0x34, &cap_ptr); + + if (cap_ptr != 0x00) { + do { + pci_read_config_dword(device, + cap_ptr, &cap_id); + + if ((cap_id & 0xff) != 0x02) + cap_ptr = (cap_id >> 8) & 0xff; + } + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); + } + if (cap_ptr != 0x00) + pci_write_config_dword(device, cap_ptr + 8, command); + } + + uninorth_tlbflush(NULL); +} + +static int uninorth_create_gatt_table(void) +{ + char *table; + char *table_end; + int size; + int page_order; + int num_entries; + int i; + void *temp; + struct page *page; + + /* The generic routines can't handle 2 level gatt's */ + if (agp_bridge.size_type == LVL2_APER_SIZE) { + return -EINVAL; + } + + table = NULL; + i = agp_bridge.aperture_size_idx; + temp = agp_bridge.current_size; + size = page_order = num_entries = 0; + + do { + size = A_SIZE_32(temp)->size; + page_order = A_SIZE_32(temp)->page_order; + num_entries = A_SIZE_32(temp)->num_entries; + + table = (char *) __get_free_pages(GFP_KERNEL, page_order); + + if (table == NULL) { + i++; + agp_bridge.current_size = A_IDX32(); + } else { + agp_bridge.aperture_size_idx = i; + } + } while ((table == NULL) && + (i < agp_bridge.num_aperture_sizes)); + + if (table == NULL) { + return -ENOMEM; + } + table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); + + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) + SetPageReserved(page); + + agp_bridge.gatt_table_real = (unsigned long *) table; + agp_bridge.gatt_table = (unsigned long *)table; + agp_bridge.gatt_bus_addr = virt_to_phys(table); + + for (i = 0; i < num_entries; i++) { + agp_bridge.gatt_table[i] = + (unsigned long) agp_bridge.scratch_page; + } + + flush_dcache_range((unsigned long)table, (unsigned long)table_end); + + return 0; +} + +static int uninorth_free_gatt_table(void) +{ + int page_order; + char *table, *table_end; + void *temp; + struct page *page; + + temp = agp_bridge.current_size; + page_order = A_SIZE_32(temp)->page_order; + + /* Do not worry about freeing memory, because if this is + * called, then all agp memory is deallocated and removed + * from the table. + */ + + table = (char *) agp_bridge.gatt_table_real; + table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); + + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) + ClearPageReserved(page); + + free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); + + return 0; +} + +static unsigned long uninorth_agp_alloc_page(void) +{ + struct page * page; + + page = alloc_page(GFP_KERNEL); + if (page == NULL) { + return 0; + } + get_page(page); + LockPage(page); + SetPageReserved(page); + atomic_inc(&agp_bridge.current_memory_agp); + return (unsigned long)page_address(page); +} + +static void uninorth_agp_destroy_page(unsigned long addr) +{ + void *pt = (void *) addr; + struct page *page; + + if (pt == NULL) { + return; + } + + page = virt_to_page(pt); + ClearPageReserved(page); + put_page(page); + UnlockPage(page); + free_page((unsigned long) pt); + atomic_dec(&agp_bridge.current_memory_agp); +} + +/* Setup function */ +static gatt_mask uninorth_masks[] = +{ + {0x00000000, 0} +}; + +static aper_size_info_32 uninorth_sizes[7] = +{ +#if 0 /* Not sure uninorth supports that high aperture sizes */ + {256, 65536, 6, 64}, + {128, 32768, 5, 32}, + {64, 16384, 4, 16}, +#endif + {32, 8192, 3, 8}, + {16, 4096, 2, 4}, + {8, 2048, 1, 2}, + {4, 1024, 0, 1} +}; + +static int __init uninorth_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = uninorth_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *)uninorth_sizes; + agp_bridge.size_type = U32_APER_SIZE; + agp_bridge.num_aperture_sizes = 4; //7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = uninorth_configure; + agp_bridge.fetch_size = uninorth_fetch_size; + agp_bridge.cleanup = uninorth_cleanup; + agp_bridge.tlb_flush = uninorth_tlbflush; + agp_bridge.mask_memory = uninorth_mask_memory; + agp_bridge.agp_enable = uninorth_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = uninorth_create_gatt_table; + agp_bridge.free_gatt_table = uninorth_free_gatt_table; + agp_bridge.insert_memory = uninorth_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = uninorth_agp_alloc_page; + agp_bridge.agp_destroy_page = uninorth_agp_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 1; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_UNINORTH */ + /* per-chipset initialization data. * note -- all chipsets for a single vendor MUST be grouped together */ @@ -4731,6 +5166,33 @@ hp_zx1_setup }, #endif +#ifdef CONFIG_AGP_UNINORTH + { PCI_DEVICE_ID_APPLE_UNI_N_AGP, + PCI_VENDOR_ID_APPLE, + APPLE_UNINORTH, + "Apple", + "UniNorth", + uninorth_setup }, + { PCI_DEVICE_ID_APPLE_UNI_N_AGP_P, + PCI_VENDOR_ID_APPLE, + APPLE_UNINORTH, + "Apple", + "UniNorth/Pangea", + uninorth_setup }, + { PCI_DEVICE_ID_APPLE_UNI_N_AGP15, + PCI_VENDOR_ID_APPLE, + APPLE_UNINORTH, + "Apple", + "UniNorth 1.5", + uninorth_setup }, + { PCI_DEVICE_ID_APPLE_UNI_N_AGP2, + PCI_VENDOR_ID_APPLE, + APPLE_UNINORTH, + "Apple", + "UniNorth 2", + uninorth_setup }, +#endif /* CONFIG_AGP_UNINORTH */ + { 0, }, /* dummy final entry, always present */ }; diff -uNr linux-2.4.20/drivers/char/briq_panel.c linux-2.4.20-ben6/drivers/char/briq_panel.c --- linux-2.4.20/drivers/char/briq_panel.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/briq_panel.c 2003-02-16 20:20:37.000000000 +0100 @@ -0,0 +1,251 @@ +/* + * Drivers for the Total Impact PPC based computer "BRIQ" + * by Dr. Karsten Jeppesen + * + * + * 010407 Coding started + * + * 04/20/2002 1.1 Adapted to 2.4, small cleanups + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TOTALIMPACT_VFD_MINOR 156 +#define VFD_IOPORT 0x0390 +#define LED_IOPORT 0x0398 +#define TI_VER "1.1 (04/20/2002)" +#define TI_MSG0 "Loading Linux" + +static int vfd_is_open; +static unsigned char vfd[40]; +static int vfd_cursor; +static unsigned char ledpb, led; + + +static void UpdateVFD( void ) +{ + int i; + outb(0x02, VFD_IOPORT); /* cursor home */ + for (i=0; i<20; i++) outb(vfd[i], VFD_IOPORT + 1); + outb(0xc0, VFD_IOPORT); /* cursor to next line */ + for (i=20; i<40; i++) outb(vfd[i], VFD_IOPORT + 1); + +} + +static void SetLED( char state) +{ + if ( state == 'R' ) led = 0x01; + else if ( state == 'G' ) led = 0x02; + else if ( state == 'Y' ) led = 0x03; + else if ( state == 'X' ) led = 0x00; + outb(led, LED_IOPORT); +} + +static int do_open(struct inode *ino, struct file *filep) +{ + if (vfd_is_open) return -EBUSY; + MOD_INC_USE_COUNT; + vfd_is_open = 1; + return(0); +} + +static int do_release(struct inode *ino, struct file *filep) +{ + if (!vfd_is_open) return -ENODEV; + MOD_DEC_USE_COUNT; + vfd_is_open = 0; + return(0); +} + + +static ssize_t do_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned short c; + unsigned char cp; + + /* Can't seek (pread) on this device */ + if (ppos != &file->f_pos) return -ESPIPE; + if (!vfd_is_open) return -ENODEV; + c = (inb( LED_IOPORT ) & 0x000c) | (ledpb & 0x0003); + SetLED(' '); + if ((!(ledpb & 0x0004)) && (c & 0x0004)) + { /* upper button released */ + cp = ' '; + ledpb = c; + if (copy_to_user(buf, &cp, 1)) return -EFAULT; + return(1); + } + else if ((!(ledpb & 0x0008)) && (c & 0x0008)) + { /* lower button released */ + cp = '\r'; + ledpb = c; + if (copy_to_user(buf, &cp, 1)) return -EFAULT; + return(1); + } else + { + ledpb = c; + return(0); + } +} + + +static void ScrollVFD( void ) +{ + int i; + for (i=0; i<20; i++) + { + vfd[i] = vfd[i+20]; + vfd[i+20] = ' '; + } + vfd_cursor = 20; +} + + +static ssize_t do_write(struct file *file, const char *buf, size_t len, + loff_t *ppos) +{ + size_t indx = len; + int i, esc=0; + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) return -ESPIPE; + if (!vfd_is_open) return -EBUSY; + for (;;) + { + if (!indx) break; + if (esc) + { + SetLED(*buf); + esc = 0; + } + else if (*buf == 27) + { + esc = 1; + } + else if (*buf == 12) + { /* do a form feed */ + for (i=0; i<40; i++) vfd[i] = ' '; + vfd_cursor = 0; + } + else if (*buf == 10) + { + if (vfd_cursor < 20) vfd_cursor = 20; + else if (vfd_cursor < 40) vfd_cursor = 40; + else if (vfd_cursor < 60) vfd_cursor = 60; + if (vfd_cursor > 59) ScrollVFD(); + } + else + { + /* just a character */ + if (vfd_cursor > 39) ScrollVFD(); + vfd[vfd_cursor++] = *buf; + } + indx--; + buf++; + } + UpdateVFD(); + return len; +} + + +static struct file_operations vfd_fops = { + read: do_read, /* Read */ + write: do_write, /* Write */ + open: do_open, /* Open */ + release: do_release, /* Release */ +}; + + +static struct miscdevice ti_vfd_miscdev = { + TOTALIMPACT_VFD_MINOR, + "vfd", + &vfd_fops +}; + + +static int __init briq_panel_init(void) +{ + struct device_node *root = find_path_device("/"); + char *machine; + int i; + + machine = get_property(root, "model", NULL); + if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) + return -ENODEV; + + printk(KERN_INFO "ti_briq: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n", TI_VER); + + if (!request_region( VFD_IOPORT, 4, "BRIQ Front Panel")) + return -EBUSY; + if (!request_region( LED_IOPORT, 2, "BRIQ Front Panel")) { + release_region(VFD_IOPORT, 4); + return -EBUSY; + } + ledpb = inb( LED_IOPORT ) & 0x000c; + + if (misc_register(&ti_vfd_miscdev) < 0) { + release_region(VFD_IOPORT, 4); + release_region(LED_IOPORT, 2); + return -EBUSY; + } + + outb(0x38, VFD_IOPORT); /* Function set */ + outb(0x01, VFD_IOPORT); /* Clear display */ + outb(0x0c, VFD_IOPORT); /* Display on */ + outb(0x06, VFD_IOPORT); /* Entry normal */ + for (i=0; i<40; i++) vfd[i]=' '; +#ifndef MODULE + vfd[0] = 'L'; + vfd[1] = 'o'; + vfd[2] = 'a'; + vfd[3] = 'd'; + vfd[4] = 'i'; + vfd[5] = 'n'; + vfd[6] = 'g'; + vfd[7] = ' '; + vfd[8] = '.'; + vfd[9] = '.'; + vfd[10] = '.'; +#endif /* !MODULE */ + UpdateVFD(); + + return 0; +} + + +static void __exit briq_panel_exit(void) +{ + misc_deregister(&ti_vfd_miscdev); + release_region(VFD_IOPORT, 4); + release_region(LED_IOPORT, 2); +} + + +module_init(briq_panel_init); +module_exit(briq_panel_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Karsten Jeppesen "); +MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel"); +EXPORT_NO_SYMBOLS; diff -uNr linux-2.4.20/drivers/char/defkeymap.c linux-2.4.20-ben6/drivers/char/defkeymap.c --- linux-2.4.20/drivers/char/defkeymap.c 1999-10-07 19:17:09.000000000 +0200 +++ linux-2.4.20-ben6/drivers/char/defkeymap.c 2003-02-16 20:20:39.000000000 +0100 @@ -1,3 +1,4 @@ + /* Do not edit this file! It was automatically generated by */ /* loadkeys --mktable defkeymap.map > defkeymap.c */ @@ -37,7 +38,7 @@ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a, 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116, 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, @@ -56,7 +57,7 @@ 0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b, 0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516, 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, @@ -94,7 +95,7 @@ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, @@ -132,7 +133,7 @@ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, 0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a, 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, @@ -147,6 +148,7 @@ unsigned int keymap_count = 7; + /* * Philosophy: most people do not define more strings, but they who do * often want quite a lot of string space. So, we statically allocate @@ -184,6 +186,7 @@ '\033', '[', 'P', 0, }; + char *funcbufptr = func_buf; int funcbufsize = sizeof(func_buf); int funcbufleft = 0; /* space left */ diff -uNr linux-2.4.20/drivers/char/drm/drmP.h linux-2.4.20-ben6/drivers/char/drm/drmP.h --- linux-2.4.20/drivers/char/drm/drmP.h 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/drm/drmP.h 2003-02-16 20:20:22.000000000 +0100 @@ -324,6 +324,15 @@ DRM(ioremapfree)( (map)->handle, (map)->size ); \ } while (0) +#define DRM_IOREMAPAGP(map, dev) \ + (map)->handle = DRM(ioremap_agp)( (map)->offset, (map)->size, (dev) ) + +#define DRM_IOREMAPAGPFREE(map) \ + do { \ + if ( (map)->handle && (map)->size ) \ + DRM(ioremap_agp_free)( (map)->handle, (map)->size ); \ + } while (0) + #define DRM_FIND_MAP(_map, _o) \ do { \ struct list_head *_list; \ @@ -758,6 +767,9 @@ extern void *DRM(ioremap)(unsigned long offset, unsigned long size); extern void DRM(ioremapfree)(void *pt, unsigned long size); +extern void *DRM(ioremap_agp)(unsigned long offset, unsigned long size, drm_device_t *dev); +extern void DRM(ioremap_agp_free)(void *pt, unsigned long size); + #if __REALLY_HAVE_AGP extern agp_memory *DRM(alloc_agp)(int pages, u32 type); extern int DRM(free_agp)(agp_memory *handle, int pages); diff -uNr linux-2.4.20/drivers/char/drm/drm_memory.h linux-2.4.20-ben6/drivers/char/drm/drm_memory.h --- linux-2.4.20/drivers/char/drm/drm_memory.h 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/drm/drm_memory.h 2003-02-16 20:20:28.000000000 +0100 @@ -313,6 +313,107 @@ return pt; } +/* PPC specific routine used by ioremap_agp, to be replaced by some + * more generic implementation + */ +extern int map_page(unsigned long va, unsigned long pa, int flags); + +void *DRM(ioremap_agp)(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + void *pt; + struct vm_struct *area; + struct drm_agp_mem *agpmem; + unsigned int flags = _PAGE_NO_CACHE|_PAGE_KERNEL|_PAGE_PRESENT|_PAGE_RW|_PAGE_DIRTY; + int err, i; + + printk("drm: ioremap_agp, offset: 0x%08lx, size: 0x%08lx\n", offset, size); + +#if __REALLY_HAVE_AGP + if (!size) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Mapping 0 bytes at 0x%08lx\n", offset); + return NULL; + } + + if (!dev->agp || !dev->agp->cant_use_aperture) + return DRM(ioremap)(offset, size); + + /* XXX This has to be changed into something more generic + * this implementation is really only valid on PPC + */ + area = get_vm_area(size, VM_IOREMAP); + if (area == 0) { + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&DRM(mem_lock)); + printk("->NULL\n"); + return NULL; + } + pt = (void *)VMALLOC_VMADDR(area->addr); + err = 0; + for (i = 0; i < size && err == 0; i += PAGE_SIZE) { + unsigned long baddr = offset + i; + unsigned long index; + + /* + * It's AGP memory - find the real physical page to map + */ + for(agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) { + if (agpmem->bound <= baddr && + agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) + break; + } + if (!agpmem) { + printk("drm: not matching AGP page in ioremap_agp\n"); + err = 1; + break; + } + index = (baddr - agpmem->bound) >> PAGE_SHIFT; + err = map_page(((unsigned long)pt)+i, agpmem->memory->memory[index], flags); + } + if (err) { + vfree((void *)pt); + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&DRM(mem_lock)); + printk("->NULL\n"); + return NULL; + } + + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; + DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&DRM(mem_lock)); + printk("->pt=0x%p\n", pt); + return pt; +#else + return NULL; +#endif +} + +void DRM(ioremap_agp_free)(void *pt, unsigned long size) +{ + int alloc_count; + int free_count; + + if (!pt) + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Attempt to free NULL pointer\n"); + else + vfree(pt); + + spin_lock(&DRM(mem_lock)); + DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size; + free_count = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count; + alloc_count = DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; + spin_unlock(&DRM(mem_lock)); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + void DRM(ioremapfree)(void *pt, unsigned long size) { int alloc_count; diff -uNr linux-2.4.20/drivers/char/drm/drm_vm.h linux-2.4.20-ben6/drivers/char/drm/drm_vm.h --- linux-2.4.20/drivers/char/drm/drm_vm.h 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/drm/drm_vm.h 2003-02-16 20:21:50.000000000 +0100 @@ -379,7 +379,13 @@ if ( !priv->authenticated ) return -EACCES; - if (!VM_OFFSET(vma)) return DRM(mmap_dma)(filp, vma); + /* We check for "dma". On Apple's UniNorth, it's valid to have + * the AGP mapped at physical address 0 + * --BenH. + */ + if (!VM_OFFSET(vma) && (!dev->agp || + dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)) + return DRM(mmap_dma)(filp, vma); /* A sequential search of a linked list is fine here because: 1) there will only be @@ -419,16 +425,22 @@ switch (map->type) { case _DRM_AGP: -#if defined(__alpha__) - /* - * On Alpha we can't talk to bus dma address from the - * CPU, so for memory of type DRM_AGP, we'll deal with - * sorting out the real physical pages and mappings - * in nopage() - */ - vma->vm_ops = &DRM(vm_ops); - break; + if (!dev->agp) + return -ENODEV; + if (dev->agp->cant_use_aperture) { + /* + * On Alpha we can't talk to bus dma address from the + * CPU, so for memory of type DRM_AGP, we'll deal with + * sorting out the real physical pages and mappings + * in nopage() + */ +#if defined(__powerpc__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; #endif + vma->vm_flags |= VM_IO; + vma->vm_ops = &DRM(vm_ops); + break; + } /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: diff -uNr linux-2.4.20/drivers/char/drm/r128_cce.c linux-2.4.20-ben6/drivers/char/drm/r128_cce.c --- linux-2.4.20/drivers/char/drm/r128_cce.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/drm/r128_cce.c 2003-02-16 20:20:00.000000000 +0100 @@ -37,6 +37,10 @@ #define R128_FIFO_DEBUG 0 +#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC) +extern unsigned long agp_special_page; +#endif + /* CCE microcode (from ATI) */ static u32 r128_cce_microcode[] = { @@ -340,6 +344,14 @@ SET_RING_HEAD( &dev_priv->ring, 0 ); if ( !dev_priv->is_pci ) { +#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC) + if (_machine == _MACH_Pmac) { + dev_priv->ring.head = (__volatile__ u32 *) agp_special_page; + SET_RING_HEAD( &dev_priv->ring, 0 ); + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, + __pa( dev_priv->ring.head ) ); + } else +#endif R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, dev_priv->ring_rptr->offset ); } else { @@ -549,9 +561,9 @@ init->sarea_priv_offset); if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cce_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAPAGP( dev_priv->cce_ring, dev ); + DRM_IOREMAPAGP( dev_priv->ring_rptr, dev ); + DRM_IOREMAPAGP( dev_priv->buffers, dev ); if(!dev_priv->cce_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { @@ -623,10 +635,11 @@ drm_r128_private_t *dev_priv = dev->dev_private; if ( !dev_priv->is_pci ) { - DRM_IOREMAPFREE( dev_priv->cce_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); - } else { + DRM_IOREMAPAGPFREE( dev_priv->cce_ring ); + DRM_IOREMAPAGPFREE( dev_priv->ring_rptr ); + DRM_IOREMAPAGPFREE( dev_priv->buffers ); + } + else { if (!DRM(ati_pcigart_cleanup)( dev, dev_priv->phys_pci_gart, dev_priv->bus_pci_gart )) diff -uNr linux-2.4.20/drivers/char/drm/r128_drv.h linux-2.4.20-ben6/drivers/char/drm/r128_drv.h --- linux-2.4.20/drivers/char/drm/r128_drv.h 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/drm/r128_drv.h 2003-02-16 20:21:36.000000000 +0100 @@ -34,8 +34,13 @@ #ifndef __R128_DRV_H__ #define __R128_DRV_H__ +#ifdef __powerpc__ +#define GET_RING_HEAD( ring ) in_le32((volatile u32 *)(ring)->head) +#define SET_RING_HEAD( ring, val ) out_le32((volatile u32 *)(ring)->head, (val) ) +#else #define GET_RING_HEAD( ring ) le32_to_cpu( *(ring)->head ) #define SET_RING_HEAD( ring, val ) *(ring)->head = cpu_to_le32( val ) +#endif typedef struct drm_r128_freelist { unsigned int age; @@ -397,6 +402,9 @@ wmb(); \ R128_DEREF(reg) = val; \ } while (0) +#elif defined (__powerpc__) +#define R128_READ(reg) in_le32( (volatile u32 *)R128_ADDR( reg ) ) +#define R128_WRITE(reg,val) out_le32( (volatile u32 *)R128_ADDR( reg ), (val) ) #else #define R128_READ(reg) le32_to_cpu( R128_DEREF( reg ) ) #define R128_WRITE(reg,val) \ @@ -418,6 +426,9 @@ wmb(); \ R128_DEREF8(reg) = val; \ } while (0) +#elif defined (__powerpc__) +#define R128_READ8(reg) in_8( (volatile u8 *)R128_ADDR(reg) ) +#define R128_WRITE8(reg,val) out_8( (volatile u8 *)R128_ADDR(reg), val ) #else #define R128_READ8(reg) R128_DEREF8( reg ) #define R128_WRITE8(reg,val) do { R128_DEREF8( reg ) = val; } while (0) @@ -493,8 +504,11 @@ * Ring control */ +#ifdef __powerpc__ +#define r128_flush_write_combine() (void)in_le32(ring) +#else #define r128_flush_write_combine() mb() - +#endif #define R128_VERBOSE 0 diff -uNr linux-2.4.20/drivers/char/drm/radeon_cp.c linux-2.4.20-ben6/drivers/char/drm/radeon_cp.c --- linux-2.4.20/drivers/char/drm/radeon_cp.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/drm/radeon_cp.c 2003-02-16 20:21:26.000000000 +0100 @@ -37,12 +37,15 @@ #define RADEON_FIFO_DEBUG 0 -#if defined(__alpha__) +#if defined(__alpha__) || defined(__powerpc__) # define PCIGART_ENABLED #else # undef PCIGART_ENABLED #endif +#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC) +extern unsigned long agp_special_page; +#endif /* CP microcode (from ATI) */ static u32 radeon_cp_microcode[][2] = { @@ -313,7 +316,7 @@ return RADEON_READ(RADEON_CLOCK_CNTL_DATA); } -#if RADEON_FIFO_DEBUG +#if 1 /* RADEON_FIFO_DEBUG */ static void radeon_status( drm_radeon_private_t *dev_priv ) { printk( "%s:\n", __FUNCTION__ ); @@ -400,7 +403,8 @@ udelay( 1 ); } -#if RADEON_FIFO_DEBUG +#if 1 /* RADEON_FIFO_DEBUG */ + printk("wait_for_idle timeout\n"); DRM_ERROR( "failed!\n" ); radeon_status( dev_priv ); #endif @@ -611,6 +615,14 @@ dev_priv->ring.tail = cur_read_ptr; if ( !dev_priv->is_pci ) { +#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC) + if (_machine == _MACH_Pmac) { + dev_priv->ring.head = (__volatile__ u32 *) agp_special_page; + *dev_priv->ring.head = cur_read_ptr; + RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, + __pa( dev_priv->ring.head ) ); + } else +#endif RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset ); } else { @@ -835,9 +847,9 @@ init->sarea_priv_offset); if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cp_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAPAGP( dev_priv->cp_ring, dev ); + DRM_IOREMAPAGP( dev_priv->ring_rptr, dev ); + DRM_IOREMAPAGP( dev_priv->buffers, dev ); if(!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { @@ -982,9 +994,9 @@ drm_radeon_private_t *dev_priv = dev->dev_private; if ( !dev_priv->is_pci ) { - DRM_IOREMAPFREE( dev_priv->cp_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); + DRM_IOREMAPAGPFREE( dev_priv->cp_ring ); + DRM_IOREMAPAGPFREE( dev_priv->ring_rptr ); + DRM_IOREMAPAGPFREE( dev_priv->buffers ); } else { if (!DRM(ati_pcigart_cleanup)( dev, dev_priv->phys_pci_gart, @@ -1351,14 +1363,15 @@ int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - radeon_update_ring_snapshot( ring ); + radeon_update_ring_snapshot( dev_priv, ring ); if ( ring->space > n ) return 0; udelay( 1 ); } /* FIXME: This return value is ignored in the BEGIN_RING macro! */ -#if RADEON_FIFO_DEBUG +#if 1 /* RADEON_FIFO_DEBUG */ + printk("wait ring timeout\n"); radeon_status( dev_priv ); DRM_ERROR( "failed!\n" ); #endif diff -uNr linux-2.4.20/drivers/char/drm/radeon_drv.h linux-2.4.20-ben6/drivers/char/drm/radeon_drv.h --- linux-2.4.20/drivers/char/drm/radeon_drv.h 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/drm/radeon_drv.h 2003-02-16 20:20:13.000000000 +0100 @@ -31,6 +31,14 @@ #ifndef __RADEON_DRV_H__ #define __RADEON_DRV_H__ +#if defined(__powerpc__) +#define GET_RING_HEAD(ring) in_le32((volatile u32 *)(ring)->head) +#define SET_RING_HEAD(ring,val) out_le32((volatile u32 *)(ring)->head, (val)) +#else +#define GET_RING_HEAD(ring) le32_to_cpu(*(ring)->head) +#define SET_RING_HEAD(ring,val) *(ring)->head = cpu_to_le32(val) +#endif + typedef struct drm_radeon_freelist { unsigned int age; drm_buf_t *buf; @@ -150,12 +158,7 @@ extern int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n ); static inline void -radeon_update_ring_snapshot( drm_radeon_ring_buffer_t *ring ) -{ - ring->space = (*(volatile int *)ring->head - ring->tail) * sizeof(u32); - if ( ring->space <= 0 ) - ring->space += ring->size; -} +radeon_update_ring_snapshot( drm_radeon_private_t *dev_priv, drm_radeon_ring_buffer_t *ring ); extern int radeon_do_cp_idle( drm_radeon_private_t *dev_priv ); extern int radeon_do_cleanup_cp( drm_device_t *dev ); @@ -539,6 +542,9 @@ wmb(); \ RADEON_DEREF(reg) = val; \ } while (0) +#elif defined(__powerpc__) +#define RADEON_READ(reg) in_le32((volatile u32 *)RADEON_ADDR(reg)) +#define RADEON_WRITE(reg,val) out_le32((volatile u32 *)RADEON_ADDR(reg), (val)) #else #define RADEON_READ(reg) RADEON_DEREF( reg ) #define RADEON_WRITE(reg, val) do { RADEON_DEREF( reg ) = val; } while (0) @@ -557,6 +563,9 @@ wmb(); \ RADEON_DEREF8( reg ) = val; \ } while (0) +#elif defined(__powerpc__) +#define RADEON_READ8(reg) in_8((volatile u8 *)RADEON_ADDR(reg)) +#define RADEON_WRITE8(reg,val) out_8((volatile u8 *)RADEON_ADDR(reg), (val)) #else #define RADEON_READ8(reg) RADEON_DEREF8( reg ) #define RADEON_WRITE8(reg, val) do { RADEON_DEREF8( reg ) = val; } while (0) @@ -652,7 +661,7 @@ drm_radeon_ring_buffer_t *ring = &dev_priv->ring; int i; \ if ( ring->space < ring->high_mark ) { \ for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { \ - radeon_update_ring_snapshot( ring ); \ + radeon_update_ring_snapshot( dev_priv, ring ); \ if ( ring->space >= ring->high_mark ) \ goto __ring_space_done; \ udelay( 1 ); \ @@ -694,12 +703,28 @@ * Ring control */ +#if defined(__powerpc__) +#define radeon_flush_write_combine() do { mb(); (void)in_le32(ring); mb(); } while(0) +#else #define radeon_flush_write_combine() mb() - +#endif #define RADEON_VERBOSE 0 +#define RADEON_DEBUG +#ifdef RADEON_DEBUG +#define RING_LOCALS int write; unsigned int mask; volatile u32 *ring; int dbg; +#define DEBUG_INIT(n) dbg = n +#define DEBUG_INC() do { if (dbg <= 0) printk("Argh 1 ! (%s:%d)\n", __FILE__, __LINE__); \ + dbg--; } while(0) +#define DEBUG_END() do { if (dbg != 0) printk("Argh 2/%d ! (%s:%d)\n", dbg, __FILE__, __LINE__); \ + dbg--; } while(0) +#else #define RING_LOCALS int write; unsigned int mask; volatile u32 *ring; +#define DEBUG_INIT() +#define DEBUG_INC() +#define DEBUG_END() +#endif #define BEGIN_RING( n ) do { \ if ( RADEON_VERBOSE ) { \ @@ -713,6 +738,7 @@ ring = dev_priv->ring.start; \ write = dev_priv->ring.tail; \ mask = dev_priv->ring.tail_mask; \ + DEBUG_INIT(n); \ } while (0) #define ADVANCE_RING() do { \ @@ -720,6 +746,7 @@ DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ write, dev_priv->ring.tail ); \ } \ + DEBUG_END(); \ radeon_flush_write_combine(); \ dev_priv->ring.tail = write; \ RADEON_WRITE( RADEON_CP_RB_WPTR, write ); \ @@ -730,10 +757,20 @@ DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \ (unsigned int)(x), write ); \ } \ - ring[write++] = (x); \ + DEBUG_INC(); \ + ring[write++] = cpu_to_le32(x); \ write &= mask; \ } while (0) #define RADEON_PERFORMANCE_BOXES 0 +static inline void +radeon_update_ring_snapshot( drm_radeon_private_t *dev_priv, drm_radeon_ring_buffer_t *ring ) +{ +// ring->space = (GET_RING_HEAD(ring) - ring->tail) * sizeof(u32); + ring->space = (RADEON_READ(0x710) - ring->tail) * sizeof(u32); + if ( ring->space <= 0 ) + ring->space += ring->size; +} + #endif /* __RADEON_DRV_H__ */ diff -uNr linux-2.4.20/drivers/char/drm/radeon_state.c linux-2.4.20-ben6/drivers/char/drm/radeon_state.c --- linux-2.4.20/drivers/char/drm/radeon_state.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.20-ben6/drivers/char/drm/radeon_state.c 2003-02-16 20:21:25.000000000 +0100 @@ -849,7 +849,7 @@ u32 *data = (u32 *) ((char *)dev_priv->buffers->handle + buf->offset + start); - data[dwords++] = RADEON_CP_PACKET2; + data[dwords++] = cpu_to_le32(RADEON_CP_PACKET2); } buf_priv->dispatched = 1; @@ -913,18 +913,22 @@ data = (u32 *)((char *)dev_priv->buffers->handle + buf->offset + start); - data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 ); + data[0] = cpu_to_le32(CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 )); - data[1] = offset; - data[2] = RADEON_MAX_VB_VERTS; - data[3] = format; - data[4] = (prim | RADEON_PRIM_WALK_IND | + data[1] = cpu_to_le32(offset); + data[2] = cpu_to_le32(RADEON_MAX_VB_VERTS); + data[3] = cpu_to_le32(format); + data[4] = cpu_to_le32((prim | RADEON_PRIM_WALK_IND | RADEON_COLOR_ORDER_RGBA | RADEON_VTX_FMT_RADEON_MODE | - (count << RADEON_NUM_VERTICES_SHIFT) ); + (count << RADEON_NUM_VERTICES_SHIFT) )); if ( count & 0x1 ) { +#ifdef __LITTLE_ENDIAN data[dwords-1] &= 0x0000ffff; +#else + data[dwords-1] &= 0xffff0000; +#endif } do { @@ -1067,22 +1071,22 @@ */ buffer = (u32 *)((char *)dev_priv->buffers->handle + buf->offset); - buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); - buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | + buffer[0] = cpu_to_le32(CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 )); + buffer[1] = cpu_to_le32((RADEON_GMC_DST_PITCH_OFFSET_CNTL | RADEON_GMC_BRUSH_NONE | (format << 8) | RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_S | RADEON_DP_SRC_SOURCE_HOST_DATA | RADEON_GMC_CLR_CMP_CNTL_DIS | - RADEON_GMC_WR_MSK_DIS); + RADEON_GMC_WR_MSK_DIS)); - buffer[2] = (tex->pitch << 22) | (tex->offset >> 10); - buffer[3] = 0xffffffff; - buffer[4] = 0xffffffff; - buffer[5] = (y << 16) | image->x; - buffer[6] = (height << 16) | image->width; - buffer[7] = dwords; + buffer[2] = cpu_to_le32((tex->pitch << 22) | (tex->offset >> 10)); + buffer[3] = cpu_to_le32(0xffffffff); + buffer[4] = cpu_to_le32(0xffffffff); + buffer[5] = cpu_to_le32((y << 16) | image->x); + buffer[6] = cpu_to_le32((height << 16) | image->width); + buffer[7] = cpu_to_le32(dwords); buffer += 8; diff -uNr linux-2.4.20/drivers/i2c/i2c-keywest.c linux-2.4.20-ben6/drivers/i2c/i2c-keywest.c --- linux-2.4.20/drivers/i2c/i2c-keywest.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/i2c/i2c-keywest.c 2003-02-16 20:20:12.000000000 +0100 @@ -256,6 +256,7 @@ len = 1; buffer = &data->byte; iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + //iface->cur_mode |= KW_I2C_MODE_COMBINED; break; case I2C_SMBUS_WORD_DATA: len = 2; @@ -267,6 +268,7 @@ len = data->block[0]; buffer = &data->block[1]; iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + //iface->cur_mode |= KW_I2C_MODE_COMBINED; break; default: return -1; diff -uNr linux-2.4.20/drivers/ide/aec62xx.c linux-2.4.20-ben6/drivers/ide/aec62xx.c --- linux-2.4.20/drivers/ide/aec62xx.c 2000-06-20 16:52:36.000000000 +0200 +++ linux-2.4.20-ben6/drivers/ide/aec62xx.c 2003-02-16 20:21:07.000000000 +0100 @@ -51,6 +51,21 @@ extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; +static const char *aec6280_get_speed(u8 speed) +{ + switch(speed) { + case 7: return "6"; + case 6: return "5"; + case 5: return "4"; + case 4: return "3"; + case 3: return "2"; + case 2: return "1"; + case 1: return "0"; + case 0: return "?"; + } + return "?"; +} + static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; @@ -69,6 +84,12 @@ case PCI_DEVICE_ID_ARTOP_ATP860R: p += sprintf(p, "\n AEC6260 Chipset.\n"); break; + case PCI_DEVICE_ID_ARTOP_ATP865: + p += sprintf(p, "\n AEC6280 Chipset without ROM.\n"); + break; + case PCI_DEVICE_ID_ARTOP_ATP865R: + p += sprintf(p, "\n AEC6280 Chipset with ROM.\n"); + break; default: p += sprintf(p, "\n AEC62?? Chipset.\n"); break; @@ -153,6 +174,41 @@ (void) pci_read_config_byte(bmide_dev, 0x4a, &uart); p += sprintf(p, "reg4ah = 0x%02x\n", uart); break; + case PCI_DEVICE_ID_ARTOP_ATP865: + case PCI_DEVICE_ID_ARTOP_ATP865R: + (void) pci_read_config_byte(bmide_dev, 0x44, &art); + p += sprintf(p, "DMA Mode: %s(%s) %s(%s)", + (c0&0x20)?((art&0x0f)?"UDMA":" DMA"):" PIO", + aec6280_get_speed(art&0x0f), + (c0&0x40)?((art&0xf0)?"UDMA":" DMA"):" PIO", + aec6280_get_speed(art>>4)); + (void) pci_read_config_byte(bmide_dev, 0x45, &art); + p += sprintf(p, " %s(%s) %s(%s)\n", + (c0&0x20)?((art&0x0f)?"UDMA":" DMA"):" PIO", + aec6280_get_speed(art&0x0f), + (c0&0x40)?((art&0xf0)?"UDMA":" DMA"):" PIO", + aec6280_get_speed(art>>4)); + (void) pci_read_config_byte(bmide_dev, 0x40, &art); + p += sprintf(p, "Active: 0x%02x", HIGH_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x41, &art); + p += sprintf(p, " 0x%02x", HIGH_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x42, &art); + p += sprintf(p, " 0x%02x", HIGH_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x43, &art); + p += sprintf(p, " 0x%02x\n", HIGH_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x40, &art); + p += sprintf(p, "Recovery: 0x%02x", LOW_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x41, &art); + p += sprintf(p, " 0x%02x", LOW_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x42, &art); + p += sprintf(p, " 0x%02x", LOW_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x43, &art); + p += sprintf(p, " 0x%02x\n", LOW_4(art)); + (void) pci_read_config_byte(bmide_dev, 0x49, &uart); + p += sprintf(p, "reg49h = 0x%02x ", uart); + (void) pci_read_config_byte(bmide_dev, 0x4a, &uart); + p += sprintf(p, "reg4ah = 0x%02x\n", uart); + break; default: break; } @@ -177,6 +233,8 @@ struct chipset_bus_clock_list_entry aec62xx_base [] = { #ifdef CONFIG_BLK_DEV_IDEDMA + { XFER_UDMA_6, 0x41, 0x06, 0x31, 0x07 }, + { XFER_UDMA_5, 0x41, 0x05, 0x31, 0x06 }, { XFER_UDMA_4, 0x41, 0x04, 0x31, 0x05 }, { XFER_UDMA_3, 0x41, 0x03, 0x31, 0x04 }, { XFER_UDMA_2, 0x41, 0x02, 0x31, 0x03 }, @@ -399,6 +457,58 @@ ide_dma_off_quietly); } +static int config_aec6280_chipset_for_dma (ide_drive_t *drive, byte ultra) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + byte unit = (drive->select.b.unit & 0x01); + unsigned long dma_base = hwif->dma_base; + byte speed = -1; + byte ultra66 = eighty_ninty_three(drive); + + if (drive->media != ide_disk) + return ((int) ide_dma_off_quietly); + + if ((id->dma_ultra & 0x0040) && (ultra) && (ultra66)) { + speed = XFER_UDMA_6; + } else if ((id->dma_ultra & 0x0020) && (ultra) && (ultra66)) { + speed = XFER_UDMA_5; + } else if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) { + speed = XFER_UDMA_4; + } else if ((id->dma_ultra & 0x0008) && (ultra) && (ultra66)) { + speed = XFER_UDMA_3; + } else if ((id->dma_ultra & 0x0004) && (ultra)) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else if (id->dma_1word & 0x0002) { + speed = XFER_SW_DMA_1; + } else if (id->dma_1word & 0x0001) { + speed = XFER_SW_DMA_0; + } else { + return ((int) ide_dma_off_quietly); + } + + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + (void) aec6260_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) { switch(HWIF(drive)->pci_dev->device) { @@ -407,6 +517,9 @@ case PCI_DEVICE_ID_ARTOP_ATP860: case PCI_DEVICE_ID_ARTOP_ATP860R: return config_aec6260_chipset_for_dma(drive, ultra); + case PCI_DEVICE_ID_ARTOP_ATP865: + case PCI_DEVICE_ID_ARTOP_ATP865R: + return config_aec6260_chipset_for_dma(drive, ultra); default: return ((int) ide_dma_off_quietly); } @@ -433,6 +546,8 @@ (void) aec6210_tune_chipset(drive, speed); case PCI_DEVICE_ID_ARTOP_ATP860: case PCI_DEVICE_ID_ARTOP_ATP860R: + case PCI_DEVICE_ID_ARTOP_ATP865: + case PCI_DEVICE_ID_ARTOP_ATP865R: (void) aec6260_tune_chipset(drive, speed); default: break; @@ -551,6 +666,31 @@ void __init ide_init_aec62xx (ide_hwif_t *hwif) { + byte reg49h = 0; + byte reg4ah = 0; + + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_ARTOP_ATP865: + case PCI_DEVICE_ID_ARTOP_ATP865R: + /* Clear reset and test bits. */ + pci_read_config_byte(hwif->pci_dev, 0x49, ®49h); + pci_write_config_byte(hwif->pci_dev, 0x49, reg49h & ~0x30); + /* Enable chip interrupt output. */ + pci_read_config_byte(hwif->pci_dev, 0x4a, ®4ah); + pci_write_config_byte(hwif->pci_dev, 0x4a, reg4ah & ~0x01); +#define CONFIG_AEC6280_BURST +#ifdef CONFIG_AEC6280_BURST + /* Must be greater than 0x80 for burst mode. */ + pci_write_config_byte(hwif->pci_dev, PCI_LATENCY_TIMER, 0x90); + /* Enable burst mode. */ + pci_read_config_byte(hwif->pci_dev, 0x4a, ®4ah); + pci_write_config_byte(hwif->pci_dev, 0x4a, reg4ah | 0x80); +#endif + break; + default: + break; + } + #ifdef CONFIG_AEC62XX_TUNING hwif->tuneproc = &aec62xx_tune_drive; hwif->speedproc = &aec62xx_tune_chipset; @@ -570,13 +710,20 @@ unsigned long flags; byte reg54h = 0; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_ARTOP_ATP865: + case PCI_DEVICE_ID_ARTOP_ATP865R: + break; + default: + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ - pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); - pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F)); + pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); + pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F)); - __restore_flags(flags); /* local CPU only */ + __restore_flags(flags); /* local CPU only */ + break; + } #endif /* CONFIG_AEC62XX_TUNING */ ide_setup_dma(hwif, dmabase, 8); } diff -uNr linux-2.4.20/drivers/ide/ide-cs.c linux-2.4.20-ben6/drivers/ide/ide-cs.c --- linux-2.4.20/drivers/ide/ide-cs.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/ide/ide-cs.c 2003-02-16 20:20:25.000000000 +0100 @@ -92,10 +92,12 @@ int ndev; dev_node_t node; int hd; + struct tq_struct rel_task; } ide_info_t; static void ide_config(dev_link_t *link); -static void ide_release(u_long arg); +static void ide_release(void *arg); +static void ide_release_tm(ulong arg); static int ide_event(event_t event, int priority, event_callback_args_t *args); @@ -136,8 +138,8 @@ if (!info) return NULL; memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; - - link->release.function = &ide_release; + INIT_TQUEUE(&info->rel_task, ide_release, link); + link->release.function = &ide_release_tm; link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; @@ -198,6 +200,7 @@ return; del_timer(&link->release); + flush_scheduled_tasks(); if (link->state & DEV_CONFIG) ide_release((u_long)link); @@ -381,7 +384,7 @@ cs_failed: cs_error(link->handle, last_fn, last_ret); failed: - ide_release((u_long)link); + ide_release(link); } /* ide_config */ @@ -393,12 +396,24 @@ ======================================================================*/ -void ide_release(u_long arg) +static void ide_release_tm(ulong arg) { - dev_link_t *link = (dev_link_t *)arg; + dev_link_t *link = arg; + ide_info_t *info = link->priv; + + if (link->state & DEV_CONFIG) + schedule_task(&info->rel_task); +} + +static void ide_release(void *arg) +{ + dev_link_t *link = arg; ide_info_t *info = link->priv; - DEBUG(0, "ide_release(0x%p)\n", link); + if (!(link->state & DEV_CONFIG)) + return; + + DEBUG(0, "ide_do_release(0x%p)\n", link); if (info->ndev) { ide_unregister(info->hd); diff -uNr linux-2.4.20/drivers/ide/ide-disk.c linux-2.4.20-ben6/drivers/ide/ide-disk.c --- linux-2.4.20/drivers/ide/ide-disk.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/ide/ide-disk.c 2003-02-16 20:20:13.000000000 +0100 @@ -1286,6 +1286,9 @@ { drive->addressing = 0; + if (HWIF(drive)->addressing) + return 0; + if (!(drive->id->cfs_enable_2 & 0x0400)) return -EIO; diff -uNr linux-2.4.20/drivers/ide/ide-dma.c linux-2.4.20-ben6/drivers/ide/ide-dma.c --- linux-2.4.20/drivers/ide/ide-dma.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/ide/ide-dma.c 2003-02-16 20:20:24.000000000 +0100 @@ -266,11 +266,21 @@ bh = rq->bh; do { struct scatterlist *sge; + int contig = 0; + + if (bh->b_page) { + if (bh_phys(bh) == lastdataend) + contig = 1; + } else { + if ((unsigned long) bh->b_data == lastdataend) + contig = 1; + } + /* * continue segment from before? */ - if (bh_phys(bh) == lastdataend) { + if (contig) { sg[nents - 1].length += bh->b_size; lastdataend += bh->b_size; continue; @@ -288,15 +298,16 @@ if (bh->b_page) { sge->page = bh->b_page; sge->offset = bh_offset(bh); + lastdataend = bh_phys(bh) + bh->b_size; } else { - if (((unsigned long) bh->b_data) < PAGE_SIZE) + if ((unsigned long) bh->b_data < PAGE_SIZE) BUG(); sge->address = bh->b_data; + lastdataend = (unsigned long) bh->b_data + bh->b_size; } sge->length = bh->b_size; - lastdataend = bh_phys(bh) + bh->b_size; nents++; } while ((bh = bh->b_reqnext) != NULL); @@ -412,6 +423,7 @@ if (count) { if (!is_trm290_chipset) *--table |= cpu_to_le32(0x80000000); + io_barrier(); return count; } printk("%s: empty DMA table?\n", drive->name); diff -uNr linux-2.4.20/drivers/ide/ide-features.c linux-2.4.20-ben6/drivers/ide/ide-features.c --- linux-2.4.20/drivers/ide/ide-features.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/ide/ide-features.c 2003-02-16 20:19:51.000000000 +0100 @@ -278,7 +278,11 @@ #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) byte unit = (drive->select.b.unit & 0x01); - outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + /* Some interfaces would like to use this routine, but don"t have this + * kind of DMA engine. --BenH. + */ + if (hwif->dma_base) + outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); #endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ /* @@ -347,10 +351,15 @@ drive->id->dma_1word &= ~0x0F00; #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) - if (speed > XFER_PIO_4) { - outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); - } else { - outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + /* Some interfaces would like to use this routine, but don"t have this + * kind of DMA engine. --BenH. + */ + if (hwif->dma_base) { + if (speed > XFER_PIO_4) { + outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); + } else { + outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + } } #endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ diff -uNr linux-2.4.20/drivers/ide/ide-pci.c linux-2.4.20-ben6/drivers/ide/ide-pci.c --- linux-2.4.20/drivers/ide/ide-pci.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/ide/ide-pci.c 2003-02-16 20:20:14.000000000 +0100 @@ -73,6 +73,8 @@ #define DEVID_AEC6210 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF}) #define DEVID_AEC6260 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860}) #define DEVID_AEC6260R ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R}) +#define DEVID_AEC6280 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865}) +#define DEVID_AEC6280R ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R}) #define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105}) #define DEVID_UM8673F ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F}) #define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A}) @@ -444,6 +446,8 @@ {DEVID_AEC6210, "AEC6210", PCI_AEC62XX, NULL, INIT_AEC62XX, DMA_AEC62XX, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, {DEVID_AEC6260, "AEC6260", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0 }, {DEVID_AEC6260R,"AEC6260R", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, + {DEVID_AEC6280, "AEC6280", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_AEC6280R,"AEC6280R", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, {DEVID_W82C105, "W82C105", PCI_W82C105, NULL, INIT_W82C105, DMA_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, {DEVID_UM8673F, "UM8673F", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, @@ -486,6 +490,8 @@ case PCI_DEVICE_ID_ARTOP_ATP850UF: case PCI_DEVICE_ID_ARTOP_ATP860: case PCI_DEVICE_ID_ARTOP_ATP860R: + case PCI_DEVICE_ID_ARTOP_ATP865: + case PCI_DEVICE_ID_ARTOP_ATP865R: return dev->irq; default: break; @@ -822,6 +828,8 @@ IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6280) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6280R) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) || diff -uNr linux-2.4.20/drivers/ide/ide-pmac.c linux-2.4.20-ben6/drivers/ide/ide-pmac.c --- linux-2.4.20/drivers/ide/ide-pmac.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/ide/ide-pmac.c 2003-02-16 20:19:53.000000000 +0100 @@ -43,21 +43,23 @@ #include #endif #include "ide_modes.h" +#include "ide-timing.h" extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq); -#define IDE_PMAC_DEBUG - +#undef IDE_PMAC_DEBUG #define DMA_WAIT_TIMEOUT 500 -struct pmac_ide_hwif { +typedef struct pmac_ide_hwif { ide_ioreg_t regbase; + unsigned long mapbase; int irq; int kind; int aapl_bus_id; + int cable_80; struct device_node* node; - u32 timings[2]; + u32 timings[4]; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC /* Those fields are duplicating what is in hwif. We currently * can't use the hwif ones because of some assumptions that are @@ -72,8 +74,9 @@ int sg_dma_direction; #endif -} pmac_ide[MAX_HWIFS] __pmacdata; +} pmac_ide_hwif_t; +static pmac_ide_hwif_t pmac_ide[MAX_HWIFS] __pmacdata; static int pmac_ide_count; enum { @@ -81,7 +84,15 @@ controller_heathrow, /* Heathrow/Paddington */ controller_kl_ata3, /* KeyLargo ATA-3 */ controller_kl_ata4, /* KeyLargo ATA-4 */ - controller_kl_ata4_80 /* KeyLargo ATA-4 with 80 conductor cable */ + controller_un_ata6 /* UniNorth2 ATA-6 */ +}; + +static const char* model_name[] = { + "OHare ATA", /* OHare based */ + "Heathrow ATA", /* Heathrow/Paddington */ + "KeyLargo ATA-3", /* KeyLargo ATA-3 */ + "KeyLargo ATA-4", /* KeyLargo ATA-4 */ + "UniNorth ATA-6" /* UniNorth2 ATA-6 */ }; /* @@ -90,6 +101,11 @@ #define IDE_TIMING_CONFIG 0x200 #define IDE_INTERRUPT 0x300 +/* Kauai (U2) ATA has different register setup */ +#define IDE_KAUAI_PIO_CONFIG 0x200 +#define IDE_KAUAI_ULTRA_CONFIG 0x210 +#define IDE_KAUAI_POLL_CONFIG 0x220 + /* * Timing configuration register definitions */ @@ -100,6 +116,28 @@ #define IDE_SYSCLK_NS 30 /* 33Mhz cell */ #define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */ +/* 100Mhz cell, found in Uninorth 2. I don't have much infos about + * this one yet, it appears as a pci device (106b/0033) on uninorth + * internal PCI bus and it's clock is controlled like gem or fw. It + * appears to be an evolution of keylargo ATA4 with a timing register + * extended to 2 32bits registers and a similar DBDMA channel. Other + * registers seem to exist but I can't tell much about them. + * + * So far, I'm using pre-calculated tables for this extracted from + * the values used by the MacOS X driver. + * + * The "PIO" register controls PIO and MDMA timings, the "ULTRA" + * register controls the UDMA timings. At least, it seems bit 0 + * of this one enables UDMA vs. MDMA, and bits 4..7 are the + * cycle time in units of 10ns. Bits 8..15 are used by I don't + * know their meaning yet + */ +#define TR_100_PIOREG_PIO_MASK 0xff000fff +#define TR_100_PIOREG_MDMA_MASK 0x00fff000 +#define TR_100_UDMAREG_UDMA_MASK 0x0000ffff +#define TR_100_UDMAREG_UDMA_EN 0x00000001 + + /* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on * 40 connector cable and to 4 on 80 connector one. * Clock unit is 15ns (66Mhz) @@ -218,12 +256,12 @@ { 0, 0, 0 } }; -/* Ultra DMA timings (rounded) */ +/* KeyLargo ATA-4 Ultra DMA timings (rounded) */ struct { int addrSetup; /* ??? */ int rdy2pause; int wrDataSetup; -} udma_timings[] __pmacdata = +} kl66_udma_timings[] __pmacdata = { { 0, 180, 120 }, /* Mode 0 */ { 0, 150, 90 }, /* 1 */ @@ -232,6 +270,63 @@ { 0, 90, 30 } /* 4 */ }; +/* UniNorth 2 ATA/100 timings */ +struct kauai_timing { + int cycle_time; + u32 timing_reg; +}; + +static struct kauai_timing kauai_pio_timings[] __pmacdata = +{ + { 930 , 0x08000fff }, + { 600 , 0x08000a92 }, + { 383 , 0x0800060f }, + { 360 , 0x08000492 }, + { 330 , 0x0800048f }, + { 300 , 0x080003cf }, + { 270 , 0x080003cc }, + { 240 , 0x0800038b }, + { 239 , 0x0800030c }, + { 180 , 0x05000249 }, + { 120 , 0x04000148 } +}; + +static struct kauai_timing kauai_mdma_timings[] __pmacdata = +{ + { 1260 , 0x00fff000 }, + { 480 , 0x00618000 }, + { 360 , 0x00492000 }, + { 270 , 0x0038e000 }, + { 240 , 0x0030c000 }, + { 210 , 0x002cb000 }, + { 180 , 0x00249000 }, + { 150 , 0x00209000 }, + { 120 , 0x00148000 }, + { 0 , 0 }, +}; + +static struct kauai_timing kauai_udma_timings[] __pmacdata = +{ + { 120 , 0x000070c0 }, + { 90 , 0x00005d80 }, + { 60 , 0x00004a60 }, + { 45 , 0x00003a50 }, + { 30 , 0x00002a30 }, + { 20 , 0x00002921 }, + { 0 , 0 }, +}; + +static inline u32 +kauai_lookup_timing(struct kauai_timing* table, int cycle_time) +{ + int i; + + for (i=0; table[i].cycle_time; i++) + if (cycle_time > table[i+1].cycle_time) + return table[i].timing_reg; + return 0; +} + /* allow up to 256 DBDMA commands per xfer */ #define MAX_DCMDS 256 @@ -240,15 +335,19 @@ * NOTE: There is at least one case I know of a disk that needs about 10sec * before anwering on the bus. I beleive we could add a kernel command * line arg to override this delay for such cases. + * + * NOTE2: This has to be fixed with a BSY wait loop. I'm working on adding + * that to the generic probe code. */ #define IDE_WAKEUP_DELAY_MS 2000 static void pmac_ide_setup_dma(struct device_node *np, int ix); static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive); -static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr); +static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr); static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed); static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio); static void pmac_ide_selectproc(ide_drive_t *drive); +static void pmac_ide_kauai_selectproc(ide_drive_t *drive); #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ @@ -266,21 +365,6 @@ 0 }; -static int __pmac -pmac_ide_find(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - ide_ioreg_t base; - int i; - - for (i=0; iio_ports[0]) - return i; - } - return -1; -} - /* * N.B. this can't be an initfunc, because the media-bay task can * call ide_[un]register at any time. @@ -315,7 +399,10 @@ *irq = pmac_ide[ix].irq; ide_hwifs[ix].tuneproc = pmac_ide_tuneproc; - ide_hwifs[ix].selectproc = pmac_ide_selectproc; + if (pmac_ide[ix].kind == controller_un_ata6) + ide_hwifs[ix].selectproc = pmac_ide_kauai_selectproc; + else + ide_hwifs[ix].selectproc = pmac_ide_selectproc; ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset; if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) { ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; @@ -347,19 +434,55 @@ static void __pmac pmac_ide_selectproc(ide_drive_t *drive) { - int i = pmac_ide_find(drive); - if (i < 0) + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; + + if (pmif == NULL) return; if (drive->select.b.unit & 0x01) out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE), - pmac_ide[i].timings[1]); + pmif->timings[1]); else out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE), - pmac_ide[i].timings[0]); + pmif->timings[0]); (void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE)); } +static void __pmac +pmac_ide_kauai_selectproc(ide_drive_t *drive) +{ + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; + + if (pmif == NULL) + return; + + if (drive->select.b.unit & 0x01) { + out_le32((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG + _IO_BASE), + pmif->timings[1]); + out_le32((unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG + _IO_BASE), + pmif->timings[3]); + } else { + out_le32((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG + _IO_BASE), + pmif->timings[0]); + out_le32((unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG + _IO_BASE), + pmif->timings[2]); + } + (void)in_le32((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG + _IO_BASE)); +} + +static void __pmac +pmac_ide_do_update_timings(ide_drive_t *drive) +{ + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; + + if (pmif == NULL) + return; + + if (pmif->kind == controller_un_ata6) + pmac_ide_kauai_selectproc(drive); + else + pmac_ide_selectproc(drive); +} /* Note: We don't use the generic routine here because for some * yet unexplained reasons, it cause some media-bay CD-ROMs to @@ -397,10 +520,10 @@ } static int __pmac -pmac_ide_do_setfeature(ide_drive_t *drive, byte command) +pmac_ide_do_setfeature(ide_drive_t *drive, u8 command) { - int result = 1; ide_hwif_t *hwif = HWIF(drive); + int result = 1; disable_irq(hwif->irq); /* disable_irq_nosync ?? */ udelay(1); @@ -454,31 +577,36 @@ static void __pmac pmac_ide_tuneproc(ide_drive_t *drive, byte pio) { - ide_pio_data_t d; - int i; + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; u32 *timings; unsigned accessTicks, recTicks; unsigned accessTime, recTime; + ide_pio_data_t d; - i = pmac_ide_find(drive); - if (i < 0) + if (pmif == NULL) return; + /* which drive is it ? */ + timings = &pmif->timings[drive->select.b.unit & 0x01]; + pio = ide_get_best_pio_mode(drive, pio, 4, &d); - accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time); - if (drive->select.b.unit & 0x01) - timings = &pmac_ide[i].timings[1]; - else - timings = &pmac_ide[i].timings[0]; - recTime = d.cycle_time - ide_pio_timings[pio].active_time - - ide_pio_timings[pio].setup_time; - recTime = max(recTime, 150U); - accessTime = ide_pio_timings[pio].active_time; - accessTime = max(accessTime, 150U); - if (pmac_ide[i].kind == controller_kl_ata4 || - pmac_ide[i].kind == controller_kl_ata4_80) { + switch (pmif->kind) { + case controller_un_ata6: { + /* 100Mhz cell */ + u32 tr = kauai_lookup_timing(kauai_pio_timings, d.cycle_time); + if (tr == 0) + return; + *timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr; + break; + } + case controller_kl_ata4: /* 66Mhz cell */ + recTime = d.cycle_time - ide_pio_timings[pio].active_time + - ide_pio_timings[pio].setup_time; + recTime = max(recTime, 150U); + accessTime = ide_pio_timings[pio].active_time; + accessTime = max(accessTime, 150U); accessTicks = SYSCLK_TICKS_66(accessTime); accessTicks = min(accessTicks, 0x1fU); recTicks = SYSCLK_TICKS_66(recTime); @@ -486,9 +614,15 @@ *timings = ((*timings) & ~TR_66_PIO_MASK) | (accessTicks << TR_66_PIO_ACCESS_SHIFT) | (recTicks << TR_66_PIO_RECOVERY_SHIFT); - } else { + break; + default: { /* 33Mhz cell */ int ebit = 0; + recTime = d.cycle_time - ide_pio_timings[pio].active_time + - ide_pio_timings[pio].setup_time; + recTime = max(recTime, 150U); + accessTime = ide_pio_timings[pio].active_time; + accessTime = max(accessTime, 150U); accessTicks = SYSCLK_TICKS(accessTime); accessTicks = min(accessTicks, 0x1fU); accessTicks = max(accessTicks, 4U); @@ -504,6 +638,8 @@ (recTicks << TR_33_PIO_RECOVERY_SHIFT); if (ebit) *timings |= TR_33_PIO_E; + break; + } } #ifdef IDE_PMAC_DEBUG @@ -512,18 +648,21 @@ #endif if (drive->select.all == IN_BYTE(IDE_SELECT_REG)) - pmac_ide_selectproc(drive); + pmac_ide_do_update_timings(drive); } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC static int __pmac -set_timings_udma(u32 *timings, byte speed) +set_timings_udma_ata4(u32 *timings, byte speed) { unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks; - rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause); - wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup); - addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup); + if (speed > XFER_UDMA_4) + return 1; + + rdyToPauseTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].rdy2pause); + wrDataSetupTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].wrDataSetup); + addrTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].addrSetup); *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) | (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | @@ -539,11 +678,28 @@ } static int __pmac -set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time) +set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, byte speed) +{ + struct ide_timing *t = ide_timing_find_mode(speed); + u32 tr; + + if (speed > XFER_UDMA_5 || t == NULL) + return 1; + tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma); + if (tr == 0) + return 1; + *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr; + *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN; + + return 0; +} + +static int __pmac +set_timings_mdma(int intf_type, u32 *timings, u32 *timings2, byte speed, int drive_cycle_time) { int cycleTime, accessTime, recTime; unsigned accessTicks, recTicks; - struct mdma_timings_t* tm; + struct mdma_timings_t* tm = NULL; int i; /* Get default cycle time for mode */ @@ -552,7 +708,7 @@ case 1: cycleTime = 150; break; case 2: cycleTime = 120; break; default: - return -1; + return 1; } /* Adjust for drive */ if (drive_cycle_time && drive_cycle_time > cycleTime) @@ -562,8 +718,9 @@ cycleTime = 150; /* Get the proper timing array for this controller */ switch(intf_type) { + case controller_un_ata6: + break; case controller_kl_ata4: - case controller_kl_ata4_80: tm = mdma_timings_66; break; case controller_kl_ata3: @@ -573,24 +730,36 @@ tm = mdma_timings_33; break; } - /* Lookup matching access & recovery times */ - i = -1; - for (;;) { - if (tm[i+1].cycleTime < cycleTime) - break; - i++; - } - if (i < 0) - return -1; - cycleTime = tm[i].cycleTime; - accessTime = tm[i].accessTime; - recTime = tm[i].recoveryTime; + if (tm != NULL) { + /* Lookup matching access & recovery times */ + i = -1; + for (;;) { + if (tm[i+1].cycleTime < cycleTime) + break; + i++; + } + if (i < 0) + return 1; + cycleTime = tm[i].cycleTime; + accessTime = tm[i].accessTime; + recTime = tm[i].recoveryTime; #ifdef IDE_PMAC_DEBUG - printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n", - cycleTime, accessTime, recTime); -#endif - if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) { + printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n", + cycleTime, accessTime, recTime); +#endif + } + switch(intf_type) { + case controller_un_ata6: { + /* 100Mhz cell */ + u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime); + if (tr == 0) + return 1; + *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr; + *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN; + } + break; + case controller_kl_ata4: /* 66Mhz cell */ accessTicks = SYSCLK_TICKS_66(accessTime); accessTicks = min(accessTicks, 0x1fU); @@ -602,7 +771,8 @@ *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) | (accessTicks << TR_66_MDMA_ACCESS_SHIFT) | (recTicks << TR_66_MDMA_RECOVERY_SHIFT); - } else if (intf_type == controller_kl_ata3) { + break; + case controller_kl_ata3: /* 33Mhz cell on KeyLargo */ accessTicks = SYSCLK_TICKS(accessTime); accessTicks = max(accessTicks, 1U); @@ -614,7 +784,8 @@ *timings = ((*timings) & ~TR_33_MDMA_MASK) | (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | (recTicks << TR_33_MDMA_RECOVERY_SHIFT); - } else { + break; + default: { /* 33Mhz cell on others */ int halfTick = 0; int origAccessTime = accessTime; @@ -639,6 +810,7 @@ (recTicks << TR_33_MDMA_RECOVERY_SHIFT); if (halfTick) *timings |= TR_33_MDMA_HALFTICK; + } } #ifdef IDE_PMAC_DEBUG printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", @@ -654,34 +826,40 @@ static int __pmac pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) { - int intf = pmac_ide_find(drive); - int unit = (drive->select.b.unit & 0x01); - int ret = 0; - u32 *timings; + int unit = (drive->select.b.unit & 0x01); + int ret = 0; + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; + u32 *timings, *timings2; - if (intf < 0) + if (pmif == NULL) return 1; - timings = &pmac_ide[intf].timings[unit]; + timings = &pmif->timings[unit]; + timings2 = &pmif->timings[unit+2]; switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + case XFER_UDMA_5: + if (pmif->kind != controller_un_ata6) + return 1; case XFER_UDMA_4: case XFER_UDMA_3: - if (pmac_ide[intf].kind != controller_kl_ata4_80) + if (HWIF(drive)->udma_four == 0) return 1; case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: - if (pmac_ide[intf].kind != controller_kl_ata4 && - pmac_ide[intf].kind != controller_kl_ata4_80) - return 1; - ret = set_timings_udma(timings, speed); + if (pmif->kind == controller_kl_ata4) + ret = set_timings_udma_ata4(timings, speed); + else if (pmif->kind == controller_un_ata6) + ret = set_timings_udma_ata6(timings, timings2, speed); + else + ret = 1; break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: - ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0); + ret = set_timings_mdma(pmif->kind, timings, timings2, speed, 0); break; case XFER_SW_DMA_2: case XFER_SW_DMA_1: @@ -705,20 +883,23 @@ if (ret) return ret; - pmac_ide_selectproc(drive); + pmac_ide_do_update_timings(drive); drive->current_speed = speed; return 0; } static void __pmac -sanitize_timings(int i) +sanitize_timings(pmac_ide_hwif_t *pmif) { - unsigned value; + unsigned int value, value2 = 0; - switch(pmac_ide[i].kind) { + switch(pmif->kind) { + case controller_un_ata6: + value = 0x08618a92; + value2 = 0x00002921; + break; case controller_kl_ata4: - case controller_kl_ata4_80: value = 0x0008438c; break; case controller_kl_ata3: @@ -730,7 +911,8 @@ value = 0x00074526; break; } - pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value; + pmif->timings[0] = pmif->timings[1] = value; + pmif->timings[2] = pmif->timings[3] = value2; } ide_ioreg_t __pmac @@ -750,6 +932,17 @@ return -1; } +struct device_node* +pmac_ide_get_of_node(int index) +{ + /* Don't access the pmac_ide array on non-pmac */ + if (pmac_ide_count == 0) + return NULL; + if (pmac_ide[index].regbase == 0) + return NULL; + return pmac_ide[index].node; +} + int __pmac pmac_ide_get_irq(ide_ioreg_t base) { @@ -792,7 +985,7 @@ int i; struct device_node *atas; struct device_node *p, **pp, *removables, **rp; - unsigned long base; + unsigned long base, regbase; int irq, big_delay; ide_hwif_t *hwif; @@ -825,7 +1018,7 @@ for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) { struct device_node *tp; - struct pmac_ide_hwif* pmhw; + struct pmac_ide_hwif* pmif; int *bidp; int in_bay = 0; u8 pbus, pid; @@ -833,29 +1026,88 @@ /* * If this node is not under a mac-io or dbdma node, - * leave it to the generic PCI driver. + * leave it to the generic PCI driver. Except for U2's + * Kauai ATA */ - for (tp = np->parent; tp != 0; tp = tp->parent) - if (tp->type && (strcmp(tp->type, "mac-io") == 0 - || strcmp(tp->type, "dbdma") == 0)) - break; - if (tp == 0) - continue; + if (!device_is_compatible(np, "kauai-ata")) { + for (tp = np->parent; tp != 0; tp = tp->parent) + if (tp->type && (strcmp(tp->type, "mac-io") == 0 + || strcmp(tp->type, "dbdma") == 0)) + break; + if (tp == 0) + continue; - if (np->n_addrs == 0) { - printk(KERN_WARNING "ide: no address for device %s\n", - np->full_name); - continue; - } + if (np->n_addrs == 0) { + printk(KERN_WARNING "ide-pmac: no address for device %s\n", + np->full_name); + continue; + } + /* We need to find the pci_dev of the mac-io holding the + * IDE interface + */ + if (pci_device_from_OF_node(tp, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + if (pdev == NULL) + printk(KERN_WARNING "ide-pmac: no PCI host for device %s, DMA disabled\n", + np->full_name); + /* + * Some older OFs have bogus sizes, causing request_OF_resource + * to fail. We fix them up here + */ + if (np->addrs[0].size > 0x1000) + np->addrs[0].size = 0x1000; + if (np->n_addrs > 1 && np->addrs[1].size > 0x100) + np->addrs[1].size = 0x100; - /* We need to find the pci_dev of the mac-io holding the - * IDE interface - */ - if (pci_device_from_OF_node(tp, &pbus, &pid) == 0) - pdev = pci_find_slot(pbus, pid); - if (pdev == NULL) - printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n", - np->full_name); + if (request_OF_resource(np, 0, " (mac-io IDE IO)") == NULL) { + printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name); + continue; + } + + base = (unsigned long) ioremap(np->addrs[0].address, 0x400); + regbase = base - _IO_BASE; + + /* XXX This is bogus. Should be fixed in the registry by checking + the kind of host interrupt controller, a bit like gatwick + fixes in irq.c + */ + if (np->n_intrs == 0) { + printk(KERN_WARNING "ide-pmac: no intrs for device %s, using 13\n", + np->full_name); + irq = 13; + } else { + irq = np->intrs[0].line; + } + } else { + unsigned long rbase, rlen; + + if (pci_device_from_OF_node(np, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + if (pdev == NULL) { + printk(KERN_WARNING "ide-pmac: no PCI host for device %s, skipping\n", + np->full_name); + continue; + } + if (pci_enable_device(pdev)) { + printk(KERN_WARNING "ide-pmac: Can't enable PCI device for %s, skipping\n", + np->full_name); + continue; + } + pci_set_master(pdev); + + if (pci_request_regions(pdev, "U2 IDE")) { + printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources\n"); + continue; + } + + rbase = pci_resource_start(pdev, 0); + rlen = pci_resource_len(pdev, 0); + + base = (unsigned long) ioremap(rbase, rlen); + regbase = base + 0x2000 - _IO_BASE; + + irq = pdev->irq; + } /* * If this slot is taken (e.g. by ide-pci.c) try the next one. @@ -865,69 +1117,48 @@ ++i; if (i >= MAX_HWIFS) break; - pmhw = &pmac_ide[i]; - - /* - * Some older OFs have bogus sizes, causing request_OF_resource - * to fail. We fix them up here - */ - if (np->addrs[0].size > 0x1000) - np->addrs[0].size = 0x1000; - if (np->n_addrs > 1 && np->addrs[1].size > 0x100) - np->addrs[1].size = 0x100; - - if (request_OF_resource(np, 0, " (mac-io IDE IO)") == NULL) { - printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name); - continue; - } - - base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE; + pmif = &pmac_ide[i]; - /* XXX This is bogus. Should be fixed in the registry by checking - the kind of host interrupt controller, a bit like gatwick - fixes in irq.c - */ - if (np->n_intrs == 0) { - printk(KERN_WARNING "ide: no intrs for device %s, using 13\n", - np->full_name); - irq = 13; - } else { - irq = np->intrs[0].line; - } - pmhw->regbase = base; - pmhw->irq = irq; - pmhw->node = np; - if (device_is_compatible(np, "keylargo-ata")) { + pmif->mapbase = base; + pmif->regbase = regbase; + pmif->irq = irq; + pmif->node = np; + pmif->cable_80 = 0; + if (device_is_compatible(np, "kauai-ata")) { + pmif->kind = controller_un_ata6; + pci_set_drvdata(pdev, pmif); + } else if (device_is_compatible(np, "keylargo-ata")) { if (strcmp(np->name, "ata-4") == 0) - pmhw->kind = controller_kl_ata4; + pmif->kind = controller_kl_ata4; else - pmhw->kind = controller_kl_ata3; + pmif->kind = controller_kl_ata3; } else if (device_is_compatible(np, "heathrow-ata")) - pmhw->kind = controller_heathrow; + pmif->kind = controller_heathrow; else - pmhw->kind = controller_ohare; + pmif->kind = controller_ohare; bidp = (int *)get_property(np, "AAPL,bus-id", NULL); - pmhw->aapl_bus_id = bidp ? *bidp : 0; + pmif->aapl_bus_id = bidp ? *bidp : 0; - if (pmhw->kind == controller_kl_ata4) { + /* Get cable type from device-tree */ + if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6) { char* cable = get_property(np, "cable-type", NULL); if (cable && !strncmp(cable, "80-", 3)) - pmhw->kind = controller_kl_ata4_80; + pmif->cable_80 = 1; } /* Make sure we have sane timings */ - sanitize_timings(i); + sanitize_timings(pmif); if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { #ifdef CONFIG_PMAC_PBOOK - media_bay_set_ide_infos(np->parent,base,irq,i); + media_bay_set_ide_infos(np->parent,regbase,irq,i); #endif /* CONFIG_PMAC_PBOOK */ in_bay = 1; if (!bidp) - pmhw->aapl_bus_id = 1; - } else if (pmhw->kind == controller_ohare) { + pmif->aapl_bus_id = 1; + } else if (pmif->kind == controller_ohare) { /* The code below is having trouble on some ohare machines * (timing related ?). Until I can put my hand on one of these * units, I keep the old way @@ -935,31 +1166,35 @@ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); } else { /* This is necessary to enable IDE when net-booting */ - printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n", - pmhw->aapl_bus_id); - ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1); - ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1); + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1); + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1); mdelay(10); - ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0); + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0); big_delay = 1; } hwif = &ide_hwifs[i]; - pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); + hwif->hwif_data = pmif; + pmac_ide_init_hwif_ports(&hwif->hw, regbase, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->chipset = ide_pmac; hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay; - hwif->udma_four = (pmhw->kind == controller_kl_ata4_80); + hwif->udma_four = pmif->cable_80; hwif->pci_dev = pdev; hwif->drives[0].unmask = 1; hwif->drives[1].unmask = 1; + + printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s\n", + i, model_name[pmif->kind], pmif->aapl_bus_id, + in_bay ? " (mediabay)" : ""); + #ifdef CONFIG_PMAC_PBOOK - if (in_bay && check_media_bay_by_base(base, MB_CD) == 0) + if (in_bay && check_media_bay_by_base(regbase, MB_CD) == 0) hwif->noprobe = 0; #endif /* CONFIG_PMAC_PBOOK */ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - if (np->n_addrs >= 2) { + if (np->n_addrs >= 2 || pmif->kind == controller_un_ata6) { /* has a DBDMA controller channel */ pmac_ide_setup_dma(np, i); } @@ -968,6 +1203,9 @@ ++i; } pmac_ide_count = i; + if (pmac_ide_count == 0) + return; + if (big_delay) mdelay(IDE_WAKEUP_DELAY_MS); @@ -984,14 +1222,18 @@ { struct pmac_ide_hwif *pmif = &pmac_ide[ix]; - if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) { - printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name); - return; - } - - pmif->dma_regs = - (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200); + if (pmif->kind == controller_un_ata6) { + pmif->dma_regs = (volatile struct dbdma_regs*)(pmif->mapbase + 0x1000); + } else { + if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) { + printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name); + return; + } + pmif->dma_regs = + (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200); + } + /* * Allocate space for the DBDMA commands. * The +2 is +1 for the stop command and +1 to allow for @@ -1023,10 +1265,9 @@ } static int -pmac_ide_build_sglist (int ix, struct request *rq) +pmac_ide_build_sglist(ide_hwif_t *hwif, struct request *rq) { - ide_hwif_t *hwif = &ide_hwifs[ix]; - struct pmac_ide_hwif *pmif = &pmac_ide[ix]; + pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data; struct buffer_head *bh; struct scatterlist *sg = pmif->sg_table; unsigned long lastdataend = ~0UL; @@ -1043,16 +1284,29 @@ bh = rq->bh; do { struct scatterlist *sge; - unsigned int size = bh->b_size; + int contig = 0; - /* continue segment from before? */ - if (bh_phys(bh) == lastdataend) { - sg[nents-1].length += size; - lastdataend += size; + if (bh->b_page) { + if (bh_phys(bh) == lastdataend) + contig = 1; + } else { + if ((unsigned long) bh->b_data == lastdataend) + contig = 1; + } + + + /* + * continue segment from before? + */ + if (contig) { + sg[nents - 1].length += bh->b_size; + lastdataend += bh->b_size; continue; } - /* start new segment */ + /* + * start new segment + */ if (nents >= MAX_DCMDS) return 0; @@ -1062,13 +1316,16 @@ if (bh->b_page) { sge->page = bh->b_page; sge->offset = bh_offset(bh); + lastdataend = bh_phys(bh) + bh->b_size; } else { - if ((unsigned long)bh->b_data < PAGE_SIZE) + if ((unsigned long) bh->b_data < PAGE_SIZE) BUG(); + sge->address = bh->b_data; + lastdataend = (unsigned long) bh->b_data + bh->b_size; } - sge->length = size; - lastdataend = bh_phys(bh) + size; + + sge->length = bh->b_size; nents++; } while ((bh = bh->b_reqnext) != NULL); @@ -1076,10 +1333,9 @@ } static int -pmac_ide_raw_build_sglist (int ix, struct request *rq) +pmac_ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq) { - ide_hwif_t *hwif = &ide_hwifs[ix]; - struct pmac_ide_hwif *pmif = &pmac_ide[ix]; + pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data; struct scatterlist *sg = hwif->sg_table; int nents = 0; ide_task_t *args = rq->special; @@ -1114,16 +1370,18 @@ * for a transfer and sets the DBDMA channel to point to it. */ static int -pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr) +pmac_ide_build_dmatable(ide_drive_t *drive, int wr) { struct dbdma_cmd *table; int i, count = 0; struct request *rq = HWGROUP(drive)->rq; - volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs; + ide_hwif_t *hwif = HWIF(drive); + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; + volatile struct dbdma_regs *dma = pmif->dma_regs; struct scatterlist *sg; /* DMA table is already aligned */ - table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu; + table = (struct dbdma_cmd *) pmif->dma_table_cpu; /* Make sure DMA controller is stopped (necessary ?) */ out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); @@ -1132,14 +1390,14 @@ /* Build sglist */ if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) - pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq); + pmif->sg_nents = i = pmac_ide_raw_build_sglist(hwif, rq); else - pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq); + pmif->sg_nents = i = pmac_ide_build_sglist(hwif, rq); if (!i) return 0; /* Build DBDMA commands list */ - sg = pmac_ide[ix].sg_table; + sg = pmif->sg_table; while (i) { u32 cur_addr; u32 cur_len; @@ -1178,82 +1436,42 @@ /* add the stop command to the end of the list */ memset(table, 0, sizeof(struct dbdma_cmd)); out_le16(&table->command, DBDMA_STOP); - - out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma); + io_barrier(); + + out_le32(&dma->cmdptr, pmif->dma_table_dma); return 1; } /* Teardown mappings after DMA has completed. */ static void -pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix) +pmac_ide_destroy_dmatable (ide_drive_t *drive) { struct pci_dev *dev = HWIF(drive)->pci_dev; - struct scatterlist *sg = pmac_ide[ix].sg_table; - int nents = pmac_ide[ix].sg_nents; + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; + struct scatterlist *sg = pmif->sg_table; + int nents = pmif->sg_nents; if (nents) { - pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction); - pmac_ide[ix].sg_nents = 0; + pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction); + pmif->sg_nents = 0; } } -static __inline__ unsigned char -dma_bits_to_command(unsigned char bits) -{ - if(bits & 0x04) - return XFER_MW_DMA_2; - if(bits & 0x02) - return XFER_MW_DMA_1; - if(bits & 0x01) - return XFER_MW_DMA_0; - return 0; -} - -static __inline__ unsigned char -udma_bits_to_command(unsigned char bits, int high_speed) -{ - if (high_speed) { - if(bits & 0x10) - return XFER_UDMA_4; - if(bits & 0x08) - return XFER_UDMA_3; - } - if(bits & 0x04) - return XFER_UDMA_2; - if(bits & 0x02) - return XFER_UDMA_1; - if(bits & 0x01) - return XFER_UDMA_0; - return 0; -} - /* Calculate MultiWord DMA timings */ static int __pmac -pmac_ide_mdma_enable(ide_drive_t *drive, int idx) +pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode) { - byte bits = drive->id->dma_mword & 0x07; - byte feature = dma_bits_to_command(bits); - u32 *timings; + ide_hwif_t *hwif = HWIF(drive); + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; int drive_cycle_time; struct hd_driveid *id = drive->id; + u32 *timings, *timings2; + u32 timing_local[2]; int ret; - /* Set feature on drive */ - printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf); - ret = pmac_ide_do_setfeature(drive, feature); - if (ret) { - printk(KERN_WARNING "%s: Failed !\n", drive->name); - return 0; - } - - if (!drive->init_speed) - drive->init_speed = feature; - /* which drive is it ? */ - if (drive->select.b.unit & 0x01) - timings = &pmac_ide[idx].timings[1]; - else - timings = &pmac_ide[idx].timings[0]; + timings = &pmif->timings[drive->select.b.unit & 0x01]; + timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2]; /* Check if drive provide explicit cycle time */ if ((id->field_valid & 2) && (id->eide_dma_time)) @@ -1261,58 +1479,97 @@ else drive_cycle_time = 0; + /* Copy timings to local image */ + timing_local[0] = *timings; + timing_local[1] = *timings2; + /* Calculate controller timings */ - set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time); + ret = set_timings_mdma( pmif->kind, + &timing_local[0], + &timing_local[1], + mode, + drive_cycle_time); + if (ret) + return 0; + + /* Set feature on drive */ + printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf); + ret = pmac_ide_do_setfeature(drive, mode); + if (ret) { + printk(KERN_WARNING "%s: Failed !\n", drive->name); + return 0; + } + + /* Apply timings to controller */ + *timings = timing_local[0]; + *timings2 = timing_local[1]; + + /* Set speed info in drive */ + drive->current_speed = mode; + if (!drive->init_speed) + drive->init_speed = mode; - drive->current_speed = feature; return 1; } /* Calculate Ultra DMA timings */ static int __pmac -pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed) +pmac_ide_udma_enable(ide_drive_t *drive, u16 mode) { - byte bits = drive->id->dma_ultra & 0x1f; - byte feature = udma_bits_to_command(bits, high_speed); - u32 *timings; + ide_hwif_t *hwif = HWIF(drive); + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; + u32 *timings, *timings2; + u32 timing_local[2]; int ret; + + /* which drive is it ? */ + timings = &pmif->timings[drive->select.b.unit & 0x01]; + timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2]; + /* Copy timings to local image */ + timing_local[0] = *timings; + timing_local[1] = *timings2; + + /* Calculate timings for interface */ + if (pmif->kind == controller_un_ata6) + ret = set_timings_udma_ata6( &timing_local[0], + &timing_local[1], + mode); + else + ret = set_timings_udma_ata4(&timing_local[0], mode); + if (ret) + return 0; + /* Set feature on drive */ - printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); - ret = pmac_ide_do_setfeature(drive, feature); + printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f); + ret = pmac_ide_do_setfeature(drive, mode); if (ret) { printk(KERN_WARNING "%s: Failed !\n", drive->name); return 0; } - if (!drive->init_speed) - drive->init_speed = feature; + /* Apply timings to controller */ + *timings = timing_local[0]; + *timings2 = timing_local[1]; - /* which drive is it ? */ - if (drive->select.b.unit & 0x01) - timings = &pmac_ide[idx].timings[1]; - else - timings = &pmac_ide[idx].timings[0]; - - set_timings_udma(timings, feature); + /* Set speed info in drive */ + drive->current_speed = mode; + if (!drive->init_speed) + drive->init_speed = mode; - drive->current_speed = feature; return 1; } static int __pmac pmac_ide_check_dma(ide_drive_t *drive) { - int ata4, udma, idx; struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; int enable = 1; - + int map; drive->using_dma = 0; - idx = pmac_ide_find(drive); - if (idx < 0) - return 0; - if (drive->media == ide_floppy) enable = 0; if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE)) @@ -1320,24 +1577,26 @@ if (check_drive_lists(drive, BAD_DMA_DRIVE)) enable = 0; - udma = 0; - ata4 = (pmac_ide[idx].kind == controller_kl_ata4 || - pmac_ide[idx].kind == controller_kl_ata4_80); - - if(enable) { - if (ata4 && (drive->media == ide_disk) && - (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) { - /* UltraDMA modes. */ - drive->using_dma = pmac_ide_udma_enable(drive, idx, - pmac_ide[idx].kind == controller_kl_ata4_80); - } - if (!drive->using_dma && (id->dma_mword & 0x0007)) { - /* Normal MultiWord DMA modes. */ - drive->using_dma = pmac_ide_mdma_enable(drive, idx); + if (enable) { + short mode; + + map = XFER_MWDMA; + if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6) { + map |= XFER_UDMA; + if (pmif->cable_80) { + map |= XFER_UDMA_66; + if (pmif->kind == controller_un_ata6) + map |= XFER_UDMA_100; + } } + mode = ide_find_best_mode(drive, map); + if (mode & XFER_UDMA) + drive->using_dma = pmac_ide_udma_enable(drive, mode); + else if (mode & XFER_MWDMA) + drive->using_dma = pmac_ide_mdma_enable(drive, mode); OUT_BYTE(0, IDE_CONTROL_REG); /* Apply settings to controller */ - pmac_ide_selectproc(drive); + pmac_ide_do_update_timings(drive); } return 0; } @@ -1362,22 +1621,16 @@ static int __pmac pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - int ix, dstat; + int dstat; volatile struct dbdma_regs *dma; + ide_hwif_t *hwif = HWIF(drive); + pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; byte unit = (drive->select.b.unit & 0x01); byte ata4; int reading = 0; - /* Can we stuff a pointer to our intf structure in config_data - * or select_data in hwif ? - */ - ix = pmac_ide_find(drive); - if (ix < 0) - return 0; - dma = pmac_ide[ix].dma_regs; - ata4 = (pmac_ide[ix].kind == controller_kl_ata4 || - pmac_ide[ix].kind == controller_kl_ata4_80); - + dma = pmif->dma_regs; + ata4 = (pmif->kind == controller_kl_ata4); switch (func) { case ide_dma_off: printk(KERN_INFO "%s: DMA disabled\n", drive->name); @@ -1394,13 +1647,13 @@ case ide_dma_read: reading = 1; case ide_dma_write: - SELECT_READ_WRITE(HWIF(drive),drive,func); - if (!pmac_ide_build_dmatable(drive, ix, !reading)) + SELECT_READ_WRITE(hwif,drive,func); + if (!pmac_ide_build_dmatable(drive, !reading)) return 1; /* Apple adds 60ns to wrDataSetup on reads */ - if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) { + if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE), - pmac_ide[ix].timings[unit] + + pmif->timings[unit] + (reading ? 0x00800000UL : 0)); (void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE)); } @@ -1426,7 +1679,7 @@ drive->waiting_for_dma = 0; dstat = in_le32(&dma->status); out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16)); - pmac_ide_destroy_dmatable(drive, ix); + pmac_ide_destroy_dmatable(drive); /* verify good dma status */ return (dstat & (RUN|DEAD|ACTIVE)) != RUN; case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ @@ -1458,14 +1711,14 @@ return 1; if (!drive->waiting_for_dma) printk(KERN_WARNING "ide%d, ide_dma_test_irq \ - called while not waiting\n", ix); + called while not waiting\n", hwif->index); /* If dbdma didn't execute the STOP command yet, the * active bit is still set */ drive->waiting_for_dma++; if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) { printk(KERN_WARNING "ide%d, timeout waiting \ - for dbdma command stop\n", ix); + for dbdma command stop\n", hwif->index); return 1; } udelay(1); @@ -1508,8 +1761,8 @@ outb(0x0, base+0x20); outb(0x0, base+0x40); outb(0x0, base+0x50); + outb(drive->ctl | 2, base+0x160); outb(0xe0, base+0x70); - outb(0x2, base+0x160); for (j = 0; j < 10; j++) { int status; mdelay(100); @@ -1619,7 +1872,7 @@ int j; /* Reset timings */ - pmac_ide_selectproc(drive); + pmac_ide_do_update_timings(drive); mdelay(10); /* Wait up to 20 seconds for the drive to be ready */ @@ -1698,7 +1951,7 @@ continue; /* Make sure we have sane timings */ - sanitize_timings(i); + sanitize_timings(&pmac_ide[i]); /* Check if this is a media bay with an IDE device or not * a media bay diff -uNr linux-2.4.20/drivers/ide/ide-probe.c linux-2.4.20-ben6/drivers/ide/ide-probe.c --- linux-2.4.20/drivers/ide/ide-probe.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/ide/ide-probe.c 2003-02-16 20:19:52.000000000 +0100 @@ -260,12 +260,22 @@ int retval; int autoprobe = 0; unsigned long cookie = 0; + ide_hwif_t *hwif = HWIF(drive); + int irqdefense = 0; - if (IDE_CONTROL_REG && !HWIF(drive)->irq) { + if (IDE_CONTROL_REG && !hwif->irq) { autoprobe = 1; cookie = probe_irq_on(); OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ } +#ifdef CONFIG_IDEPCI_SHARE_IRQ + if (hwif->irq && IDE_CHIPSET_IS_PCI(hwif->chipset)) { + OUT_BYTE(drive->ctl|2, IDE_CONTROL_REG); /* mask device irq */ + printk(KERN_WARNING "disabling irq %d defensively\n", hwif->irq); + disable_irq(hwif->irq); + irqdefense = 1; + } +#endif CONFIG_IDEPCI_SHARE_IRQ retval = actual_try_to_identify(drive, cmd); @@ -291,6 +301,12 @@ } } } + +#ifdef CONFIG_IDEPCI_SHARE_IRQ + if (irqdefense) + enable_irq(hwif->irq); +#endif CONFIG_IDEPCI_SHARE_IRQ + return retval; } @@ -493,6 +509,68 @@ } /* + * This function waits for the hwif to report a non-busy status + * see comments in probe_hwif() + */ +static int wait_not_busy(ide_hwif_t *hwif, unsigned long timeout) +{ + u8 stat = 0; + + while(timeout--) { + /* Turn this into a schedule() sleep once I'm sure + * about locking issues (2.5 work ?) + */ + mdelay(1); + stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); + if ((stat & BUSY_STAT) == 0) + break; + /* Assume a value of 0xff means nothing is connected to + * the interface and it doesn't implement the pull-down + * resistor on D7 + */ + if (stat == 0xff) + break; + } + return ((stat & BUSY_STAT) == 0) ? 0 : -EBUSY; +} + +static int wait_hwif_ready(ide_hwif_t *hwif) +{ + int rc; + + printk("Probing IDE interface %s...\n", hwif->name); + + /* Let HW settle down a bit from whatever init state we + * come from */ + mdelay(2); + + /* Wait for BSY bit to go away, spec timeout is 30 seconds, + * I know of at least one disk who takes 31 seconds, I use 35 + * here to be safe + */ + rc = wait_not_busy(hwif, 35000); + if (rc) + return rc; + + /* Now make sure both master & slave are ready */ + SELECT_DRIVE(hwif, &hwif->drives[0]); + OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]); + mdelay(2); + rc = wait_not_busy(hwif, 10000); + if (rc) + return rc; + SELECT_DRIVE(hwif, &hwif->drives[1]); + OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]); + mdelay(2); + rc = wait_not_busy(hwif, 10000); + + /* Exit function with master reselected (let's be sane) */ + SELECT_DRIVE(hwif, &hwif->drives[0]); + + return rc; +} + +/* * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. */ @@ -532,6 +610,29 @@ __save_flags(flags); /* local CPU only */ __sti(); /* local CPU only; needed for jiffies and irq probing */ + + /* This is needed on some PPCs and a bunch of BIOS-less embedded + * platforms. Typical cases are: + * + * - The firmware hard reset the disk before booting the kernel, + * the drive is still doing it's poweron-reset sequence, that + * can take up to 30 seconds + * - The firmware does nothing (or no firmware), the device is + * still in POST state (same as above actually). + * - Some CD/DVD/Writer combo drives tend to drive the bus during + * their reset sequence even when they are non-selected slave + * devices, thus preventing discovery of the main HD + * + * Doing this wait-for-busy should not harm any existing configuration + * (at least things won't be worse than what current code does, that + * is blindly go & talk to the drive) and fix some issues like the + * above. + * + * BenH. + */ + if (wait_hwif_ready(hwif)) + printk(KERN_WARNING "%s: Wait for ready failed before probe !\n", hwif->name); + /* * Second drive should only exist if first drive was found, * but a lot of cdrom drives are configured as single slaves. diff -uNr linux-2.4.20/drivers/ide/ide-proc.c linux-2.4.20-ben6/drivers/ide/ide-proc.c --- linux-2.4.20/drivers/ide/ide-proc.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/ide/ide-proc.c 2003-02-16 20:21:21.000000000 +0100 @@ -70,6 +70,11 @@ #include +#ifdef CONFIG_ALL_PPC +#include +#include +#endif + #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif @@ -414,13 +419,35 @@ case ide_cmd646: name = "cmd646"; break; case ide_cy82c693: name = "cy82c693"; break; case ide_4drives: name = "4drives"; break; - case ide_pmac: name = "mac-io"; break; + case ide_pmac: name = "pmac"; break; default: name = "(unknown)"; break; } len = sprintf(page, "%s\n", name); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +#ifdef CONFIG_ALL_PPC +static int proc_ide_read_devspec + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_hwif_t *hwif = (ide_hwif_t *) data; + int len; + struct device_node *ofnode = NULL; + +#ifdef CONFIG_BLK_DEV_IDE_PMAC + extern struct device_node* pmac_ide_get_of_node(int index); + if (hwif->chipset == ide_pmac) + ofnode = pmac_ide_get_of_node(hwif->index); +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#ifdef CONFIG_PCI + if (ofnode == NULL && hwif->pci_dev) + ofnode = pci_device_to_OF_node(hwif->pci_dev); +#endif /* CONFIG_PCI */ + len = sprintf(page, "%s\n", ofnode ? ofnode->full_name : ""); + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} +#endif /* CONFIG_ALL_PPC */ + static int proc_ide_read_mate (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -801,6 +828,9 @@ { "config", S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config, proc_ide_write_config }, { "mate", S_IFREG|S_IRUGO, proc_ide_read_mate, NULL }, { "model", S_IFREG|S_IRUGO, proc_ide_read_imodel, NULL }, +#ifdef CONFIG_ALL_PPC + { "devspec", S_IFREG|S_IRUGO, proc_ide_read_devspec, NULL }, +#endif { NULL, 0, NULL, NULL } }; diff -uNr linux-2.4.20/drivers/ide/ide.c linux-2.4.20-ben6/drivers/ide/ide.c --- linux-2.4.20/drivers/ide/ide.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/ide/ide.c 2003-02-16 20:19:52.000000000 +0100 @@ -1049,6 +1049,9 @@ struct request *rq; byte err; +#ifdef CONFIG_BLK_DEV_PDC202XX + extern int pdc202xx_marvell_idle (ide_drive_t *);/* needed below -- Promise */ +#endif err = ide_dump_status(drive, msg, stat); if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; @@ -1083,9 +1086,15 @@ if ((stat & DRQ_STAT) && rq->cmd != WRITE) try_to_flush_leftover_data(drive); } - if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) - OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); /* force an abort */ - + if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) { +#ifdef CONFIG_BLK_DEV_PDC202XX + /* Give a breath for Idle Immediate by Promise */ + if (HWIF(drive)->pci_devid.vid == PCI_VENDOR_ID_PROMISE) + pdc202xx_marvell_idle(drive); + else +#endif + OUT_BYTE(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG); /* force an abort */ + } if (rq->errors >= ERROR_MAX) { if (drive->driver != NULL) DRIVER(drive)->end_request(0, HWGROUP(drive)); @@ -2420,6 +2429,7 @@ hw->irq = irq; hw->dma = NO_DMA; hw->ack_intr = ack_intr; + hw->chipset = ide_generic; } /* @@ -2481,6 +2491,7 @@ hw_regs_t hw; ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL); hw.irq = irq; + hw.chipset = ide_unknown; return ide_register_hw(&hw, NULL); } diff -uNr linux-2.4.20/drivers/ide/pdc202xx.c linux-2.4.20-ben6/drivers/ide/pdc202xx.c --- linux-2.4.20/drivers/ide/pdc202xx.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/ide/pdc202xx.c 2003-02-16 20:20:13.000000000 +0100 @@ -68,13 +68,20 @@ #include #include +#ifdef CONFIG_ALL_PPC +#include +#include +#include +#include +#endif + #include #include #include "ide_modes.h" -#define PDC202XX_DEBUG_DRIVE_INFO 0 -#define PDC202XX_DECODE_REGISTER_INFO 0 +#define PDC202XX_DEBUG_DRIVE_INFO 1 +#define PDC202XX_DECODE_REGISTER_INFO 1 #define DISPLAY_PDC202XX_TIMINGS @@ -82,6 +89,9 @@ #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif +#define OUT_LONG(l,p) outl((l),(p)) +#define IN_LONG(p) inl(p) + #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) #include #include @@ -89,9 +99,46 @@ static int pdc202xx_get_info(char *, char **, off_t, int); extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ extern char *ide_media_verbose(ide_drive_t *); -static struct pci_dev *bmide_dev; -static struct hd_driveid *id[4]; -static int speed_rate[4]; + +#define PDC202_MAX_DEVS 5 + +static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS]; +static int n_pdc202_devs; + +char *pdc202xx_pio_verbose (u32 drive_pci) +{ + if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET"); + if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4"); + if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3"); + if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2"); + if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1"); + if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0"); + return("PIO ?"); +} + +char *pdc202xx_dma_verbose (u32 drive_pci) +{ + if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2"); + if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1"); + if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0"); + if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2"); + if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1"); + if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0"); + return("PIO---"); +} + +char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable) +{ + if ((drive_pci & 0x000ff000) == 0x000ff000) + return("NOTSET"); + if ((drive_pci & 0x00012000) == 0x00012000) + return((slow_cable) ? "UDMA 2" : "UDMA 4"); + if ((drive_pci & 0x00024000) == 0x00024000) + return((slow_cable) ? "UDMA 1" : "UDMA 3"); + if ((drive_pci & 0x00036000) == 0x00036000) + return("UDMA 0"); + return(pdc202xx_dma_verbose(drive_pci)); +} static char * pdc202xx_info (char *buf, struct pci_dev *dev) { @@ -99,10 +146,8 @@ u32 bibma = pci_resource_start(dev, 4); u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; - u16 reg50h = 0; - u16 word88 = 0; - int udmasel[4] = {0,0,0,0}, piosel[4] = {0,0,0,0}; - int i = 0, hd = 0; + u16 reg50h = 0, pmask = (1<<10), smask = (1<<11); + u8 hi = 0, lo = 0; /* * at that point bibma+0x2 et bibma+0xa are byte registers @@ -114,10 +159,10 @@ u8 sc11 = inb_p((unsigned short)bibma + 0x11); u8 sc1a = inb_p((unsigned short)bibma + 0x1a); u8 sc1b = inb_p((unsigned short)bibma + 0x1b); - /* u8 sc1c = inb_p((unsigned short)bibma + 0x1c); + u8 sc1c = inb_p((unsigned short)bibma + 0x1c); u8 sc1d = inb_p((unsigned short)bibma + 0x1d); u8 sc1e = inb_p((unsigned short)bibma + 0x1e); - u8 sc1f = inb_p((unsigned short)bibma + 0x1f); */ + u8 sc1f = inb_p((unsigned short)bibma + 0x1f); pci_read_config_word(dev, 0x50, ®50h); pci_read_config_dword(dev, 0x60, ®60h); @@ -125,75 +170,141 @@ pci_read_config_dword(dev, 0x68, ®68h); pci_read_config_dword(dev, 0x6c, ®6ch); - p+=sprintf(p, "\nPROMISE Ultra series driver Ver %s %s Adapter: ", VERSION, VERDATE); + p += sprintf(p, "\n "); switch(dev->device) { - case PCI_DEVICE_ID_PROMISE_20275: - p += sprintf(p, "MBUltra133\n"); - break; - case PCI_DEVICE_ID_PROMISE_20269: - p += sprintf(p, "Ultra133 TX2\n"); - break; - case PCI_DEVICE_ID_PROMISE_20268: - p += sprintf(p, "Ultra100 TX2\n"); - break; case PCI_DEVICE_ID_PROMISE_20267: - p += sprintf(p, "Ultra100\n"); - break; + p += sprintf(p, "Ultra100"); break; case PCI_DEVICE_ID_PROMISE_20265: - p += sprintf(p, "Ultra100 on M/B\n"); - break; + p += sprintf(p, "Ultra100 on M/B"); break; + case PCI_DEVICE_ID_PROMISE_20263: + p += sprintf(p, "FastTrak 66"); break; case PCI_DEVICE_ID_PROMISE_20262: - p += sprintf(p, "Ultra66\n"); - break; + p += sprintf(p, "Ultra66"); break; case PCI_DEVICE_ID_PROMISE_20246: - p += sprintf(p, "Ultra33\n"); + p += sprintf(p, "Ultra33"); reg50h |= 0x0c00; break; default: - p += sprintf(p, "Ultra Series\n"); - break; + p += sprintf(p, "Ultra Series"); break; } + p += sprintf(p, " Chipset.\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, "------------------------------- General Status " + "---------------------------------\n"); + p += sprintf(p, "Burst Mode : %sabled\n", + (sc1f & 0x01) ? "en" : "dis"); + p += sprintf(p, "Host Mode : %s\n", + (sc1f & 0x08) ? "Tri-Stated" : "Normal"); + p += sprintf(p, "Bus Clocking : %s\n", + ((sc1f & 0xC0) == 0xC0) ? "100 External" : + ((sc1f & 0x80) == 0x80) ? "66 External" : + ((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal"); + p += sprintf(p, "IO pad select : %s mA\n", + ((sc1c & 0x03) == 0x03) ? "10" : + ((sc1c & 0x02) == 0x02) ? "8" : + ((sc1c & 0x01) == 0x01) ? "6" : + ((sc1c & 0x00) == 0x00) ? "4" : "??"); + SPLIT_BYTE(sc1e, hi, lo); + p += sprintf(p, "Status Polling Period : %d\n", hi); + p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); p += sprintf(p, " %s %s\n", (c0&0x80)?"disabled":"enabled ", (c1&0x80)?"disabled":"enabled "); p += sprintf(p, "66 Clocking %s %s\n", (sc11&0x02)?"enabled ":"disabled", (sc11&0x08)?"enabled ":"disabled"); - p += sprintf(p, "Mode %s %s\n", + p += sprintf(p, " Mode %s Mode %s\n", (sc1a & 0x01) ? "MASTER" : "PCI ", (sc1b & 0x01) ? "MASTER" : "PCI "); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (id[0]!=NULL && (c0&0x20))?"yes":"no ",(id[1]!=NULL && (c0&0x40))?"yes":"no ", - (id[2]!=NULL && (c1&0x20))?"yes":"no ",(id[3]!=NULL && (c1&0x40))?"yes":"no "); - for( hd = 0; hd < 4 ; hd++) { - if (id[hd] == NULL) - continue; - word88 = id[hd]->dma_ultra; - for ( i = 7 ; i >= 0 ; i--) - if (word88 >> (i+8)) { - udmasel[hd] = i; /* get select UDMA mode */ - break; - } - piosel[hd] = (id[hd]->eide_pio_modes >= 0x02) ? 4 : 3; - } - p += sprintf(p, "UDMA Mode: %d %d %d %d\n", - udmasel[0], udmasel[1], udmasel[2], udmasel[3]); - p += sprintf(p, "PIO Mode: %d %d %d %d\n", - piosel[0], piosel[1], piosel[2], piosel[3]); + p += sprintf(p, " %s %s\n", + (sc1d & 0x08) ? "Error " : + ((sc1d & 0x05) == 0x05) ? "Not My INTR " : + (sc1d & 0x04) ? "Interrupting" : + (sc1d & 0x02) ? "FIFO Full " : + (sc1d & 0x01) ? "FIFO Empty " : "????????????", + (sc1d & 0x80) ? "Error " : + ((sc1d & 0x50) == 0x50) ? "Not My INTR " : + (sc1d & 0x40) ? "Interrupting" : + (sc1d & 0x20) ? "FIFO Full " : + (sc1d & 0x10) ? "FIFO Empty " : "????????????"); + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s " + " %s %s\n", + (c0&0x20)?"yes":"no ", (c0&0x40)?"yes":"no ", + (c1&0x20)?"yes":"no ", (c1&0x40)?"yes":"no "); + p += sprintf(p, "DMA Mode: %s %s " + " %s %s\n", + pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)), + pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)), + pdc202xx_ultra_verbose(reg68h, (reg50h & smask)), + pdc202xx_ultra_verbose(reg6ch, (reg50h & smask))); + p += sprintf(p, "PIO Mode: %s %s " + " %s %s\n", + pdc202xx_pio_verbose(reg60h), + pdc202xx_pio_verbose(reg64h), + pdc202xx_pio_verbose(reg68h), + pdc202xx_pio_verbose(reg6ch)); #if 0 p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n"); #endif return (char *)p; } +static char * pdc202xx_info_new (char *buf, struct pci_dev *dev) +{ + char *p = buf; + + p += sprintf(p, "\n "); + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + p += sprintf(p, "SBFastTrak 133 Lite"); break; + case PCI_DEVICE_ID_PROMISE_20276: + p += sprintf(p, "MBFastTrak 133 Lite"); break; + case PCI_DEVICE_ID_PROMISE_20275: + p += sprintf(p, "MBUltra133"); break; + case PCI_DEVICE_ID_PROMISE_20271: + p += sprintf(p, "FastTrak TX2000"); break; + case PCI_DEVICE_ID_PROMISE_20270: + p += sprintf(p, "FastTrak LP/TX2/TX4"); break; + case PCI_DEVICE_ID_PROMISE_20269: + p += sprintf(p, "Ultra133 TX2"); break; + case PCI_DEVICE_ID_PROMISE_20268: + p += sprintf(p, "Ultra100 TX2"); break; + default: + p += sprintf(p, "Ultra series"); break; + break; + } + p += sprintf(p, " Chipset.\n"); + return (char *)p; +} + static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - - p = pdc202xx_info(buffer, bmide_dev); + int i; + + for (i = 0; i < n_pdc202_devs; i++) { + struct pci_dev *dev = pdc202_devs[i]; + + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20270: + p = pdc202xx_info_new(buffer, dev); + break; + default: + p = pdc202xx_info(buffer, dev); + break; + } + } return p-buffer; /* => must be less than 4k! */ } #endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ @@ -324,6 +435,66 @@ #endif /* PDC202XX_DECODE_REGISTER_INFO */ +static byte pdc202xx_ratemask (ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + u8 mode = 0; + + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20269: + mode |= 0x04; + break; + case PCI_DEVICE_ID_PROMISE_20270: + case PCI_DEVICE_ID_PROMISE_20268: + mode |= 0x03; + break; + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + mode |= 0x03; + break; + case PCI_DEVICE_ID_PROMISE_20263: + case PCI_DEVICE_ID_PROMISE_20262: + mode |= 0x02; + break; + case PCI_DEVICE_ID_PROMISE_20246: + mode |= 0x01; + break; + default: + return (mode &= ~0xF8); + } + + if (!eighty_ninty_three(drive) &&(mode)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + u8 mode = pdc202xx_ratemask(drive); + + switch(mode) { + case 0x04: while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + static int check_in_drive_lists (ide_drive_t *drive, const char **list) { struct hd_driveid *id = drive->id; @@ -344,25 +515,19 @@ return 0; } -static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed) +static int pdc202xx_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; + u8 drive_pci = 0x60 + (drive->dn << 2); + u8 speed = pdc202xx_ratefilter(drive, xferspeed); unsigned int drive_conf; - int err = 0, i = 0, j = hwif->channel ? 2 : 0 ; - byte drive_pci, AP, BP, CP, DP; + byte AP, BP, CP, DP; byte TA = 0, TB = 0, TC = 0; - switch (drive->dn) { - case 0: drive_pci = 0x60; break; - case 1: drive_pci = 0x64; break; - case 2: drive_pci = 0x68; break; - case 3: drive_pci = 0x6c; break; - default: return -1; - } - - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return -1; + if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) + return -1; pci_read_config_dword(dev, drive_pci, &drive_conf); pci_read_config_byte(dev, (drive_pci), &AP); @@ -370,59 +535,53 @@ pci_read_config_byte(dev, (drive_pci)|0x02, &CP); pci_read_config_byte(dev, (drive_pci)|0x03, &DP); -#ifdef CONFIG_BLK_DEV_IDEDMA - if (speed >= XFER_SW_DMA_0) { - if ((BP & 0xF0) && (CP & 0x0F)) { - /* clear DMA modes of upper 842 bits of B Register */ - /* clear PIO forced mode upper 1 bit of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - - /* clear DMA modes of lower 8421 bits of C Register */ - pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - } - } else { -#else - { -#endif /* CONFIG_BLK_DEV_IDEDMA */ + if (speed < XFER_SW_DMA_0) { if ((AP & 0x0F) || (BP & 0x07)) { /* clear PIO modes of lower 8421 bits of A Register */ - pci_write_config_byte(dev, (drive_pci), AP & ~0x0F); + pci_write_config_byte(dev, (drive_pci), AP &~0x0F); pci_read_config_byte(dev, (drive_pci), &AP); /* clear PIO modes of lower 421 bits of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07); + pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); } +#ifdef CONFIG_BLK_DEV_IDEDMA + } else { + if ((BP & 0xF0) && (CP & 0x0F)) { + /* clear DMA modes of upper 842 bits of B Register */ + /* clear PIO forced mode upper 1 bit of B Register */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + + /* clear DMA modes of lower 8421 bits of C Register */ + pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + } +#endif /* CONFIG_BLK_DEV_IDEDMA */ } pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - for ( i = 0; i < 2; i++) - if (hwif->drives[i].present) - id[i+j] = hwif->drives[i].id; /* get identify structs */ - switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA /* case XFER_UDMA_6: */ case XFER_UDMA_5: - case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; /* speed 8 == UDMA mode 4 */ - case XFER_UDMA_3: TB = 0x40; TC = 0x02; break; /* speed 7 == UDMA mode 3 */ - case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; /* speed 6 == UDMA mode 2 */ - case XFER_UDMA_1: TB = 0x40; TC = 0x02; break; /* speed 5 == UDMA mode 1 */ - case XFER_UDMA_0: TB = 0x60; TC = 0x03; break; /* speed 4 == UDMA mode 0 */ - case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break; /* speed 4 == MDMA mode 2 */ - case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break; /* speed 3 == MDMA mode 1 */ - case XFER_MW_DMA_0: TB = 0x60; TC = 0x05; break; /* speed 2 == MDMA mode 0 */ - case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break; /* speed 0 == SDMA mode 2 */ - case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break; /* speed 1 == SDMA mode 1 */ - case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break; /* speed 0 == SDMA mode 0 */ + case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; + case XFER_UDMA_3: TB = 0x40; TC = 0x02; break; + case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; + case XFER_UDMA_1: TB = 0x40; TC = 0x02; break; + case XFER_UDMA_0: TB = 0x60; TC = 0x03; break; + case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break; + case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break; + case XFER_MW_DMA_0: TB = 0x60; TC = 0x05; break; + case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break; + case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break; + case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break; #endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: TA = 0x01; TB = 0x04; break; case XFER_PIO_3: TA = 0x02; TB = 0x06; break; @@ -432,16 +591,14 @@ default: TA = 0x09; TB = 0x13; break; } + if (speed < XFER_SW_DMA_0) { + pci_write_config_byte(dev, (drive_pci), AP|TA); + pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); #ifdef CONFIG_BLK_DEV_IDEDMA - if (speed >= XFER_SW_DMA_0) { + } else { pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); - } else { -#else - { #endif /* CONFIG_BLK_DEV_IDEDMA */ - pci_write_config_byte(dev, (drive_pci), AP|TA); - pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); } #if PDC202XX_DECODE_REGISTER_INFO @@ -455,12 +612,6 @@ decode_registers(REG_C, CP); decode_registers(REG_D, DP); #endif /* PDC202XX_DECODE_REGISTER_INFO */ - - if (!drive->init_speed) - drive->init_speed = speed; - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - #if PDC202XX_DEBUG_DRIVE_INFO printk("%s: %s drive%d 0x%08x ", drive->name, ide_xfer_verbose(speed), @@ -468,175 +619,87 @@ pci_read_config_dword(dev, drive_pci, &drive_conf); printk("0x%08x\n", drive_conf); #endif /* PDC202XX_DEBUG_DRIVE_INFO */ - return err; + + return (ide_config_drive_speed(drive, speed)); } -static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed) +#define set_2regs(a, b) \ + do { \ + OUT_BYTE((a + adj), indexreg); \ + OUT_BYTE(b, datareg); \ + } while(0) + +#define set_ultra(a, b, c) \ + do { \ + set_2regs(0x10,(a)); \ + set_2regs(0x11,(b)); \ + set_2regs(0x12,(c)); \ + } while(0) + +#define set_ata2(a, b) \ + do { \ + set_2regs(0x0e,(a)); \ + set_2regs(0x0f,(b)); \ + } while(0) + +#define set_pio(a, b, c) \ + do { \ + set_2regs(0x0c,(a)); \ + set_2regs(0x0d,(b)); \ + set_2regs(0x13,(c)); \ + } while(0) + + +static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; #ifdef CONFIG_BLK_DEV_IDEDMA - unsigned long indexreg = (hwif->dma_base + 1); - unsigned long datareg = (hwif->dma_base + 3); + u32 indexreg = dma_base+1; + u32 datareg = dma_base+3; #else struct pci_dev *dev = hwif->pci_dev; - unsigned long high_16 = pci_resource_start(dev, 4); - unsigned long indexreg = high_16 + (hwif->channel ? 0x09 : 0x01); - unsigned long datareg = (indexreg + 2); + u32 high_16 = pci_resource_start(dev, 4); + u32 indexreg = high_16 + (hwif->channel ? 0x09 : 0x01); + u32 datareg = (indexreg + 2); #endif /* CONFIG_BLK_DEV_IDEDMA */ - byte thold = 0x10; - byte adj = (drive->dn%2) ? 0x08 : 0x00; - int set_speed = 0, i=0, j=hwif->channel ? 2:0; - int err; + u8 thold = 0x10; + u8 adj = (drive->dn%2) ? 0x08 : 0x00; + u8 speed = pdc202xx_ratefilter(drive, xferspeed); - /* Setting tHOLD bit to 0 if using UDMA mode 2 */ +#ifdef CONFIG_BLK_DEV_IDEDMA if (speed == XFER_UDMA_2) { + u8 data = 0; OUT_BYTE((thold + adj), indexreg); - OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg); + data = IN_BYTE(datareg); + OUT_BYTE((data & 0x7f), datareg); } - - /* We need to set ATA133 timing if ATA133 drives exist */ - if (speed>=XFER_UDMA_6) - set_speed=1; +#endif /* CONFIG_BLK_DEV_IDEDMA */ - if (!drive->init_speed) - drive->init_speed = speed; -#if PDC202XX_DEBUG_DRIVE_INFO - printk("%s: Before set_feature = %s, word88 = %#x\n", - drive->name, ide_xfer_verbose(speed), drive->id->dma_ultra ); -#endif /* PDC202XX_DEBUG_DRIVE_INFO */ - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - for ( i = 0 ; i < 2 ; i++) - if (hwif->drives[i].present) { - id[i+j] = hwif->drives[i].id; /* get identify structs */ - speed_rate[i+j] = speed; /* get current speed */ - } - if (set_speed) { - for (i=0; i<4; i++) { - if (id[i]==NULL) - continue; - switch(speed_rate[i]) { + switch (speed) { #ifdef CONFIG_BLK_DEV_IDEDMA - case XFER_UDMA_6: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x01, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcb, datareg); - break; - case XFER_UDMA_5: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x02, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcb, datareg); - break; - case XFER_UDMA_4: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x03, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); - break; - case XFER_UDMA_3: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x05, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); - break; - case XFER_UDMA_2: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x2a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x07, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); - break; - case XFER_UDMA_1: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x3a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x0a, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xd0, datareg); - break; - case XFER_UDMA_0: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x4a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x0f, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xd5, datareg); - break; - case XFER_MW_DMA_2: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0x69, datareg); - OUT_BYTE((0x0f + adj), indexreg); - OUT_BYTE(0x25, datareg); - break; - case XFER_MW_DMA_1: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0x6b, datareg); - OUT_BYTE((0x0f+ adj), indexreg); - OUT_BYTE(0x27, datareg); - break; - case XFER_MW_DMA_0: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0xdf, datareg); - OUT_BYTE((0x0f + adj), indexreg); - OUT_BYTE(0x5f, datareg); - break; + case XFER_UDMA_7: + speed = XFER_UDMA_6; + case XFER_UDMA_6: set_ultra(0x1a, 0x01, 0xcb); break; + case XFER_UDMA_5: set_ultra(0x1a, 0x02, 0xcb); break; + case XFER_UDMA_4: set_ultra(0x1a, 0x03, 0xcd); break; + case XFER_UDMA_3: set_ultra(0x1a, 0x05, 0xcd); break; + case XFER_UDMA_2: set_ultra(0x2a, 0x07, 0xcd); break; + case XFER_UDMA_1: set_ultra(0x3a, 0x0a, 0xd0); break; + case XFER_UDMA_0: set_ultra(0x4a, 0x0f, 0xd5); break; + case XFER_MW_DMA_2: set_ata2(0x69, 0x25); break; + case XFER_MW_DMA_1: set_ata2(0x6b, 0x27); break; + case XFER_MW_DMA_0: set_ata2(0xdf, 0x5f); break; #endif /* CONFIG_BLK_DEV_IDEDMA */ - case XFER_PIO_4: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x23, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x09, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x25, datareg); - break; - case XFER_PIO_3: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x27, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x0d, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x35, datareg); - break; - case XFER_PIO_2: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x23, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x26, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x64, datareg); - break; - case XFER_PIO_1: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x46, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x29, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0xa4, datareg); - break; - case XFER_PIO_0: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0xfb, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x2b, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0xac, datareg); - break; - default: - } - } + case XFER_PIO_4: set_pio(0x23, 0x09, 0x25); break; + case XFER_PIO_3: set_pio(0x27, 0x0d, 0x35); break; + case XFER_PIO_2: set_pio(0x23, 0x26, 0x64); break; + case XFER_PIO_1: set_pio(0x46, 0x29, 0xa4); break; + case XFER_PIO_0: set_pio(0xfb, 0x2b, 0xac); break; + default: } - return err; + + return (ide_config_drive_speed(drive, speed)); } /* 0 1 2 3 4 5 6 7 8 @@ -648,7 +711,7 @@ */ static int config_chipset_for_pio (ide_drive_t *drive, byte pio) { - byte speed = 0x00; + u8 speed = 0; pio = (pio == 5) ? 4 : pio; speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL); @@ -662,77 +725,89 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) + +static u8 pdc202xx_new_cable_detect (ide_hwif_t *hwif) +{ + u8 ata66 = 0; + unsigned long dma_base = hwif->dma_base; + + /* Fake detection on RackMac on-board controller */ +#ifdef __CONFIG_ALL_PPC_DISABLED + if (machine_is_compatible("RackMac1,1")) { + struct device_node *np; + np = pci_device_to_OF_node(hwif->pci_dev); + if (np && !strcmp(np->name, "AppleKiwi")) + return 0; + } +#endif /* CONFIG_ALL_PPC */ + if (dma_base == 0) + dma_base = pci_resource_start(hwif->pci_dev, 4); + OUT_BYTE(0x0b, dma_base + 1); + ata66 = IN_BYTE(dma_base + 3); + return (ata66 & 0x04); +} + +static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) +{ + u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10); + pci_read_config_word(hwif->pci_dev, 0x50, &CIS); + return ((u8)(CIS & mask)); +} + +static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; + u8 mode = pdc202xx_ratemask(drive); ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - unsigned long high_16 = pci_resource_start(dev, 4); - unsigned long dma_base = hwif->dma_base; - unsigned long indexreg = dma_base + 1; - unsigned long datareg = dma_base + 3; + u32 high_16 = pci_resource_start(dev, 4); + u32 indexreg = hwif->dma_base+1; + u32 datareg = hwif->dma_base+3; byte iordy = 0x13; byte adj = (drive->dn%2) ? 0x08 : 0x00; byte cable = 0; - byte new_chip = 0; - byte unit = (drive->select.b.unit & 0x01); + byte jumpbit = 0; unsigned int drive_conf; byte drive_pci = 0; byte test1, test2, speed = -1; byte AP; - unsigned short EP; byte CLKSPD = 0; - byte clockreg = high_16 + 0x11; - byte udma_33 = ultra; - byte udma_66 = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0; + byte udma_66 = (eighty_ninty_three(drive)) ? 1 : 0; byte udma_100 = 0; byte udma_133 = 0; - byte mask = hwif->channel ? 0x08 : 0x02; - unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10); + byte mask = hwif->channel ? 0x08 : 0x02; byte ultra_66 = ((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0; - byte ultra_100 = ((id->dma_ultra & 0x0020) || - (ultra_66)) ? 1 : 0; - byte ultra_133 = ((id->dma_ultra & 0x0040) || - (ultra_100)) ? 1 : 0; switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20269: udma_133 = (udma_66) ? 1 : 0; udma_100 = (udma_66) ? 1 : 0; - OUT_BYTE(0x0b, (hwif->dma_base + 1)); - cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04)); - new_chip = 1; - break; - case PCI_DEVICE_ID_PROMISE_20268: case PCI_DEVICE_ID_PROMISE_20270: - udma_100 = (udma_66) ? 1 : 0; - OUT_BYTE(0x0b, (hwif->dma_base + 1)); - cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04)); - new_chip = 1; + case PCI_DEVICE_ID_PROMISE_20268: + cable = pdc202xx_new_cable_detect(hwif); + jumpbit = 1; break; case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: udma_100 = (udma_66) ? 1 : 0; - pci_read_config_word(dev, 0x50, &EP); - cable = (EP & c_mask); - new_chip = 0; - CLKSPD = IN_BYTE(clockreg); - break; + case PCI_DEVICE_ID_PROMISE_20263: case PCI_DEVICE_ID_PROMISE_20262: - pci_read_config_word(dev, 0x50, &EP); - cable = (EP & c_mask); - new_chip = 0; - CLKSPD = IN_BYTE(clockreg); + cable = pdc202xx_old_cable_detect(hwif); + jumpbit = 0; break; default: - udma_100 = 0; udma_133 = 0; cable = 0; new_chip = 1; + cable = 1; jumpbit = 0; break; } + if (!jumpbit) + CLKSPD = IN_BYTE(high_16 + 0x11); /* * Set the control register to use the 66Mhz system * clock for UDMA 3/4 mode operation. If one drive on @@ -746,122 +821,130 @@ * parameters. */ - if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) { -#ifdef DEBUG - printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary"); + if ((ultra_66) && (cable)) { +#if 1 + printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 " + "requires an 80-pin cable for Ultra66 operation.\n", + hwif->channel ? "Secondary" : "Primary"); printk(" Switching to Ultra33 mode.\n"); #endif /* DEBUG */ /* Primary : zero out second bit */ /* Secondary : zero out fourth bit */ - //if (!new_chip) - OUT_BYTE(CLKSPD & ~mask, clockreg); + if (!jumpbit) + OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary"); printk("%s reduced to Ultra33 mode.\n", drive->name); - udma_66 = 0; udma_100 = 0; udma_133 = 0; + udma_66 = 0; } else { - if ((ultra_66) || (ultra_100) || (ultra_133)) { + if (ultra_66) { /* * check to make sure drive on same channel * is u66 capable */ if (hwif->drives[!(drive->dn%2)].id) { - if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) || - (hwif->drives[!(drive->dn%2)].id->dma_ultra -& 0x0020) || - (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) || - (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) { - OUT_BYTE(CLKSPD | mask, clockreg); + if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) { + if (!jumpbit) + OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } else { - OUT_BYTE(CLKSPD & ~mask, clockreg); + if (!jumpbit) + OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); } } else { /* udma4 drive by itself */ - OUT_BYTE(CLKSPD | mask, clockreg); + if (!jumpbit) + OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } } } - if (new_chip) goto chipset_is_set; + if (jumpbit) { + if (drive->media != ide_disk) + return ide_dma_off_quietly; + if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ + u8 data = 0; + OUT_BYTE((iordy + adj), indexreg); + data = IN_BYTE(datareg); + OUT_BYTE((data|0x03), datareg); + } + goto jumpbit_is_set; + } - switch(drive->dn) { - case 0: drive_pci = 0x60; - pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; - pci_read_config_byte(dev, (drive_pci), &test1); - if (!(test1 & SYNC_ERRDY_EN)) - pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); - break; - case 1: drive_pci = 0x64; - pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; - pci_read_config_byte(dev, 0x60, &test1); - pci_read_config_byte(dev, (drive_pci), &test2); - if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) - pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN); - break; - case 2: drive_pci = 0x68; - pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; - pci_read_config_byte(dev, (drive_pci), &test1); - if (!(test1 & SYNC_ERRDY_EN)) - pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN); - break; - case 3: drive_pci = 0x6c; - pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; - pci_read_config_byte(dev, 0x68, &test1); - pci_read_config_byte(dev, (drive_pci), &test2); - if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN)) - pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN); - break; - default: - return ide_dma_off; + drive_pci = 0x60 + (drive->dn << 2); + pci_read_config_dword(dev, drive_pci, &drive_conf); + if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) + goto chipset_is_set; + + pci_read_config_byte(dev, drive_pci, &test1); + if (!(test1 & SYNC_ERRDY_EN)) { + if (drive->select.b.unit & 0x01) { + pci_read_config_byte(dev, drive_pci - 4, &test2); + if ((test2 & SYNC_ERRDY_EN) && + !(test1 & SYNC_ERRDY_EN)) { + pci_write_config_byte(dev, drive_pci, + test1|SYNC_ERRDY_EN); + } + } else { + pci_write_config_byte(dev, drive_pci, + test1|SYNC_ERRDY_EN); + } } chipset_is_set: - if (drive->media != ide_disk) + if (drive->media != ide_disk) { + hwif->tuneproc(drive, 5); return ide_dma_off_quietly; - - if (new_chip) { - if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ - OUT_BYTE((iordy + adj), indexreg); - OUT_BYTE((IN_BYTE(datareg)|0x03), datareg); - } } - else { - pci_read_config_byte(dev, (drive_pci), &AP); - if (id->capability & 4) /* IORDY_EN */ - pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); - pci_read_config_byte(dev, (drive_pci), &AP); - if (drive->media == ide_disk) /* PREFETCH_EN */ - pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); - } - - if ((id->dma_ultra & 0x0040)&&(udma_133)) speed = XFER_UDMA_6; - else if ((id->dma_ultra & 0x0020)&&(udma_100)) speed = XFER_UDMA_5; - else if ((id->dma_ultra & 0x0010)&&(udma_66)) speed = XFER_UDMA_4; - else if ((id->dma_ultra & 0x0008)&&(udma_66)) speed = XFER_UDMA_3; - else if ((id->dma_ultra & 0x0004)&&(udma_33)) speed = XFER_UDMA_2; - else if ((id->dma_ultra & 0x0002)&&(udma_33)) speed = XFER_UDMA_1; - else if ((id->dma_ultra & 0x0001)&&(udma_33)) speed = XFER_UDMA_0; - else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; - else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; - else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; - else if ((id->dma_1word & 0x0004)&&(!new_chip)) speed = XFER_SW_DMA_2; - else if ((id->dma_1word & 0x0002)&&(!new_chip)) speed = XFER_SW_DMA_1; - else if ((id->dma_1word & 0x0001)&&(!new_chip)) speed = XFER_SW_DMA_0; - else { - /* restore original pci-config space */ - if (!new_chip) - pci_write_config_dword(dev, drive_pci, drive_conf); - return ide_dma_off_quietly; + + pci_read_config_byte(dev, (drive_pci), &AP); + if (id->capability & 4) /* IORDY_EN */ + pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); + pci_read_config_byte(dev, (drive_pci), &AP); + if (drive->media == ide_disk) /* PREFETCH_EN */ + pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); + +jumpbit_is_set: + + switch(mode) { + case 0x04: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_6; break; } + case 0x03: + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } + if ((id->dma_1word & 0x0004) && (!jumpbit)) + { speed = XFER_SW_DMA_2; break; } + if ((id->dma_1word & 0x0002) && (!jumpbit)) + { speed = XFER_SW_DMA_1; break; } + if ((id->dma_1word & 0x0001) && (!jumpbit)) + { speed = XFER_SW_DMA_0; break; } + default: + + /* restore original pci-config space */ + if (!jumpbit) + pci_write_config_dword(dev, drive_pci, drive_conf); + hwif->tuneproc(drive, 5); + return ide_dma_off_quietly; } - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); (void) hwif->speedproc(drive, speed); return ((int) ((id->dma_ultra >> 14) & 3) ? ide_dma_on : @@ -872,23 +955,24 @@ ide_dma_off_quietly); } -static int config_drive_xfer_rate (ide_drive_t *drive) +int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - ide_dma_action_t dma_func = ide_dma_off_quietly; + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + ide_dma_action_t dma_func = ide_dma_off_quietly; - if (id && (id->capability & 1) && hwif->autodma) { + drive->init_speed = 0; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { dma_func = ide_dma_off; goto fast_ata_pio; } - dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; @@ -898,16 +982,15 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } } else if (ide_dmaproc(ide_dma_good_drive, drive)) { - if (id->eide_dma_time > 150) { + if (id->eide_dma_time > 150) goto no_dma_set; - } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } else { @@ -917,10 +1000,9 @@ fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - (void) config_chipset_for_pio(drive, 5); + hwif->tuneproc(drive, 5); } - - return HWIF(drive)->dmaproc(dma_func, drive); + return hwif->dmaproc(dma_func, drive); } int pdc202xx_quirkproc (ide_drive_t *drive) @@ -928,9 +1010,110 @@ return ((int) check_in_drive_lists(drive, pdc_quirk_drives)); } +void pdc202xx_old_ide_dma_begin(ide_drive_t *drive) +{ + if (drive->addressing == 1) { + struct request *rq = HWGROUP(drive)->rq; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + u32 high_16 = pci_resource_start(dev, 4); + u32 atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); + u32 word_count = 0; + u8 clock = 0; + + clock = IN_BYTE(high_16 + 0x11); + OUT_BYTE(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11); + word_count = (rq->nr_sectors << 8); + word_count = (rq->cmd == READ) ? word_count | 0x05000000 : + word_count | 0x06000000; + OUT_LONG(word_count, atapi_reg); + } +} + +void pdc202xx_old_ide_dma_end(ide_drive_t *drive) +{ + if (drive->addressing == 1) { + ide_hwif_t *hwif = HWIF(drive); + u32 high_16 = pci_resource_start(hwif->pci_dev, 4); + u32 atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); + u8 clock = 0; + + OUT_LONG(0, atapi_reg); /* zero out extra */ + clock = IN_BYTE(high_16 + 0x11); + OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11); + } +} + +int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + unsigned long high_16 = pci_resource_start(dev, 4); + u8 dma_stat = 0, sc1d = 0; + + dma_stat = IN_BYTE(hwif->dma_base+2); + sc1d = IN_BYTE(high_16 + 0x001d); + + if (hwif->channel) { + if ((sc1d & 0x50) == 0x50) + goto somebody_else; + else if ((sc1d & 0x40) == 0x40) + return (dma_stat & 4) == 4; + } else { + if ((sc1d & 0x05) == 0x05) + goto somebody_else; + else if ((sc1d & 0x04) == 0x04) + return (dma_stat & 4) == 4; + } +somebody_else: + return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ +} + /* * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. */ +int pdc202xx_dmaproc_old (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return pdc202xx_config_drive_xfer_rate(drive); + break; + case ide_dma_begin: + pdc202xx_old_ide_dma_begin(drive); + break; + case ide_dma_end: + pdc202xx_old_ide_dma_end(drive); + break; + case ide_dma_test_irq: + return pdc202xx_old_ide_dma_test_irq(drive); + case ide_dma_lostirq: + case ide_dma_timeout: + if (HWIF(drive)->resetproc != NULL) + HWIF(drive)->resetproc(drive); + break; + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +int pdc202xx_dmaproc_new (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return pdc202xx_config_drive_xfer_rate(drive); + case ide_dma_lostirq: + case ide_dma_timeout: + if (HWIF(drive)->resetproc != NULL) + HWIF(drive)->resetproc(drive); + break; + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} + +#if 0 int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { byte dma_stat = 0; @@ -1020,16 +1203,31 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +#endif #endif /* CONFIG_BLK_DEV_IDEDMA */ -void pdc202xx_reset (ide_drive_t *drive) +void pdc202xx_reset_pci (struct pci_dev *dev) { - OUT_BYTE(0x04,IDE_CONTROL_REG); - mdelay(1000); - OUT_BYTE(0x00,IDE_CONTROL_REG); - mdelay(1000); + unsigned long high_16 = pci_resource_start(dev, 4); + u8 udma_speed_flag = IN_BYTE(high_16 + 0x001f); + + OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); + mdelay(100); + OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); + mdelay(2000); /* 2 seconds ?! */ +} + +void pdc202xx_reset_host (ide_hwif_t *hwif) +{ + pdc202xx_reset_pci(hwif->pci_dev); printk("PDC202XX: %s channel reset.\n", - HWIF(drive)->channel ? "Secondary" : "Primary"); + hwif->channel ? "Secondary" : "Primary"); +} + +void pdc202xx_reset (ide_drive_t *drive) +{ + pdc202xx_reset_host(HWIF(drive)); + HWIF(drive)->tuneproc(drive, 5); } /* @@ -1058,128 +1256,175 @@ return 0; } -unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) +void pdc202xx_marvell_idle (ide_drive_t *drive) { - unsigned long high_16 = pci_resource_start(dev, 4); - byte udma_speed_flag = IN_BYTE(high_16 + 0x001f); - byte primary_mode = IN_BYTE(high_16 + 0x001a); - byte secondary_mode = IN_BYTE(high_16 + 0x001b); + /* Give a breath for Marvell's Idle Immediate command */ + OUT_BYTE(0, IDE_NSECTOR_REG); /* timeout disable */ + OUT_BYTE(WIN_SETIDLE1, IDE_COMMAND_REG); +} - OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); - mdelay(100); - OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); - mdelay(2000); /* 2 seconds ?! */ +unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) +{ + u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0; + u32 dmabase = pci_resource_start(dev, 4); if (dev->resource[PCI_ROM_RESOURCE].start) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); + pci_write_config_dword(dev, PCI_ROM_ADDRESS, + dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", + name, dev->resource[PCI_ROM_RESOURCE].start); } + + pdc202_devs[n_pdc202_devs++] = dev; - printk("%s: (U)DMA Burst Bit %sABLED " \ - "Primary %s Mode " \ - "Secondary %s Mode.\n", - name, - (udma_speed_flag & 1) ? "EN" : "DIS", - (primary_mode & 1) ? "MASTER" : "PCI", - (secondary_mode & 1) ? "MASTER" : "PCI" ); +#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) + if (!pdc202xx_proc) { + pdc202xx_proc = 1; + pdc202xx_display_info = &pdc202xx_get_info; + } +#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ + + switch (dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20270: + case PCI_DEVICE_ID_PROMISE_20268: + break; + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20263: + case PCI_DEVICE_ID_PROMISE_20262: + /* + * software reset - this is required because the bios + * will set UDMA timing on if the hdd supports it. The + * user may want to turn udma off. A bug in the pdc20262 + * is that it cannot handle a downgrade in timing from + * UDMA to DMA. Disk accesses after issuing a set + * feature command will result in errors. A software + * reset leaves the timing registers intact, + * but resets the drives. + */ + pdc202xx_reset_pci(dev); + default: + if (!dmabase) + break; + udma_speed_flag = IN_BYTE(dmabase + 0x001f); + primary_mode = IN_BYTE(dmabase + 0x001a); + secondary_mode = IN_BYTE(dmabase + 0x001b); + printk("%s: (U)DMA Burst Bit %sABLED " \ + "Primary %s Mode " \ + "Secondary %s Mode.\n", name, + (udma_speed_flag & 1) ? "EN" : "DIS", + (primary_mode & 1) ? "MASTER" : "PCI", + (secondary_mode & 1) ? "MASTER" : "PCI" ); #ifdef CONFIG_PDC202XX_BURST - if (!(udma_speed_flag & 1)) { - printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); - OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f); - printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA"); - } + if (!(udma_speed_flag & 1)) { + u8 burst = 0; + printk("%s: FORCING BURST BIT 0x%02x->0x%02x ", + name, udma_speed_flag, + (udma_speed_flag|1)); + OUT_BYTE(udma_speed_flag|1,(dmabase+0x001f)); + burst = IN_BYTE(dmabase+0x001f); + printk("%sCTIVE\n", (burst & 1) ? "A" : "INA"); + } #endif /* CONFIG_PDC202XX_BURST */ - #ifdef CONFIG_PDC202XX_MASTER - if (!(primary_mode & 1)) { - printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", - name, primary_mode, (primary_mode|1)); - OUT_BYTE(primary_mode|1, high_16 + 0x001a); - printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI"); - } + if (!(primary_mode & 1)) { + u8 tmp1 = 0; + printk("%s: FORCING PRIMARY MODE BIT " + "0x%02x -> 0x%02x ", name, + primary_mode, (primary_mode|1)); + OUT_BYTE(primary_mode|1, (dmabase+0x001a)); + tmp1 = IN_BYTE(dmabase+0x001a); + printk("%s\n", (tmp1 & 1) ? "MASTER" : "PCI"); + } - if (!(secondary_mode & 1)) { - printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ", - name, secondary_mode, (secondary_mode|1)); - OUT_BYTE(secondary_mode|1, high_16 + 0x001b); - printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); - } + if (!(secondary_mode & 1)) { + u8 tmp2 = 0; + printk("%s: FORCING SECONDARY MODE BIT " + "0x%02x -> 0x%02x ", name, + secondary_mode, (secondary_mode|1)); + OUT_BYTE(secondary_mode|1, (dmabase+0x001b)); + tmp2 = IN_BYTE(dmabase+0x001b)); + printk("%s\n", (tmp2 & 1) ? "MASTER" : "PCI"); + } #endif /* CONFIG_PDC202XX_MASTER */ -#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) - if (!pdc202xx_proc) { - pdc202xx_proc = 1; - bmide_dev = dev; - pdc202xx_display_info = &pdc202xx_get_info; + break; } -#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ return dev->irq; } unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif) { - unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10); - unsigned short CIS; - - switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_PROMISE_20276: - case PCI_DEVICE_ID_PROMISE_20275: - case PCI_DEVICE_ID_PROMISE_20269: - case PCI_DEVICE_ID_PROMISE_20268: - case PCI_DEVICE_ID_PROMISE_20270: - OUT_BYTE(0x0b, (hwif->dma_base + 1)); - return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04)); - /* check 80pin cable */ - default: - pci_read_config_word(hwif->pci_dev, 0x50, &CIS); - return (!(CIS & mask)); - /* check 80pin cable */ + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20270: + return !pdc202xx_new_cable_detect(hwif); + /* check 80pin cable */ + default: + return !pdc202xx_old_cable_detect(hwif); + /* check 80pin cable */ } } void __init ide_init_pdc202xx (ide_hwif_t *hwif) { + int newchip = 0; + hwif->tuneproc = &pdc202xx_tune_drive; hwif->quirkproc = &pdc202xx_quirkproc; - hwif->resetproc = &pdc202xx_reset; + + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + hwif->autodma = 0; switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20269: case PCI_DEVICE_ID_PROMISE_20268: case PCI_DEVICE_ID_PROMISE_20270: hwif->speedproc = &pdc202xx_new_tune_chipset; + hwif->resetproc = NULL; + newchip = 1; break; case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: + hwif->addressing = (hwif->channel) ? 0 : 1; + case PCI_DEVICE_ID_PROMISE_20263: case PCI_DEVICE_ID_PROMISE_20262: hwif->busproc = &pdc202xx_tristate; + hwif->resetproc = &pdc202xx_reset; case PCI_DEVICE_ID_PROMISE_20246: hwif->speedproc = &pdc202xx_tune_chipset; default: break; } -#undef CONFIG_PDC202XX_32_UNMASK -#ifdef CONFIG_PDC202XX_32_UNMASK - hwif->drives[0].io_32bit = 1; - hwif->drives[1].io_32bit = 1; - hwif->drives[0].unmask = 1; - hwif->drives[1].unmask = 1; -#endif /* CONFIG_PDC202XX_32_UNMASK */ + if (!hwif->dma_base) + return; #ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) { - hwif->dmaproc = &pdc202xx_dmaproc; - if (!noautodma) - hwif->autodma = 1; - } else { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - hwif->autodma = 0; - } + if (newchip) + hwif->dmaproc = &pdc202xx_dmaproc_new; + else + hwif->dmaproc = &pdc202xx_dmaproc_old; +# ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +# endif /* CONFIG_IDEDMA_AUTO */ #else /* !CONFIG_BLK_DEV_IDEDMA */ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff -uNr linux-2.4.20/drivers/ide/rapide.c linux-2.4.20-ben6/drivers/ide/rapide.c --- linux-2.4.20/drivers/ide/rapide.c 2001-10-11 18:14:32.000000000 +0200 +++ linux-2.4.20-ben6/drivers/ide/rapide.c 2003-02-16 20:20:05.000000000 +0100 @@ -40,6 +40,7 @@ } hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206; hw.irq = ec->irq; + hw.chipset = ide_generic; return ide_register_hw(&hw, NULL); } diff -uNr linux-2.4.20/drivers/macintosh/Makefile linux-2.4.20-ben6/drivers/macintosh/Makefile --- linux-2.4.20/drivers/macintosh/Makefile 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/macintosh/Makefile 2003-02-16 20:21:47.000000000 +0100 @@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_ADBHID) += adbhid.o obj-$(CONFIG_PPC_RTC) += rtc.o obj-$(CONFIG_ANSLCD) += ans-lcd.o +obj-$(CONFIG_I2C) += thermostat.o obj-$(CONFIG_ADB_PMU) += via-pmu.o obj-$(CONFIG_ADB_CUDA) += via-cuda.o diff -uNr linux-2.4.20/drivers/macintosh/adb.c linux-2.4.20-ben6/drivers/macintosh/adb.c --- linux-2.4.20/drivers/macintosh/adb.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/macintosh/adb.c 2003-02-16 20:21:20.000000000 +0100 @@ -592,7 +592,6 @@ return (*original_address != 0); } - /* * /dev/adb device driver. */ @@ -636,6 +635,27 @@ spin_unlock_irqrestore(&state->lock, flags); } +static int +do_adb_query(struct adb_request *req) +{ + int ret = -EINVAL; + + switch(req->data[1]) + { + case ADB_QUERY_GETDEVINFO: + if (req->nbytes < 3) + break; + req->reply[0] = adb_handler[req->data[2]].original_address; + req->reply[1] = adb_handler[req->data[2]].handler_id; + req->complete = 1; + req->reply_len = 2; + adb_write_done(req); + ret = 0; + break; + } + return ret; +} + static int adb_open(struct inode *inode, struct file *file) { struct adbdev_state *state; @@ -655,6 +675,7 @@ return 0; } +/* FIXME: Should wait completion, dequeue & delete pending requests */ static int adb_release(struct inode *inode, struct file *file) { struct adbdev_state *state = file->private_data; @@ -772,9 +793,17 @@ /* If a probe is in progress or we are sleeping, wait for it to complete */ down(&adb_probe_mutex); + /* Queries are special requests sent to the ADB driver itself */ + if (req->data[0] == ADB_QUERY) { + if (count > 1) + ret = do_adb_query(req); + else + ret = -EINVAL; + up(&adb_probe_mutex); + } /* Special case for ADB_BUSRESET request, all others are sent to the controller */ - if ((req->data[0] == ADB_PACKET)&&(count > 1) + else if ((req->data[0] == ADB_PACKET)&&(count > 1) &&(req->data[1] == ADB_BUSRESET)) { ret = do_adb_reset_bus(); up(&adb_probe_mutex); diff -uNr linux-2.4.20/drivers/macintosh/adbhid.c linux-2.4.20-ben6/drivers/macintosh/adbhid.c --- linux-2.4.20/drivers/macintosh/adbhid.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/macintosh/adbhid.c 2003-02-16 20:21:20.000000000 +0100 @@ -42,6 +42,10 @@ #include #include #include + +#include +#include + #ifdef CONFIG_PMAC_BACKLIGHT #include #endif @@ -65,7 +69,7 @@ 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0, 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124, 63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88, - 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116 + 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,126,116 }; struct adbhid { @@ -154,6 +158,15 @@ return; case 0x3f: /* ignore Powerbook Fn key */ return; + case 0x7e: /* Power key on PBook 3400 needs remapping */ + switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_MODEL, 0)) { + case PMAC_TYPE_COMET: + case PMAC_TYPE_HOOPER: + case PMAC_TYPE_KANGA: + keycode = 0x7f; + } + break; } if (adbhid[id]->keycode[keycode]) diff -uNr linux-2.4.20/drivers/macintosh/apm_emu.c linux-2.4.20-ben6/drivers/macintosh/apm_emu.c --- linux-2.4.20/drivers/macintosh/apm_emu.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/macintosh/apm_emu.c 2003-02-16 20:20:24.000000000 +0100 @@ -436,40 +436,40 @@ int percentage = -1; int time_units = -1; int real_count = 0; - int charge = -1; - int current = 0; int i; char * p = buf; char charging = 0; + long charge = -1; + long current = 0; + unsigned long btype = 0; ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); for (i=0; i 0) { battery_status = 0x03; battery_flag = 0x08; } else if (percentage <= APM_CRITICAL) { @@ -516,6 +516,7 @@ static int __init apm_emu_init(void) { struct proc_dir_entry *apm_proc; + int retval; if (sys_ctrler != SYS_CTRLER_PMU) { printk(KERN_INFO "apm_emu: Requires a machine with a PMU.\n"); @@ -523,10 +524,18 @@ } apm_proc = create_proc_info_entry("apm", 0, NULL, apm_emu_get_info); - if (apm_proc) - SET_MODULE_OWNER(apm_proc); + if (!apm_proc) { + printk(KERN_ERR "apm_emu: create_proc_info_entry failed.\n"); + return -ENOENT; + } + SET_MODULE_OWNER(apm_proc); - misc_register(&apm_device); + retval = misc_register(&apm_device); + if (retval < 0) { + printk(KERN_ERR "apm_emu: misc_register failed\n"); + remove_proc_entry("apm", NULL); + return retval; + } pmu_register_sleep_notifier(&apm_sleep_notifier); diff -uNr linux-2.4.20/drivers/macintosh/macio-adb.c linux-2.4.20-ben6/drivers/macintosh/macio-adb.c --- linux-2.4.20/drivers/macintosh/macio-adb.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/macintosh/macio-adb.c 2003-02-16 20:21:03.000000000 +0100 @@ -218,7 +218,6 @@ out_8(&adb->ctrl.r, DTB + CRE); } else { out_8(&adb->ctrl.r, DTB); - req->complete = 1; current_req = req->next; complete = 1; if (current_req) @@ -238,7 +237,6 @@ for (i = 0; i < req->reply_len; ++i) req->reply[i] = in_8(&adb->data[i].r); } - req->complete = 1; current_req = req->next; complete = 1; if (current_req) @@ -255,8 +253,16 @@ out_8(&adb->intr.r, 0); } spin_unlock(&macio_lock); - if (complete && req && req->done) - (*req->done)(req); + if (complete && req) { + void (*done)(struct adb_request *) = req->done; + mb(); + req->complete = 1; + /* Here, we assume that if the request has a done member, the + * struct request will survive to setting req->complete to 1 + */ + if (done) + (*done)(req); + } if (ibuf_len) adb_input(ibuf, ibuf_len, regs, autopoll); } diff -uNr linux-2.4.20/drivers/macintosh/macserial.c linux-2.4.20-ben6/drivers/macintosh/macserial.c --- linux-2.4.20/drivers/macintosh/macserial.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/macintosh/macserial.c 2003-02-16 20:20:39.000000000 +0100 @@ -1134,6 +1134,8 @@ */ static void shutdown(struct mac_serial * info) { + unsigned long flags; + OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line, info->irq); @@ -1142,6 +1144,8 @@ return; } + save_flags(flags); cli(); /* Disable interrupts */ + if (info->has_dma) { del_timer(&info->poll_dma_timer); dbdma_reset(info->tx_dma); @@ -1151,6 +1155,8 @@ } disable_irq(info->irq); + restore_flags(flags); + info->pendregs[1] = info->curregs[1] = 0; write_zsreg(info->zs_channel, 1, 0); /* no interrupts */ @@ -1980,6 +1986,7 @@ return; } info->flags |= ZILOG_CLOSING; + restore_flags(flags); /* * Save the termios structure, since this port may have * separate termios for callout and dialin. @@ -1994,11 +2001,8 @@ */ OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait); tty->closing = 1; - if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) { - restore_flags(flags); + if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, info->closing_wait); - save_flags(flags); cli(); - } /* * At this point we stop accepting input. To do this, we @@ -2017,15 +2021,10 @@ * has completely drained. */ OPNDBG("waiting end of Rx...\n"); - restore_flags(flags); rs_wait_until_sent(tty, info->timeout); - save_flags(flags); cli(); } shutdown(info); - /* restore flags now since shutdown() will have disabled this port's - specific irqs */ - restore_flags(flags); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); @@ -2880,7 +2879,7 @@ static int __init serial_console_setup(struct console *co, char *options) { struct mac_serial *info; - int baud = 38400; + int baud = 57600; /*38400;*/ int bits = 8; int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; diff -uNr linux-2.4.20/drivers/macintosh/thermostat.c linux-2.4.20-ben6/drivers/macintosh/thermostat.c --- linux-2.4.20/drivers/macintosh/thermostat.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/macintosh/thermostat.c 2003-02-16 20:21:10.000000000 +0100 @@ -0,0 +1,271 @@ +/* + * Device driver for the i2c thermostat found on some laptops + * + * Copyright (C) 2001 Benjamin Herrenschmidt + * + * Actually, there are 2 DS1775R1 on uninorth I2C busses + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG + +#define I2C_THERMOSTAT_ADDR 0x49 +#define I2C_THERMOSTAT_ADDR2 0x48 +#define MAX_THERMOSTATS 4 + + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("Driver for DS1775 thermostat on Apple laptops"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + +struct temp_range +{ + u8 high; /* Start the fan */ + u8 low; /* Stop the fan */ +}; + +struct apple_thermal_info { + u8 id; /* Implementation ID */ + u8 fan_count; /* Number of fans */ + u8 thermostat_count; /* Number of thermostats */ + u8 unused[5]; + struct temp_range ranges[4]; /* Temperature ranges (may be [])*/ +}; + +struct thermostat { + struct i2c_client clt; + int th_num; + // more to come ? +}; + +static struct apple_thermal_info *thinfo; +static struct thermostat* thermostats[MAX_THERMOSTATS]; +static int therm_count; + +static int attach_thermostat(struct i2c_adapter *adapter); +static int detach_thermostat(struct i2c_client *client); + +/* What is this supposed to be ? registered ? I hate + * magic numbers like that ... + */ +#define I2C_DRIVERID_THERMOSTAT (0xDEAD) + +static struct i2c_driver thermostat_driver = { + name: "Apple Thermostat", + id: I2C_DRIVERID_THERMOSTAT, + flags: I2C_DF_NOTIFY, + attach_adapter: &attach_thermostat, + detach_client: &detach_thermostat, + command: NULL, + inc_use: NULL, + dec_use: NULL +}; + +static int +write_reg(struct thermostat* th, int reg, u8* data, int len) +{ + u8 tmp[5]; + int rc; + + if (len > 4) + return -EINVAL; + tmp[0] = reg; + memcpy(&tmp[1], data, len); + rc = i2c_master_send(&th->clt, (const char *)tmp, len+1); + if (rc < 0) + return rc; + if (rc != (len+1)) + return -ENODEV; + return 0; +} + +static int +read_reg(struct thermostat* th, int reg, u8* data, int len) +{ + u8 reg_addr; + int rc; + + reg_addr = (u8)reg; + rc = i2c_master_send(&th->clt, ®_addr, 1); + if (rc < 0) + return rc; + if (rc != 1) + return -ENODEV; + rc = i2c_master_recv(&th->clt, (char *)data, len); + if (rc < 0) + return rc; + if (rc != len) + return -ENODEV; + return 0; +} + +static int +attach_one_thermostat(struct i2c_adapter *adapter, int addr, int num) +{ + struct thermostat* th; + int rc; + u16 t, tlo, thi; + u8 config; + + if (therm_count >= MAX_THERMOSTATS) { + printk(KERN_WARNING "Skipped thermostat %d (%s:%x), max count reached !\n", + num, adapter->name, addr); + return -ENODEV; + } + + th = (struct thermostat *)kmalloc(sizeof(struct thermostat), GFP_KERNEL); + if (!th) + return -ENOMEM; + th->clt.addr = addr; + th->clt.adapter = adapter; + th->clt.driver = &thermostat_driver; + th->clt.flags = 0; + th->clt.data = (void *)therm_count; + th->th_num = num; + strcpy(th->clt.name, "thermostat"); + + rc = read_reg(th, 1, &config, 1); + if (rc < 0) { + printk(KERN_ERR "Thermostat %d (%s:%x) failed to read config !\n", + num, adapter->name, addr); + kfree(th); + return -ENODEV; + } + printk(KERN_INFO "Thermostat %d (%s:%x), config: %02x\n", + num, adapter->name, addr, config); + + rc = read_reg(th, 0, (u8 *)&t, 2); + if (rc < 0) { + printk(KERN_ERR "Thermostat %d (%s:%x) failed to read temp !\n", + num, adapter->name, addr); + kfree(th); + return -ENODEV; + } + printk(KERN_INFO "Thermostat %d (%s:%x), temp: %04x (about: %d degree C)\n", + num, adapter->name, addr, t, t>>8); + + thermostats[therm_count++] = th; + + if (i2c_attach_client(&th->clt)) { + printk(KERN_ERR "Thermostat %d (%s:%x), failed to attach client !\n", + num, adapter->name, addr); + thermostats[--therm_count] = NULL; + kfree(th); + return -ENODEV; + } + + tlo = thi = 0; + rc = read_reg(th, 2, (u8 *)&tlo, 2); + if (rc < 0) { + printk(KERN_WARNING "Thermostat %d (%s:%x) failed to read low threshold !\n", + num, adapter->name, addr); + } + rc = read_reg(th, 3, (u8 *)&thi, 2); + if (rc < 0) { + printk(KERN_WARNING "Thermostat %d (%s:%x) failed to read high threshold !\n", + num, adapter->name, addr); + } + printk(KERN_INFO "Thermostat %d (%s:%x), tl: %04x (%d degree C), th: %04x (%d degree C)\n", + num, adapter->name, addr, tlo, tlo>>8, thi, thi>>8); + return 0; +} + +static int +attach_thermostat(struct i2c_adapter *adapter) +{ + unsigned long bus_no; + int rc; + + if (strncmp(adapter->name, "uni-n", 5)) + return 0; + bus_no = simple_strtoul(adapter->name + 6, NULL, 10); + rc = attach_one_thermostat(adapter, I2C_THERMOSTAT_ADDR, bus_no); + if (!rc && thinfo->thermostat_count > 2) + attach_one_thermostat(adapter, I2C_THERMOSTAT_ADDR2, bus_no+2); + + return rc; +} + +static int +detach_thermostat(struct i2c_client *client) +{ + int index = (int)client->data; + struct thermostat* th; + + if (index >= MAX_THERMOSTATS || !thermostats[index]) { + printk(KERN_ERR "Invalid client in deatch_thermostat()\n"); + return -ENODEV; + } + th = thermostats[index]; + i2c_detach_client(&th->clt); + thermostats[index] = NULL; + + kfree(th); + + return 0; +} + +static int __init +thermostat_init(void) +{ + struct device_node* np; + + np = find_devices("power-mgt"); + if (!np) + return -ENODEV; + thinfo = (struct apple_thermal_info *)get_property(np, "thermal-info", NULL); + if (!thinfo) + return -ENODEV; + +#ifdef DEBUG + printk(KERN_DEBUG " Thermal Infos found :\n"); + printk(KERN_DEBUG " implementation id : %d\n", thinfo->id); + printk(KERN_DEBUG " fan_count : %d\n", thinfo->fan_count); + printk(KERN_DEBUG " thermostat_count : %d\n", thinfo->thermostat_count); + printk(KERN_DEBUG " ranges[0] : %d,%d\n", + thinfo->ranges[0].high, thinfo->ranges[0].low); + printk(KERN_DEBUG " ranges[1] : %d,%d\n", + thinfo->ranges[1].high, thinfo->ranges[1].low); + printk(KERN_DEBUG " ranges[2] : %d,%d\n", + thinfo->ranges[2].high, thinfo->ranges[2].low); + printk(KERN_DEBUG " ranges[3] : %d,%d\n", + thinfo->ranges[3].high, thinfo->ranges[3].low); +#endif + /* Check against titaniums & ibooks.... */ +// if (machine_is_compatible("PowerBook3,1")) { + if (thinfo->id != 1 && thinfo->id != 2) { + printk(KERN_ERR "thermostat: design id %d unknown !\n", thinfo->id); + return -ENODEV; + } +// } else { +// printk(KERN_ERR "thermostat: unsupported machine type !\n"); +// return -ENODEV; +// } + + return i2c_add_driver(&thermostat_driver); +} + +static void __exit +thermostat_exit(void) +{ + i2c_del_driver(&thermostat_driver); +} + +module_init(thermostat_init); +module_exit(thermostat_exit); diff -uNr linux-2.4.20/drivers/macintosh/via-cuda.c linux-2.4.20-ben6/drivers/macintosh/via-cuda.c --- linux-2.4.20/drivers/macintosh/via-cuda.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/macintosh/via-cuda.c 2003-02-16 20:20:00.000000000 +0100 @@ -175,8 +175,8 @@ /* for us by the main VIA driver in arch/m68k/mac/via.c */ #ifndef CONFIG_MAC - via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ - via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */ + out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */ + out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ #endif /* enable autopoll */ @@ -244,7 +244,8 @@ #endif /* CONFIG_ADB */ #define WAIT_FOR(cond, what) \ - do { \ + do { \ + int x; \ for (x = 1000; !(cond); --x) { \ if (x == 0) { \ printk("Timeout waiting for " what "\n"); \ @@ -257,40 +258,40 @@ static int cuda_init_via() { - int x; - - via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; /* TACK & TIP out */ - via[B] |= TACK | TIP; /* negate them */ - via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; /* SR data in */ - eieio(); - x = via[SR]; eieio(); /* clear any left-over data */ + out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */ + out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */ + out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */ + (void)in_8(&via[SR]); /* clear any left-over data */ #ifndef CONFIG_MAC - via[IER] = 0x7f; eieio(); /* disable interrupts from VIA */ + out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ + (void)in_8(&via[IER]); #endif - eieio(); /* delay 4ms and then clear any pending interrupt */ mdelay(4); - x = via[SR]; eieio(); + (void)in_8(&via[SR]); + out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); /* sync with the CUDA - assert TACK without TIP */ - via[B] &= ~TACK; eieio(); + out_8(&via[B], in_8(&via[B]) & ~TACK); /* wait for the CUDA to assert TREQ in response */ - WAIT_FOR((via[B] & TREQ) == 0, "CUDA response to sync"); + WAIT_FOR((in_8(&via[B]) & TREQ) == 0, "CUDA response to sync"); /* wait for the interrupt and then clear it */ - WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (2)"); - x = via[SR]; eieio(); + WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)"); + (void)in_8(&via[SR]); + out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); /* finish the sync by negating TACK */ - via[B] |= TACK; eieio(); + out_8(&via[B], in_8(&via[B]) | TACK); /* wait for the CUDA to negate TREQ and the corresponding interrupt */ - WAIT_FOR(via[B] & TREQ, "CUDA response to sync (3)"); - WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (4)"); - x = via[SR]; eieio(); - via[B] |= TIP; eieio(); /* should be unnecessary */ + WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)"); + WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)"); + (void)in_8(&via[SR]); + out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); + out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */ return 0; } @@ -413,55 +414,59 @@ req = current_req; if (req == 0) return; - if ((via[B] & TREQ) == 0) + if ((in_8(&via[B]) & TREQ) == 0) return; /* a byte is coming in from the CUDA */ /* set the shift register to shift out and send a byte */ - via[ACR] |= SR_OUT; eieio(); - via[SR] = req->data[0]; eieio(); - via[B] &= ~TIP; + out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT); + out_8(&via[SR], req->data[0]); + out_8(&via[B], in_8(&via[B]) & ~TIP); cuda_state = sent_first_byte; } void cuda_poll() { - if (via[IFR] & SR_INT) { - unsigned long flags; + unsigned long flags; - /* cuda_interrupt only takes a normal lock, we disable - * interrupts here to avoid re-entering and thus deadlocking. - * An option would be to disable only the IRQ source with - * disable_irq(), would that work on m68k ? --BenH - */ - local_irq_save(flags); - cuda_interrupt(0, 0, 0); - local_irq_restore(flags); - } + /* cuda_interrupt only takes a normal lock, we disable + * interrupts here to avoid re-entering and thus deadlocking. + * An option would be to disable only the IRQ source with + * disable_irq(), would that work on m68k ? --BenH + */ + local_irq_save(flags); + cuda_interrupt(0, 0, 0); + local_irq_restore(flags); } static void cuda_interrupt(int irq, void *arg, struct pt_regs *regs) { - int x, status; + int status; struct adb_request *req = NULL; unsigned char ibuf[16]; int ibuf_len = 0; int complete = 0; + unsigned char virq; - if ((via[IFR] & SR_INT) == 0) - return; - spin_lock(&cuda_lock); - status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio(); + + virq = in_8(&via[IFR]) & 0x7f; + out_8(&via[IFR], virq); + if ((virq & SR_INT) == 0) { + spin_unlock(&cuda_lock); + return; + } + + status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT); /* printk("cuda_interrupt: state=%d status=%x\n", cuda_state, status); */ switch (cuda_state) { case idle: /* CUDA has sent us the first byte of data - unsolicited */ if (status != TREQ) printk("cuda: state=idle, status=%x\n", status); - x = via[SR]; eieio(); - via[B] &= ~TIP; eieio(); + (void)in_8(&via[SR]); + out_8(&via[B], in_8(&via[B]) & ~TIP); cuda_state = reading; reply_ptr = cuda_rbuf; reading_reply = 0; @@ -471,8 +476,8 @@ /* CUDA has sent us the first byte of data of a reply */ if (status != TREQ) printk("cuda: state=awaiting_reply, status=%x\n", status); - x = via[SR]; eieio(); - via[B] &= ~TIP; eieio(); + (void)in_8(&via[SR]); + out_8(&via[B], in_8(&via[B]) & ~TIP); cuda_state = reading; reply_ptr = current_req->reply; reading_reply = 1; @@ -481,16 +486,16 @@ case sent_first_byte: if (status == TREQ + TIP + SR_OUT) { /* collision */ - via[ACR] &= ~SR_OUT; eieio(); - x = via[SR]; eieio(); - via[B] |= TIP | TACK; eieio(); + out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT); + (void)in_8(&via[SR]); + out_8(&via[B], in_8(&via[B]) | TIP | TACK); cuda_state = idle; } else { /* assert status == TIP + SR_OUT */ if (status != TIP + SR_OUT) printk("cuda: state=sent_first_byte status=%x\n", status); - via[SR] = current_req->data[1]; eieio(); - via[B] ^= TACK; eieio(); + out_8(&via[SR], current_req->data[1]); + out_8(&via[B], in_8(&via[B]) ^ TACK); data_index = 2; cuda_state = sending; } @@ -499,9 +504,9 @@ case sending: req = current_req; if (data_index >= req->nbytes) { - via[ACR] &= ~SR_OUT; eieio(); - x = via[SR]; eieio(); - via[B] |= TACK | TIP; eieio(); + out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT); + (void)in_8(&via[SR]); + out_8(&via[B], in_8(&via[B]) | TACK | TIP); req->sent = 1; if (req->reply_expected) { cuda_state = awaiting_reply; @@ -513,27 +518,27 @@ cuda_start(); } } else { - via[SR] = req->data[data_index++]; eieio(); - via[B] ^= TACK; eieio(); + out_8(&via[SR], req->data[data_index++]); + out_8(&via[B], in_8(&via[B]) ^ TACK); } break; case reading: - *reply_ptr++ = via[SR]; eieio(); + *reply_ptr++ = in_8(&via[SR]); if (status == TIP) { /* that's all folks */ - via[B] |= TACK | TIP; eieio(); + out_8(&via[B], in_8(&via[B]) | TACK | TIP); cuda_state = read_done; } else { /* assert status == TIP | TREQ */ if (status != TIP + TREQ) printk("cuda: state=reading status=%x\n", status); - via[B] ^= TACK; eieio(); + out_8(&via[B], in_8(&via[B]) ^ TACK); } break; case read_done: - x = via[SR]; eieio(); + (void)in_8(&via[SR]); if (reading_reply) { req = current_req; req->reply_len = reply_ptr - req->reply; @@ -548,7 +553,6 @@ memmove(req->reply, req->reply + 2, req->reply_len); } } - req->complete = 1; current_req = req->next; complete = 1; } else { @@ -563,7 +567,7 @@ memcpy(ibuf, cuda_rbuf, ibuf_len); } if (status == TREQ) { - via[B] &= ~TIP; eieio(); + out_8(&via[B], in_8(&via[B]) & ~TIP); cuda_state = reading; reply_ptr = cuda_rbuf; reading_reply = 0; @@ -577,8 +581,16 @@ printk("cuda_interrupt: unknown cuda_state %d?\n", cuda_state); } spin_unlock(&cuda_lock); - if (complete && req && req->done) - (*req->done)(req); + if (complete && req) { + void (*done)(struct adb_request *) = req->done; + mb(); + req->complete = 1; + /* Here, we assume that if the request has a done member, the + * struct request will survive to setting req->complete to 1 + */ + if (done) + (*done)(req); + } if (ibuf_len) cuda_input(ibuf, ibuf_len, regs); } diff -uNr linux-2.4.20/drivers/macintosh/via-pmu.c linux-2.4.20-ben6/drivers/macintosh/via-pmu.c --- linux-2.4.20/drivers/macintosh/via-pmu.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/macintosh/via-pmu.c 2003-02-16 20:21:28.000000000 +0100 @@ -345,11 +345,6 @@ } else pmu_kind = PMU_UNKNOWN; -#ifdef CONFIG_PMAC_PBOOK - if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) - can_sleep = 1; -#endif /* CONFIG_PMAC_PBOOK */ - via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ @@ -410,6 +405,8 @@ bright_req_3.complete = 1; #ifdef CONFIG_PMAC_PBOOK batt_req.complete = 1; + if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) + can_sleep = 1; #endif if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", @@ -436,12 +433,20 @@ #ifdef CONFIG_PMAC_PBOOK if (machine_is_compatible("AAPL,3400/2400") || - machine_is_compatible("AAPL,3500")) + machine_is_compatible("AAPL,3500")) { + int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_MODEL, 0); pmu_battery_count = 1; - else if (machine_is_compatible("AAPL,PowerBook1998") || - machine_is_compatible("PowerBook1,1")) + if (mb == PMAC_TYPE_COMET) + pmu_batteries[0].flags |= PMU_BATT_TYPE_COMET; + else + pmu_batteries[0].flags |= PMU_BATT_TYPE_HOOPER; + } else if (machine_is_compatible("AAPL,PowerBook1998") || + machine_is_compatible("PowerBook1,1")) { pmu_battery_count = 2; - else { + pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART; + pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; + } else { struct device_node* prim = find_devices("power-mgt"); u32 *prim_info = NULL; if (prim) @@ -449,6 +454,9 @@ if (prim_info) { /* Other stuffs here yet unknown */ pmu_battery_count = (prim_info[6] >> 16) & 0xff; + pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART; + if (pmu_battery_count > 1) + pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART; } } #endif /* CONFIG_PMAC_PBOOK */ @@ -558,148 +566,12 @@ #ifdef CONFIG_PMAC_PBOOK -/* - * WARNING ! This code probably needs some debugging... -- BenH. +/* This new version of the code for 2400/3400/3500 powerbooks + * is inspired from the implementation in gkrellm-pmu */ -#ifdef NEW_OHARE_CODE -static void __pmac -done_battery_state_ohare(struct adb_request* req) -{ - unsigned int bat_flags = 0; - int current = 0; - unsigned int capa, max, voltage, time; - int lrange[] = { 0, 275, 850, 1680, 2325, - 2765, 3160, 3500, 3830, 4115, - 4360, 4585, 4795, 4990, 5170, - 5340, 5510, 5710, 5930, 6150, - 6370, 6500 - }; - - if (req->reply[0] & 0x01) - pmu_power_flags |= PMU_PWR_AC_PRESENT; - else - pmu_power_flags &= ~PMU_PWR_AC_PRESENT; - - if (req->reply[0] & 0x04) { - int vb, i, j, k, charge, pcharge; - bat_flags |= PMU_BATT_PRESENT; - vb = (req->reply[1] << 8) | req->reply[2]; - voltage = ((vb * 2650) + 726650)/100; - vb *= 100; - current = req->reply[5]; - if ((req->reply[0] & 0x01) == 0 && (current > 200)) - vb += (current - 200) * 15; - else if (req->reply[0] & 0x02) - vb = (vb - 2000); - i = (33000 - vb) / 10; - j = i - (i % 100); - k = j/100; - if (k <= 0) - charge = 0; - else if (k >= 21) - charge = 650000; - else - charge = (lrange[k + 1] - lrange[k]) * (i - j) + (lrange[k] * 100); - charge = (1000 - charge / 650) / 10; - if (req->reply[0] & 0x40) { - pcharge = (req->reply[6] << 8) + req->reply[7]; - if (pcharge > 6500) - pcharge = 6500; - pcharge *= 100; - pcharge = (1000 - pcharge / 650) / 10; - if (pcharge < charge) - charge = pcharge; - } - capa = charge; - max = 100; - time = (charge * 16440) / current; - current = -current; - - } else - capa = max = current = voltage = time = 0; - - if (req->reply[0] & 0x02) - bat_flags |= PMU_BATT_CHARGING; - - pmu_batteries[pmu_cur_battery].flags = bat_flags; - pmu_batteries[pmu_cur_battery].charge = capa; - pmu_batteries[pmu_cur_battery].max_charge = max; - pmu_batteries[pmu_cur_battery].current = current; - pmu_batteries[pmu_cur_battery].voltage = voltage; - pmu_batteries[pmu_cur_battery].time_remaining = time; -} -#else /* NEW_OHARE_CODE */ static void __pmac done_battery_state_ohare(struct adb_request* req) { - unsigned int bat_flags = 0; - int current = 0; - unsigned int capa, max, voltage, time; - int lrange[] = { 0, 275, 850, 1680, 2325, - 2765, 3160, 3500, 3830, 4115, - 4360, 4585, 4795, 4990, 5170, - 5340, 5510, 5710, 5930, 6150, - 6370, 6500 - }; - - if (req->reply[0] & 0x01) - pmu_power_flags |= PMU_PWR_AC_PRESENT; - else - pmu_power_flags &= ~PMU_PWR_AC_PRESENT; - - if (req->reply[0] & 0x04) { - int vb, i, j, charge, pcharge; - bat_flags |= PMU_BATT_PRESENT; - vb = (req->reply[1] << 8) | req->reply[2]; - voltage = ((vb * 2650) + 726650)/100; - current = *((signed char *)&req->reply[5]); - if ((req->reply[0] & 0x01) == 0 && (current > 200)) - vb += (current - 200) * 15; - else if (req->reply[0] & 0x02) - vb = (vb - 10) * 100; - i = (33000 - vb) / 10; - j = i - (i % 100); - if (j <= 0) - charge = 0; - else if (j >= 21) - charge = 650000; - else - charge = (lrange[j + 1] - lrange[j]) * (i - j) + (lrange[j] * 100); - charge = (1000 - charge / 650) / 10; - if (req->reply[0] & 0x40) { - pcharge = (req->reply[6] << 8) + req->reply[7]; - if (pcharge > 6500) - pcharge = 6500; - pcharge *= 100; - pcharge = (1000 - pcharge / 650) / 10; - if (pcharge < charge) - charge = pcharge; - } - capa = charge; - max = 100; - time = (charge * 274) / current; - current = -current; - - } else - capa = max = current = voltage = time = 0; - - if ((req->reply[0] & 0x02) && (current > 0)) - bat_flags |= PMU_BATT_CHARGING; - if (req->reply[0] & 0x04) /* CHECK THIS ONE */ - bat_flags |= PMU_BATT_PRESENT; - - pmu_batteries[pmu_cur_battery].flags = bat_flags; - pmu_batteries[pmu_cur_battery].charge = capa; - pmu_batteries[pmu_cur_battery].max_charge = max; - pmu_batteries[pmu_cur_battery].current = current; - pmu_batteries[pmu_cur_battery].voltage = voltage; - pmu_batteries[pmu_cur_battery].time_remaining = time; -} -#endif /* NEW_OHARE_CODE */ - - static void __pmac -done_battery_state_comet(struct adb_request* req) -{ /* format: * [0] : flags * 0x01 : AC indicator @@ -718,57 +590,62 @@ * [6][7] : pcharge * --tkoba */ + unsigned int bat_flags = PMU_BATT_TYPE_HOOPER; + long pcharge, charge, vb, vmax, lmax; + long vmax_charging, vmax_charged; + long current, voltage, time, max; + int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, + NULL, PMAC_MB_INFO_MODEL, 0); - unsigned int bat_flags = 0; - int current = 0; - unsigned int max = 100; - unsigned int charge, voltage, time; - int lrange[] = { 0, 600, 750, 900, 1000, 1080, - 1180, 1250, 1300, 1340, 1360, - 1390, 1420, 1440, 1470, 1490, - 1520, 1550, 1580, 1610, 1650, - 1700 - }; - if (req->reply[0] & 0x01) pmu_power_flags |= PMU_PWR_AC_PRESENT; else pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + if (mb == PMAC_TYPE_COMET) { + vmax_charged = 189; + vmax_charging = 213; + lmax = 6500; + } else { + vmax_charged = 330; + vmax_charging = 330; + lmax = 6500; + } + vmax = vmax_charged; - if (req->reply[0] & 0x04) { /* battery exist */ - int vb, i; + /* If battery installed */ + if (req->reply[0] & 0x04) { bat_flags |= PMU_BATT_PRESENT; + if (req->reply[0] & 0x02) + bat_flags |= PMU_BATT_CHARGING; vb = (req->reply[1] << 8) | req->reply[2]; - voltage = ((vb * 2650) + 726650)/100; - vb *= 10; + voltage = (vb * 265 + 72665) / 10; current = req->reply[5]; - if ((req->reply[0] & 0x01) == 0 && (current > 200)) - vb += ((current - 200) * 3); /* vb = 500<->1800 */ - else if (req->reply[0] & 0x02) - vb = ((vb - 800) * 1700/13)/100; /* in charging vb = 1300<->2130 */ - - if (req->reply[0] & 0x20) { /* full charged */ - charge = max; - } else { - if (lrange[21] < vb) - charge = max; - else { - if (vb < lrange[1]) - charge = 0; - else { - for (i=21; vb < lrange[i]; --i); - charge = (i * 100)/21; - } - } - if (charge > max) charge = max; + if ((req->reply[0] & 0x01) == 0) { + if (current > 200) + vb += ((current - 200) * 15)/100; + } else if (req->reply[0] & 0x02) { + vb = (vb * 97) / 100; + vmax = vmax_charging; } - time = (charge * 72); + charge = (100 * vb) / vmax; + if (req->reply[0] & 0x40) { + pcharge = (req->reply[6] << 8) + req->reply[7]; + if (pcharge > lmax) + pcharge = lmax; + pcharge *= 100; + pcharge = 100 - pcharge / lmax; + if (pcharge < charge) + charge = pcharge; + } + if (current > 0) + time = (charge * 16440) / current; + else + time = 0; + max = 100; current = -current; } else - max = current = voltage = time = 0; - - if (req->reply[0] & 0x02) - bat_flags |= PMU_BATT_CHARGING; + charge = max = current = voltage = time = 0; pmu_batteries[pmu_cur_battery].flags = bat_flags; pmu_batteries[pmu_cur_battery].charge = charge; @@ -800,7 +677,7 @@ * [8][9] : voltage */ - unsigned int bat_flags = 0; + unsigned int bat_flags = PMU_BATT_TYPE_SMART; int current; unsigned int capa, max, voltage; @@ -858,17 +735,10 @@ { if (!batt_req.complete) return; - if (pmu_kind == PMU_OHARE_BASED) { - int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO, - NULL, PMAC_MB_INFO_MODEL, 0); - - if (mb == PMAC_TYPE_COMET) - pmu_request(&batt_req, done_battery_state_comet, - 1, PMU_BATTERY_STATE); - else - pmu_request(&batt_req, done_battery_state_ohare, - 1, PMU_BATTERY_STATE); - } else + if (pmu_kind == PMU_OHARE_BASED) + pmu_request(&batt_req, done_battery_state_ohare, + 1, PMU_BATTERY_STATE); + else pmu_request(&batt_req, done_battery_state_smart, 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1); } @@ -1220,9 +1090,14 @@ static inline void pmu_done(struct adb_request *req) { + void (*done)(struct adb_request *) = req->done; + mb(); req->complete = 1; - if (req->done) - (*req->done)(req); + /* Here, we assume that if the request has a done member, the + * struct request will survive to setting req->complete to 1 + */ + if (done) + (*done)(req); } static void __openfirmware diff -uNr linux-2.4.20/drivers/net/Makefile linux-2.4.20-ben6/drivers/net/Makefile --- linux-2.4.20/drivers/net/Makefile 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/net/Makefile 2003-02-16 20:20:24.000000000 +0100 @@ -17,7 +17,7 @@ export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o \ ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \ - net_init.o mii.o + net_init.o mii.o sungem_phy.o list-multi := rcpci.o rcpci-objs := rcpci45.o rclanmtl.o @@ -59,7 +59,7 @@ obj-$(CONFIG_SUNQE) += sunqe.o obj-$(CONFIG_SUNBMAC) += sunbmac.o obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o -obj-$(CONFIG_SUNGEM) += sungem.o +obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o diff -uNr linux-2.4.20/drivers/net/bmac.c linux-2.4.20-ben6/drivers/net/bmac.c --- linux-2.4.20/drivers/net/bmac.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/net/bmac.c 2003-02-16 20:20:13.000000000 +0100 @@ -1403,7 +1403,7 @@ memset((char *) bp->tx_cmds, 0, (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); - /* init_timer(&bp->tx_timeout); */ + init_timer(&bp->tx_timeout); /* bp->timeout_active = 0; */ ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev); diff -uNr linux-2.4.20/drivers/net/gmac.c linux-2.4.20-ben6/drivers/net/gmac.c --- linux-2.4.20/drivers/net/gmac.c 2002-11-29 00:53:13.000000000 +0100 +++ linux-2.4.20-ben6/drivers/net/gmac.c 2003-02-16 20:20:23.000000000 +0100 @@ -1622,6 +1622,7 @@ gm->of_node = gmac; if (!request_OF_resource(gmac, 0, " (gmac)")) { printk(KERN_ERR "GMAC: can't request IO resource !\n"); + gm->of_node = NULL; goto out_unreg; } dev->base_addr = gmac->addrs[0].address; diff -uNr linux-2.4.20/drivers/net/mace.c linux-2.4.20-ben6/drivers/net/mace.c --- linux-2.4.20/drivers/net/mace.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/net/mace.c 2003-02-16 20:20:40.000000000 +0100 @@ -1,6 +1,8 @@ /* * Network device driver for the MACE ethernet controller on * Apple Powermacs. Assumes it's under a DBDMA controller. + * + * MACE is beleived to be an AMD 79C940 * * Copyright (C) 1996 Paul Mackerras. */ diff -uNr linux-2.4.20/drivers/net/ne2k-pci.c linux-2.4.20-ben6/drivers/net/ne2k-pci.c --- linux-2.4.20/drivers/net/ne2k-pci.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/net/ne2k-pci.c 2003-02-16 20:20:13.000000000 +0100 @@ -69,8 +69,6 @@ #if defined(__powerpc__) #define inl_le(addr) le32_to_cpu(inl(addr)) #define inw_le(addr) le16_to_cpu(inw(addr)) -#define insl insl_ns -#define outsl outsl_ns #endif #define PFX DRV_NAME ": " diff -uNr linux-2.4.20/drivers/net/pcnet32.c linux-2.4.20-ben6/drivers/net/pcnet32.c --- linux-2.4.20/drivers/net/pcnet32.c 2002-11-29 00:53:14.000000000 +0100 +++ linux-2.4.20-ben6/drivers/net/pcnet32.c 2003-02-16 20:21:14.000000000 +0100 @@ -575,7 +575,7 @@ break; case 0x2625: chipname = "PCnet/FAST III 79C973"; /* PCI */ - fdx = 1; mii = 1; + fdx = 1; mii = 1; fset = 1; break; case 0x2626: chipname = "PCnet/Home 79C978"; /* PCI */ @@ -618,6 +618,7 @@ if(fset) { + printk(KERN_INFO PFX "Activating Tx error recovery on %s\n", chipname); a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800)); a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); dxsuflo = 1; diff -uNr linux-2.4.20/drivers/net/sungem.c linux-2.4.20-ben6/drivers/net/sungem.c --- linux-2.4.20/drivers/net/sungem.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/net/sungem.c 2003-02-16 20:20:40.000000000 +0100 @@ -10,10 +10,6 @@ * - Get rid of all those nasty mdelay's and replace them * with schedule_timeout. * - Implement WOL - * - Currently, forced Gb mode is only supported on bcm54xx - * PHY for which I use the SPD2 bit of the control register. - * On m1011 PHY, I can't force as I don't have the specs, but - * I can at least detect gigabit with autoneg. */ #include @@ -63,12 +59,17 @@ #include #endif +#include "sungem_phy.h" #include "sungem.h" #define DEFAULT_MSG (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ NETIF_MSG_LINK) +#define ADVERTISE_MASK (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) + #define DRV_NAME "sungem" #define DRV_VERSION "0.97" #define DRV_RELDATE "3/20/02" @@ -83,21 +84,14 @@ MODULE_PARM(gem_debug, "i"); MODULE_PARM_DESC(gem_debug, "bitmapped message enable number"); -MODULE_PARM(link_mode, "i"); -MODULE_PARM_DESC(link_mode, "default link mode"); +MODULE_PARM(forced_speed, "i"); +MODULE_PARM(forced_duplex, "i"); +MODULE_PARM_DESC(forced_speed, "force link speed (10,100,1000)"); +MODULE_PARM_DESC(forced_duplex, "force link duplex (0: half, 1: full)"); int gem_debug = -1; -static int link_mode; - -static u16 link_modes[] __devinitdata = { - BMCR_ANENABLE, /* 0 : autoneg */ - 0, /* 1 : 10bt half duplex */ - BMCR_SPEED100, /* 2 : 100bt half duplex */ - BMCR_SPD2, /* bcm54xx only */ /* 3 : 1000bt half duplex */ - BMCR_FULLDPLX, /* 4 : 10bt full duplex */ - BMCR_SPEED100|BMCR_FULLDPLX, /* 5 : 100bt full duplex */ - BMCR_SPD2|BMCR_FULLDPLX /* 6 : 1000bt full duplex */ -}; +static int forced_speed = -1; +static int forced_duplex = -1; #define GEM_MODULE_NAME "gem" #define PFX GEM_MODULE_NAME ": " @@ -119,12 +113,14 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMACP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMAC2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, {0, } }; MODULE_DEVICE_TABLE(pci, gem_pci_tbl); -static u16 __phy_read(struct gem *gp, int reg, int phy_addr) +static u16 __phy_read(struct gem *gp, int phy_addr, int reg) { u32 cmd; int limit = 10000; @@ -150,12 +146,18 @@ return cmd & MIF_FRAME_DATA; } +static inline int _phy_read(struct net_device *dev, int mii_id, int reg) +{ + struct gem *gp = dev->priv; + return __phy_read(gp, mii_id, reg); +} + static inline u16 phy_read(struct gem *gp, int reg) { - return __phy_read(gp, reg, gp->mii_phy_addr); + return __phy_read(gp, gp->mii_phy_addr, reg); } -static void __phy_write(struct gem *gp, int reg, u16 val, int phy_addr) +static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val) { u32 cmd; int limit = 10000; @@ -177,9 +179,15 @@ } } +static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val) +{ + struct gem *gp = dev->priv; + __phy_write(gp, mii_id, reg, val & 0xffff); +} + static inline void phy_write(struct gem *gp, int reg, u16 val) { - __phy_write(gp, reg, val, gp->mii_phy_addr); + __phy_write(gp, gp->mii_phy_addr, reg, val); } static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits) @@ -228,10 +236,11 @@ if (pcs_miistat & PCS_MIISTAT_LS) { printk(KERN_INFO "%s: PCS link is now up.\n", dev->name); + netif_carrier_on(gp->dev); } else { printk(KERN_INFO "%s: PCS link is now down.\n", dev->name); - + netif_carrier_off(gp->dev); /* If this happens and the link timer is not running, * reset so we re-negotiate. */ @@ -359,6 +368,7 @@ rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); } + io_barrier(); gp->rx_new = gp->rx_old = 0; /* Now we must reprogram the rest of RX unit. */ @@ -667,6 +677,7 @@ count = 0; } } + io_barrier(); if (kick >= 0) writel(kick, gp->regs + RXDMA_KICK); } @@ -936,6 +947,7 @@ if (netif_msg_tx_queued(gp)) printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", dev->name, entry, skb->len); + io_barrier(); writel(gp->tx_new, gp->regs + TXDMA_KICK); spin_unlock_irq(&gp->lock); @@ -1003,7 +1015,7 @@ } while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST)); if (limit <= 0) - printk(KERN_ERR "gem: SW reset is ghetto.\n"); + printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name); } /* Must be invoked under gp->lock. */ @@ -1030,136 +1042,118 @@ } -/* Link modes of the BCM5400 PHY */ -static int phy_BCM5400_link_table[8][3] = { - { 0, 0, 0 }, /* No link */ - { 0, 0, 0 }, /* 10BT Half Duplex */ - { 1, 0, 0 }, /* 10BT Full Duplex */ - { 0, 1, 0 }, /* 100BT Half Duplex */ - { 0, 1, 0 }, /* 100BT Half Duplex */ - { 1, 1, 0 }, /* 100BT Full Duplex*/ - { 1, 0, 1 }, /* 1000BT */ - { 1, 0, 1 }, /* 1000BT */ -}; /* Must be invoked under gp->lock. */ +// XXX dbl check what that function should do when called on PCS PHY static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) { - u16 ctl; + u32 advertise, features; + int autoneg; + int speed; + int duplex; + + if (gp->phy_type != phy_mii_mdio0 && + gp->phy_type != phy_mii_mdio1) + goto non_mii; + + /* Setup advertise */ + if (found_mii_phy(gp)) + features = gp->phy_mii.def->features; + else + features = 0; + + advertise = features & ADVERTISE_MASK; + if (gp->phy_mii.advertising != 0) + advertise &= gp->phy_mii.advertising; + + autoneg = gp->want_autoneg; + speed = gp->phy_mii.speed; + duplex = gp->phy_mii.duplex; /* Setup link parameters */ if (!ep) goto start_aneg; if (ep->autoneg == AUTONEG_ENABLE) { - /* TODO: parse ep->advertising */ - gp->link_advertise |= (ADVERTISE_10HALF | ADVERTISE_10FULL); - gp->link_advertise |= (ADVERTISE_100HALF | ADVERTISE_100FULL); - /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ - gp->link_cntl = BMCR_ANENABLE; + advertise = ep->advertising; + autoneg = 1; } else { - gp->link_cntl = 0; - if (ep->speed == SPEED_100) - gp->link_cntl |= BMCR_SPEED100; - else if (ep->speed == SPEED_1000 && gp->gigabit_capable) - /* Hrm... check if this is right... */ - gp->link_cntl |= BMCR_SPD2; - if (ep->duplex == DUPLEX_FULL) - gp->link_cntl |= BMCR_FULLDPLX; + autoneg = 0; + speed = ep->speed; + duplex = ep->duplex; } start_aneg: - if (!gp->hw_running) + /* Sanitize settings based on PHY capabilities */ + if ((features & SUPPORTED_Autoneg) == 0) + autoneg = 0; + if (speed == SPEED_1000 && + !(features & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full))) + speed = SPEED_100; + if (speed == SPEED_100 && + !(features & (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full))) + speed = SPEED_10; + if (duplex == DUPLEX_FULL && + !(features & (SUPPORTED_1000baseT_Full | + SUPPORTED_100baseT_Full | + SUPPORTED_10baseT_Full))) + duplex = DUPLEX_HALF; + if (speed == 0) + speed = SPEED_10; + + /* If HW is down, we don't try to actually setup the PHY, we + * just store the settings + */ + if (!gp->hw_running) { + gp->phy_mii.autoneg = gp->want_autoneg = autoneg; + gp->phy_mii.speed = speed; + gp->phy_mii.duplex = duplex; return; + } /* Configure PHY & start aneg */ - ctl = phy_read(gp, MII_BMCR); - ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE); - ctl |= gp->link_cntl; - if (ctl & BMCR_ANENABLE) { - ctl |= BMCR_ANRESTART; + gp->want_autoneg = autoneg; + if (autoneg) { + if (found_mii_phy(gp)) + gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, advertise); gp->lstate = link_aneg; } else { + if (found_mii_phy(gp)) + gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, speed, duplex); gp->lstate = link_force_ok; } - phy_write(gp, MII_BMCR, ctl); +non_mii: gp->timer_ticks = 0; mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); } -/* Must be invoked under gp->lock. */ -static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause) -{ - u32 val; - - *fd = 0; - *spd = 10; - *pause = 0; - - if (gp->phy_mod == phymod_bcm5400 || - gp->phy_mod == phymod_bcm5401 || - gp->phy_mod == phymod_bcm5411) { - int link_mode; - - val = phy_read(gp, MII_BCM5400_AUXSTATUS); - link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> - MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); - *fd = phy_BCM5400_link_table[link_mode][0]; - *spd = phy_BCM5400_link_table[link_mode][2] ? - 1000 : - (phy_BCM5400_link_table[link_mode][1] ? 100 : 10); - val = phy_read(gp, MII_LPA); - if (val & LPA_PAUSE) - *pause = 1; - } else { - val = phy_read(gp, MII_LPA); - - if (val & (LPA_10FULL | LPA_100FULL)) - *fd = 1; - if (val & (LPA_100FULL | LPA_100HALF)) - *spd = 100; - - if (gp->phy_mod == phymod_m1011) { - val = phy_read(gp, 0x0a); - if (val & 0xc00) - *spd = 1000; - if (val & 0x800) - *fd = 1; - } - } -} - /* A link-up condition has occurred, initialize and enable the * rest of the chip. * * Must be invoked under gp->lock. */ -static void gem_set_link_modes(struct gem *gp) +static int gem_set_link_modes(struct gem *gp) { u32 val; int full_duplex, speed, pause; full_duplex = 0; - speed = 10; + speed = SPEED_10; pause = 0; - if (gp->phy_type == phy_mii_mdio0 || - gp->phy_type == phy_mii_mdio1) { - val = phy_read(gp, MII_BMCR); - if (val & BMCR_ANENABLE) - gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause); - else { - if (val & BMCR_FULLDPLX) - full_duplex = 1; - if (val & BMCR_SPEED100) - speed = 100; - } - } else { + if (found_mii_phy(gp)) { + if (gp->phy_mii.def->ops->read_link(&gp->phy_mii)) + return 1; + full_duplex = (gp->phy_mii.duplex == DUPLEX_FULL); + speed = gp->phy_mii.speed; + pause = gp->phy_mii.pause; + } else if (gp->phy_type == phy_serialink || + gp->phy_type == phy_serdes) { u32 pcs_lpa = readl(gp->regs + PCS_MIILP); if (pcs_lpa & PCS_MIIADV_FD) full_duplex = 1; - speed = 1000; + speed = SPEED_1000; } if (netif_msg_link(gp)) @@ -1183,7 +1177,7 @@ val |= MAC_XIFCFG_FLED; } - if (speed == 1000) + if (speed == SPEED_1000) val |= (MAC_XIFCFG_GMII); writel(val, gp->regs + MAC_XIFCFG); @@ -1191,7 +1185,7 @@ /* If gigabit and half-duplex, enable carrier extension * mode. Else, disable it. */ - if (speed == 1000 && !full_duplex) { + if (speed == SPEED_1000 && !full_duplex) { val = readl(gp->regs + MAC_TXCFG); writel(val | MAC_TXCFG_TCE, gp->regs + MAC_TXCFG); @@ -1239,50 +1233,51 @@ writel(val, gp->regs + MAC_MCCFG); gem_start_dma(gp); + + return 0; } /* Must be invoked under gp->lock. */ static int gem_mdio_link_not_up(struct gem *gp) { - u16 val; - - if (gp->lstate == link_force_ret) { + switch (gp->lstate) { + case link_force_ret: if (netif_msg_link(gp)) printk(KERN_INFO "%s: Autoneg failed again, keeping" " forced mode\n", gp->dev->name); - phy_write(gp, MII_BMCR, gp->link_fcntl); + gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, + gp->last_forced_speed, DUPLEX_HALF); gp->timer_ticks = 5; gp->lstate = link_force_ok; - } else if (gp->lstate == link_aneg) { - val = phy_read(gp, MII_BMCR); - + return 0; + case link_aneg: if (netif_msg_link(gp)) printk(KERN_INFO "%s: switching to forced 100bt\n", gp->dev->name); /* Try forced modes. */ - val &= ~(BMCR_ANRESTART | BMCR_ANENABLE); - val &= ~(BMCR_FULLDPLX); - val |= BMCR_SPEED100; - phy_write(gp, MII_BMCR, val); + gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_100, + DUPLEX_HALF); gp->timer_ticks = 5; gp->lstate = link_force_try; - } else { + return 0; + case link_force_try: /* Downgrade from 100 to 10 Mbps if necessary. * If already at 10Mbps, warn user about the * situation every 10 ticks. */ - val = phy_read(gp, MII_BMCR); - if (val & BMCR_SPEED100) { - val &= ~BMCR_SPEED100; - phy_write(gp, MII_BMCR, val); + if (gp->phy_mii.speed == SPEED_100) { + gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_10, + DUPLEX_HALF); gp->timer_ticks = 5; if (netif_msg_link(gp)) printk(KERN_INFO "%s: switching to forced 10bt\n", gp->dev->name); + return 0; } else return 1; + default: + return 0; } - return 0; } static void gem_init_rings(struct gem *); @@ -1322,7 +1317,8 @@ static void gem_link_timer(unsigned long data) { struct gem *gp = (struct gem *) data; - + int restart_aneg = 0; + if (!gp->hw_running) return; @@ -1334,62 +1330,8 @@ if (gp->reset_task_pending) goto restart; - if (gp->phy_type == phy_mii_mdio0 || - gp->phy_type == phy_mii_mdio1) { - u16 val = phy_read(gp, MII_BMSR); - u16 cntl = phy_read(gp, MII_BMCR); - int up; - - /* When using autoneg, we really wait for ANEGCOMPLETE or we may - * get a "transcient" incorrect link state - */ - if (cntl & BMCR_ANENABLE) - up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS); - else - up = (val & BMSR_LSTATUS) != 0; - if (up) { - /* Ok, here we got a link. If we had it due to a forced - * fallback, and we were configured for autoneg, we do - * retry a short autoneg pass. If you know your hub is - * broken, use ethtool ;) - */ - if (gp->lstate == link_force_try && (gp->link_cntl & BMCR_ANENABLE)) { - gp->lstate = link_force_ret; - gp->link_fcntl = phy_read(gp, MII_BMCR); - gp->timer_ticks = 5; - if (netif_msg_link(gp)) - printk(KERN_INFO "%s: Got link after fallback, retrying" - " autoneg once...\n", gp->dev->name); - phy_write(gp, MII_BMCR, - gp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART); - } else if (gp->lstate != link_up) { - gp->lstate = link_up; - if (gp->opened) - gem_set_link_modes(gp); - } - } else { - int restart = 0; - - /* If the link was previously up, we restart the - * whole process - */ - if (gp->lstate == link_up) { - gp->lstate = link_down; - if (netif_msg_link(gp)) - printk(KERN_INFO "%s: Link down\n", - gp->dev->name); - gp->reset_task_pending = 2; - schedule_task(&gp->reset_task); - restart = 1; - } else if (++gp->timer_ticks > 10) - restart = gem_mdio_link_not_up(gp); - - if (restart) { - gem_begin_auto_negotiation(gp, NULL); - goto out_unlock; - } - } - } else { + if (gp->phy_type == phy_serialink || + gp->phy_type == phy_serdes) { u32 val = readl(gp->regs + PCS_MIISTAT); if (!(val & PCS_MIISTAT_LS)) @@ -1397,11 +1339,56 @@ if ((val & PCS_MIISTAT_LS) != 0) { gp->lstate = link_up; + netif_carrier_on(gp->dev); if (gp->opened) - gem_set_link_modes(gp); + (void)gem_set_link_modes(gp); } + goto restart; + } + if (found_mii_phy(gp) && gp->phy_mii.def->ops->poll_link(&gp->phy_mii)) { + /* Ok, here we got a link. If we had it due to a forced + * fallback, and we were configured for autoneg, we do + * retry a short autoneg pass. If you know your hub is + * broken, use ethtool ;) + */ + if (gp->lstate == link_force_try && gp->want_autoneg) { + gp->lstate = link_force_ret; + gp->last_forced_speed = gp->phy_mii.speed; + gp->timer_ticks = 5; + if (netif_msg_link(gp)) + printk(KERN_INFO "%s: Got link after fallback, retrying" + " autoneg once...\n", gp->dev->name); + gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, gp->phy_mii.advertising); + } else if (gp->lstate != link_up) { + gp->lstate = link_up; + netif_carrier_on(gp->dev); + if (gp->opened && gem_set_link_modes(gp)) + restart_aneg = 1; + } + } else { + /* If the link was previously up, we restart the + * whole process + */ + if (gp->lstate == link_up) { + gp->lstate = link_down; + if (netif_msg_link(gp)) + printk(KERN_INFO "%s: Link down\n", + gp->dev->name); + netif_carrier_off(gp->dev); + gp->reset_task_pending = 2; + schedule_task(&gp->reset_task); + restart_aneg = 1; + } else if (++gp->timer_ticks > 10) { + if (found_mii_phy(gp)) + restart_aneg = gem_mdio_link_not_up(gp); + else + restart_aneg = 1; + } + } + if (restart_aneg) { + gem_begin_auto_negotiation(gp, NULL); + goto out_unlock; } - restart: mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); out_unlock: @@ -1501,153 +1488,14 @@ txd->control_word = 0; txd->buffer = 0; } -} - -/* Must be invoked under gp->lock. */ -static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr) -{ - u16 val; - int limit = 10000; - - val = __phy_read(gp, MII_BMCR, phy_addr); - val &= ~BMCR_ISOLATE; - val |= BMCR_RESET; - __phy_write(gp, MII_BMCR, val, phy_addr); - - udelay(100); - - while (limit--) { - val = __phy_read(gp, MII_BMCR, phy_addr); - if ((val & BMCR_RESET) == 0) - break; - udelay(10); - } - if ((val & BMCR_ISOLATE) && limit > 0) - __phy_write(gp, MII_BMCR, val & ~BMCR_ISOLATE, phy_addr); - - return (limit <= 0); -} - -/* Must be invoked under gp->lock. */ -static void gem_init_bcm5201_phy(struct gem *gp) -{ - u16 data; - - data = phy_read(gp, MII_BCM5201_MULTIPHY); - data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE; - phy_write(gp, MII_BCM5201_MULTIPHY, data); -} - -/* Must be invoked under gp->lock. */ -static void gem_init_bcm5400_phy(struct gem *gp) -{ - u16 data; - - /* Configure for gigabit full duplex */ - data = phy_read(gp, MII_BCM5400_AUXCONTROL); - data |= MII_BCM5400_AUXCONTROL_PWR10BASET; - phy_write(gp, MII_BCM5400_AUXCONTROL, data); - - data = phy_read(gp, MII_BCM5400_GB_CONTROL); - data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; - phy_write(gp, MII_BCM5400_GB_CONTROL, data); - - mdelay(10); - - /* Reset and configure cascaded 10/100 PHY */ - gem_reset_one_mii_phy(gp, 0x1f); - - data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f); - data |= MII_BCM5201_MULTIPHY_SERIALMODE; - __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f); - - data = phy_read(gp, MII_BCM5400_AUXCONTROL); - data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; - phy_write(gp, MII_BCM5400_AUXCONTROL, data); -} - -/* Must be invoked under gp->lock. */ -static void gem_init_bcm5401_phy(struct gem *gp) -{ - u16 data; - int rev; - - rev = phy_read(gp, MII_PHYSID2) & 0x000f; - if (rev == 0 || rev == 3) { - /* Some revisions of 5401 appear to need this - * initialisation sequence to disable, according - * to OF, "tap power management" - * - * WARNING ! OF and Darwin don't agree on the - * register addresses. OF seem to interpret the - * register numbers below as decimal - * - * Note: This should (and does) match tg3_init_5401phy_dsp - * in the tg3.c driver. -DaveM - */ - phy_write(gp, 0x18, 0x0c20); - phy_write(gp, 0x17, 0x0012); - phy_write(gp, 0x15, 0x1804); - phy_write(gp, 0x17, 0x0013); - phy_write(gp, 0x15, 0x1204); - phy_write(gp, 0x17, 0x8006); - phy_write(gp, 0x15, 0x0132); - phy_write(gp, 0x17, 0x8006); - phy_write(gp, 0x15, 0x0232); - phy_write(gp, 0x17, 0x201f); - phy_write(gp, 0x15, 0x0a20); - } - - /* Configure for gigabit full duplex */ - data = phy_read(gp, MII_BCM5400_GB_CONTROL); - data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; - phy_write(gp, MII_BCM5400_GB_CONTROL, data); - - mdelay(1); - - /* Reset and configure cascaded 10/100 PHY */ - gem_reset_one_mii_phy(gp, 0x1f); - - data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f); - data |= MII_BCM5201_MULTIPHY_SERIALMODE; - __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f); -} - -/* Must be invoked under gp->lock. */ -static void gem_init_bcm5411_phy(struct gem *gp) -{ - u16 data; - - /* Here's some more Apple black magic to setup - * some voltage stuffs. - */ - phy_write(gp, 0x1c, 0x8c23); - phy_write(gp, 0x1c, 0x8ca3); - phy_write(gp, 0x1c, 0x8c23); - - /* Here, Apple seems to want to reset it, do - * it as well - */ - phy_write(gp, MII_BMCR, BMCR_RESET); - - /* Start autoneg */ - phy_write(gp, MII_BMCR, - (BMCR_ANENABLE | BMCR_FULLDPLX | - BMCR_ANRESTART | BMCR_SPD2)); - - data = phy_read(gp, MII_BCM5400_GB_CONTROL); - data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; - phy_write(gp, MII_BCM5400_GB_CONTROL, data); + io_barrier(); } /* Must be invoked under gp->lock. */ static void gem_init_phy(struct gem *gp) { u32 mifcfg; - - if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201) - phy_write(gp, MII_BCM5201_INTERRUPT, 0); - + /* Revert MIF CFG setting done on stop_phy */ mifcfg = readl(gp->regs + MIF_CFG); mifcfg &= ~MIF_CFG_BBMODE; @@ -1655,19 +1503,37 @@ #ifdef CONFIG_ALL_PPC if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { - int i; + int i, j; + /* Those delay sucks, the HW seem to love them though, I'll + * serisouly consider breaking some locks here to be able + * to schedule instead + */ pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0); - for (i = 0; i < 32; i++) { - gp->mii_phy_addr = i; - if (phy_read(gp, MII_BMCR) != 0xffff) + mdelay(10); + for (j = 0; j < 3; j++) { + /* Some PHYs used by apple have problem getting back to us, + * we _know_ it's actually at addr 0, that's a hack, but + * it helps to do that reset now. I suspect some motherboards + * don't wire the PHY reset line properly, thus the PHY doesn't + * come back with the above pmac_call_feature. + */ + gp->mii_phy_addr = 0; + phy_write(gp, MII_BMCR, BMCR_RESET); + /* We should probably break some locks here and schedule... */ + mdelay(10); + for (i = 0; i < 32; i++) { + gp->mii_phy_addr = i; + if (phy_read(gp, MII_BMCR) != 0xffff) + break; + } + if (i == 32) { + printk(KERN_WARNING "%s: GMAC PHY not responding !\n", + gp->dev->name); + gp->mii_phy_addr = 0; + } else break; } - if (i == 32) { - printk(KERN_WARNING "%s: GMAC PHY not responding !\n", - gp->dev->name); - return; - } } #endif /* CONFIG_ALL_PPC */ @@ -1690,79 +1556,12 @@ if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { - u32 phy_id; - u16 val; - - /* Take PHY out of isloate mode and reset it. */ - gem_reset_one_mii_phy(gp, gp->mii_phy_addr); - - phy_id = (phy_read(gp, MII_PHYSID1) << 16 | phy_read(gp, MII_PHYSID2)) - & 0xfffffff0; - printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id); - switch(phy_id) { - case 0x406210: - gp->phy_mod = phymod_bcm5201; - gem_init_bcm5201_phy(gp); - printk("BCM 5201\n"); - break; - - case 0x4061e0: - printk("BCM 5221\n"); - gp->phy_mod = phymod_bcm5221; - break; - - case 0x206040: - printk("BCM 5400\n"); - gp->phy_mod = phymod_bcm5400; - gem_init_bcm5400_phy(gp); - gp->gigabit_capable = 1; - break; - - case 0x206050: - printk("BCM 5401\n"); - gp->phy_mod = phymod_bcm5401; - gem_init_bcm5401_phy(gp); - gp->gigabit_capable = 1; - break; - - case 0x206070: - printk("BCM 5411\n"); - gp->phy_mod = phymod_bcm5411; - gem_init_bcm5411_phy(gp); - gp->gigabit_capable = 1; - break; - case 0x1410c60: - printk("M1011 (Marvel ?)\n"); - gp->phy_mod = phymod_m1011; - gp->gigabit_capable = 1; - break; - - case 0x18074c0: - printk("Lucent\n"); - gp->phy_mod = phymod_generic; - break; - - case 0x437420: - printk("Enable Semiconductor\n"); - gp->phy_mod = phymod_generic; - break; + // XXX check for errors + mii_phy_probe(&gp->phy_mii, gp->mii_phy_addr); - default: - printk("Unknown (Using generic mode)\n"); - gp->phy_mod = phymod_generic; - break; - }; - - /* Init advertisement and enable autonegotiation. */ - val = phy_read(gp, MII_BMCR); - val &= ~BMCR_ANENABLE; - phy_write(gp, MII_BMCR, val); - udelay(10); - - phy_write(gp, MII_ADVERTISE, - phy_read(gp, MII_ADVERTISE) | - (ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL)); + /* Init PHY */ + if (gp->phy_mii.def && gp->phy_mii.def->ops->init) + gp->phy_mii.def->ops->init(&gp->phy_mii); } else { u32 val; int limit; @@ -1819,13 +1618,7 @@ else val |= PCS_SCTRL_LOOP; writel(val, gp->regs + PCS_SCTRL); - gp->gigabit_capable = 1; } - - /* BMCR_SPD2 is a broadcom 54xx specific thing afaik */ - if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 && - gp->phy_mod != phymod_bcm5411) - gp->link_cntl &= ~BMCR_SPD2; } /* Must be invoked under gp->lock. */ @@ -1914,9 +1707,7 @@ { unsigned char *e = &gp->dev->dev_addr[0]; - if (gp->pdev->vendor == PCI_VENDOR_ID_SUN && - gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) - writel(0x1bf0, gp->regs + MAC_SNDPAUSE); + writel(0x1bf0, gp->regs + MAC_SNDPAUSE); writel(0x00, gp->regs + MAC_IPG0); writel(0x08, gp->regs + MAC_IPG1); @@ -1953,6 +1744,7 @@ writel(0, gp->regs + MAC_AF0MSK); gp->mac_rx_cfg = gem_setup_multicast(gp); + gp->mac_rx_cfg |= MAC_RXCFG_SFCS; writel(0, gp->regs + MAC_NCOLL); writel(0, gp->regs + MAC_FASUCC); @@ -2129,12 +1921,15 @@ /* Default aneg parameters */ gp->timer_ticks = 0; gp->lstate = link_down; + netif_carrier_off(gp->dev); /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ gem_begin_auto_negotiation(gp, NULL); } else { - if (gp->lstate == link_up) + if (gp->lstate == link_up) { + netif_carrier_on(gp->dev); gem_set_link_modes(gp); + } } } @@ -2184,9 +1979,6 @@ { u32 mifcfg; - if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201) - phy_write(gp, MII_BCM5201_INTERRUPT, 0); - /* Make sure we aren't polling PHY status change. We * don't currently use that feature though */ @@ -2194,9 +1986,6 @@ mifcfg &= ~MIF_CFG_POLL; writel(mifcfg, gp->regs + MIF_CFG); - /* Here's a strange hack used by both MacOS 9 and X */ - phy_write(gp, MII_LPA, phy_read(gp, MII_LPA)); - if (gp->wake_on_lan) { /* Setup wake-on-lan */ } else @@ -2210,21 +1999,12 @@ gem_stop(gp); writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); - if (gp->phy_mod == phymod_bcm5400 || gp->phy_mod == phymod_bcm5401 || - gp->phy_mod == phymod_bcm5411) { -#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ - phy_write(gp, MII_BMCR, BMCR_PDOWN); -#endif - } else if (gp->phy_mod == phymod_bcm5201 || gp->phy_mod == phymod_bcm5221) { -#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ - u16 val = phy_read(gp, MII_BCM5201_AUXMODE2) - phy_write(gp, MII_BCM5201_AUXMODE2, - val & ~MII_BCM5201_AUXMODE2_LOWPOWER); -#endif - phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE); - } else if (gp->phy_mod == phymod_m1011) - phy_write(gp, MII_BMCR, BMCR_PDOWN); + } + + if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend) + gp->phy_mii.def->ops->suspend(&gp->phy_mii, 0 /* wake on lan options */); + if (!gp->wake_on_lan) { /* According to Apple, we must set the MDIO pins to this begnign * state or we may 1) eat more current, 2) damage some PHYs */ @@ -2526,7 +2306,9 @@ netif_stop_queue(dev); rxcfg = readl(gp->regs + MAC_RXCFG); - gp->mac_rx_cfg = rxcfg_new = gem_setup_multicast(gp); + rxcfg_new = gem_setup_multicast(gp); + rxcfg_new |= MAC_RXCFG_SFCS; + gp->mac_rx_cfg = rxcfg_new; writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) { @@ -2551,8 +2333,6 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user) { struct gem *gp = dev->priv; - u16 bmcr; - int full_duplex, speed, pause; struct ethtool_cmd ecmd; if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) @@ -2575,41 +2355,36 @@ } case ETHTOOL_GSET: - ecmd.supported = + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + if (gp->phy_mii.def) + ecmd.supported = gp->phy_mii.def->features; + else + ecmd.supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full; + + /* XXX hardcoded stuff for now */ + ecmd.port = PORT_MII; + ecmd.transceiver = XCVR_EXTERNAL; + ecmd.phy_address = 0; /* XXX fixed PHYAD */ + + /* Return current PHY settings */ + spin_lock_irq(&gp->lock); + ecmd.autoneg = gp->want_autoneg; + ecmd.speed = gp->phy_mii.speed; + ecmd.duplex = gp->phy_mii.duplex; + ecmd.advertising = gp->phy_mii.advertising; + /* If we started with a forced mode, we don't have a default + * advertise set, we need to return something sensible so + * userland can re-enable autoneg properly */ + if (ecmd.advertising == 0) + ecmd.advertising = ecmd.supported; + spin_unlock_irq(&gp->lock); + } else { // XXX PCS ? + ecmd.supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); - - if (gp->gigabit_capable) - ecmd.supported |= - (SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full); - - /* XXX hardcoded stuff for now */ - ecmd.port = PORT_MII; - ecmd.transceiver = XCVR_EXTERNAL; - ecmd.phy_address = 0; /* XXX fixed PHYAD */ - - /* Record PHY settings if HW is on. */ - spin_lock_irq(&gp->lock); - if (gp->hw_running) { - bmcr = phy_read(gp, MII_BMCR); - gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause); - } else - bmcr = 0; - spin_unlock_irq(&gp->lock); - if (bmcr & BMCR_ANENABLE) { - ecmd.autoneg = AUTONEG_ENABLE; - ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100); - ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.speed = - (bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10; - ecmd.duplex = - (bmcr & BMCR_FULLDPLX) ? - DUPLEX_FULL : DUPLEX_HALF; + SUPPORTED_Autoneg); + ecmd.advertising = ecmd.supported; } if (copy_to_user(ep_user, &ecmd, sizeof(ecmd))) return -EFAULT; @@ -2624,13 +2399,18 @@ ecmd.autoneg != AUTONEG_DISABLE) return -EINVAL; + if (ecmd.autoneg == AUTONEG_ENABLE && + ecmd.advertising == 0) + return -EINVAL; + if (ecmd.autoneg == AUTONEG_DISABLE && - ((ecmd.speed != SPEED_100 && + ((ecmd.speed != SPEED_1000 && + ecmd.speed != SPEED_100 && ecmd.speed != SPEED_10) || (ecmd.duplex != DUPLEX_HALF && ecmd.duplex != DUPLEX_FULL))) return -EINVAL; - + /* Apply settings and restart link process. */ spin_lock_irq(&gp->lock); gem_begin_auto_negotiation(gp, &ecmd); @@ -2639,7 +2419,7 @@ return 0; case ETHTOOL_NWAY_RST: - if ((gp->link_cntl & BMCR_ANENABLE) == 0) + if (!gp->want_autoneg) return -EINVAL; /* Restart link process. */ @@ -2743,15 +2523,21 @@ /* Fallthrough... */ case SIOCGMIIREG: /* Read MII PHY register. */ - data->val_out = __phy_read(gp, data->reg_num & 0x1f, data->phy_id & 0x1f); - rc = 0; + if (!gp->hw_running) + rc = -EIO; + else { + data->val_out = __phy_read(gp, data->phy_id & 0x1f, data->reg_num & 0x1f); + rc = 0; + } break; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) { + if (!capable(CAP_NET_ADMIN)) rc = -EPERM; - } else { - __phy_write(gp, data->reg_num & 0x1f, data->val_in, data->phy_id & 0x1f); + else if (!gp->hw_running) + rc = -EIO; + else { + __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); rc = 0; } break; @@ -2953,13 +2739,9 @@ INIT_TQUEUE(&gp->pm_task, gem_pm_task, gp); INIT_TQUEUE(&gp->reset_task, gem_reset_task, gp); - /* Default link parameters */ - if (link_mode >= 0 && link_mode <= 6) - gp->link_cntl = link_modes[link_mode]; - else - gp->link_cntl = BMCR_ANENABLE; gp->lstate = link_down; gp->timer_ticks = 0; + netif_carrier_off(dev); gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len); if (gp->regs == 0UL) { @@ -2980,15 +2762,33 @@ gem_stop(gp); spin_unlock_irq(&gp->lock); + /* Fill up the mii_phy structure (even if we won't use it) */ + gp->phy_mii.dev = dev; + gp->phy_mii.mdio_read = _phy_read; + gp->phy_mii.mdio_write = _phy_write; + + /* Default link parameters */ + if (forced_speed != -1 && + forced_speed != SPEED_10 && + forced_speed != SPEED_100 && + forced_speed != SPEED_1000) { + forced_speed = -1; + printk(KERN_WARNING "forced_speed argument invalid, reverting to autoneg\n"); + } + if (forced_speed < SPEED_10) + gp->want_autoneg = 1; + else { + gp->want_autoneg = 0; + gp->phy_mii.speed = forced_speed; + if (forced_duplex > 0) + gp->phy_mii.duplex = DUPLEX_FULL; + else + gp->phy_mii.duplex = DUPLEX_HALF; + } + if (gem_check_invariants(gp)) goto err_out_iounmap; - spin_lock_irq(&gp->lock); - gp->hw_running = 1; - gem_init_phy(gp); - gem_begin_auto_negotiation(gp, NULL); - spin_unlock_irq(&gp->lock); - /* It is guarenteed that the returned buffer will be at least * PAGE_SIZE aligned. */ @@ -3015,12 +2815,23 @@ printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':'); printk("\n"); + /* Detect & init PHY, start autoneg */ + spin_lock_irq(&gp->lock); + gp->hw_running = 1; + gem_init_phy(gp); + gem_begin_auto_negotiation(gp, NULL); + spin_unlock_irq(&gp->lock); + + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) + printk(KERN_INFO "%s: Found %s PHY\n", dev->name, + gp->phy_mii.def ? gp->phy_mii.def->name : "no"); + pci_set_drvdata(pdev, dev); dev->open = gem_open; diff -uNr linux-2.4.20/drivers/net/sungem.h linux-2.4.20-ben6/drivers/net/sungem.h --- linux-2.4.20/drivers/net/sungem.h 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/net/sungem.h 2003-02-16 20:20:22.000000000 +0100 @@ -936,16 +936,6 @@ phy_serdes, }; -enum gem_phy_model { - phymod_generic, - phymod_bcm5201, - phymod_bcm5221, - phymod_bcm5400, - phymod_bcm5401, - phymod_bcm5411, - phymod_m1011, -}; - enum link_state { link_down = 0, /* No link, will retry */ link_aneg, /* Autoneg in progress */ @@ -980,21 +970,20 @@ struct net_device_stats net_stats; enum gem_phy_type phy_type; - enum gem_phy_model phy_mod; + struct mii_phy phy_mii; + int tx_fifo_sz; int rx_fifo_sz; int rx_pause_off; int rx_pause_on; int mii_phy_addr; - int gigabit_capable; u32 mac_rx_cfg; u32 swrst_base; /* Autoneg & PHY control */ - int link_cntl; - int link_advertise; - int link_fcntl; + int want_autoneg; + int last_forced_speed; enum link_state lstate; struct timer_list link_timer; int timer_ticks; @@ -1014,6 +1003,9 @@ #endif }; +#define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) \ + && gp->phy_mii.def && gp->phy_mii.def->ops) + #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr)) static __inline__ struct sk_buff *gem_alloc_skb(int size, int gfp_flags) diff -uNr linux-2.4.20/drivers/net/sungem_phy.c linux-2.4.20-ben6/drivers/net/sungem_phy.c --- linux-2.4.20/drivers/net/sungem_phy.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/net/sungem_phy.c 2003-02-16 20:21:31.000000000 +0100 @@ -0,0 +1,784 @@ +/* + * PHY drivers for the sungem ethernet driver. + * + * This file could be shared with other drivers. + * + * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org) + * + * TODO: + * - Implement WOL + * - Add support for PHYs that provide an IRQ line + * - Eventually moved the entire polling state machine in + * there (out of the eth driver), so that it can easily be + * skipped on PHYs that implement it in hardware. + * - On LXT971 & BCM5201, Apple uses some chip specific regs + * to read the link status. Figure out why and if it makes + * sense to do the same (magic aneg ?) + * - Apple has some additional power management code for some + * Broadcom PHYs that they "hide" from the OpenSource version + * of darwin, still need to reverse engineer that + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sungem_phy.h" + +/* Link modes of the BCM5400 PHY */ +static int phy_BCM5400_link_table[8][3] = { + { 0, 0, 0 }, /* No link */ + { 0, 0, 0 }, /* 10BT Half Duplex */ + { 1, 0, 0 }, /* 10BT Full Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 1, 1, 0 }, /* 100BT Full Duplex*/ + { 1, 0, 1 }, /* 1000BT */ + { 1, 0, 1 }, /* 1000BT */ +}; + +static inline int __phy_read(struct mii_phy* phy, int id, int reg) +{ + return phy->mdio_read(phy->dev, id, reg); +} + +static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val) +{ + phy->mdio_write(phy->dev, id, reg, val); +} + +static inline int phy_read(struct mii_phy* phy, int reg) +{ + return phy->mdio_read(phy->dev, phy->mii_id, reg); +} + +static inline void phy_write(struct mii_phy* phy, int reg, int val) +{ + phy->mdio_write(phy->dev, phy->mii_id, reg, val); +} + +static int reset_one_mii_phy(struct mii_phy* phy, int phy_id) +{ + u16 val; + int limit = 10000; + + val = __phy_read(phy, phy_id, MII_BMCR); + val &= ~BMCR_ISOLATE; + val |= BMCR_RESET; + __phy_write(phy, phy_id, MII_BMCR, val); + + udelay(100); + + while (limit--) { + val = __phy_read(phy, phy_id, MII_BMCR); + if ((val & BMCR_RESET) == 0) + break; + udelay(10); + } + if ((val & BMCR_ISOLATE) && limit > 0) + __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE); + + return (limit <= 0); +} + +static int bcm5201_init(struct mii_phy* phy) +{ + u16 data; + + data = phy_read(phy, MII_BCM5201_MULTIPHY); + data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE; + phy_write(phy, MII_BCM5201_MULTIPHY, data); + + return 0; +} + +static int bcm5201_suspend(struct mii_phy* phy, int wol_options) +{ + if (!wol_options) + phy_write(phy, MII_BCM5201_INTERRUPT, 0); + + /* Here's a strange hack used by both MacOS 9 and X */ + phy_write(phy, MII_LPA, phy_read(phy, MII_LPA)); + + if (!wol_options) { +#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ + u16 val = phy_read(phy, MII_BCM5201_AUXMODE2) + phy_write(phy, MII_BCM5201_AUXMODE2, + val & ~MII_BCM5201_AUXMODE2_LOWPOWER); +#endif + phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE); + } + + return 0; +} + +static int bcm5400_init(struct mii_phy* phy) +{ + u16 data; + + /* Configure for gigabit full duplex */ + data = phy_read(phy, MII_BCM5400_AUXCONTROL); + data |= MII_BCM5400_AUXCONTROL_PWR10BASET; + phy_write(phy, MII_BCM5400_AUXCONTROL, data); + + data = phy_read(phy, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + phy_write(phy, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + + /* Reset and configure cascaded 10/100 PHY */ + (void)reset_one_mii_phy(phy, 0x1f); + + data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data); + + data = phy_read(phy, MII_BCM5400_AUXCONTROL); + data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; + phy_write(phy, MII_BCM5400_AUXCONTROL, data); + + return 0; +} + +static int bcm5400_suspend(struct mii_phy* phy, int wol_options) +{ +#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ + phy_write(phy, MII_BMCR, BMCR_PDOWN); +#endif + return 0; +} + +static int bcm5401_init(struct mii_phy* phy) +{ + u16 data; + int rev; + + rev = phy_read(phy, MII_PHYSID2) & 0x000f; + if (rev == 0 || rev == 3) { + /* Some revisions of 5401 appear to need this + * initialisation sequence to disable, according + * to OF, "tap power management" + * + * WARNING ! OF and Darwin don't agree on the + * register addresses. OF seem to interpret the + * register numbers below as decimal + * + * Note: This should (and does) match tg3_init_5401phy_dsp + * in the tg3.c driver. -DaveM + */ + phy_write(phy, 0x18, 0x0c20); + phy_write(phy, 0x17, 0x0012); + phy_write(phy, 0x15, 0x1804); + phy_write(phy, 0x17, 0x0013); + phy_write(phy, 0x15, 0x1204); + phy_write(phy, 0x17, 0x8006); + phy_write(phy, 0x15, 0x0132); + phy_write(phy, 0x17, 0x8006); + phy_write(phy, 0x15, 0x0232); + phy_write(phy, 0x17, 0x201f); + phy_write(phy, 0x15, 0x0a20); + } + + /* Configure for gigabit full duplex */ + data = phy_read(phy, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + phy_write(phy, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + + /* Reset and configure cascaded 10/100 PHY */ + (void)reset_one_mii_phy(phy, 0x1f); + + data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data); + + return 0; +} + +static int bcm5401_suspend(struct mii_phy* phy, int wol_options) +{ +#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ + phy_write(phy, MII_BMCR, BMCR_PDOWN); +#endif + return 0; +} + +static int bcm5411_init(struct mii_phy* phy) +{ + u16 data; + + /* Here's some more Apple black magic to setup + * some voltage stuffs. + */ + phy_write(phy, 0x1c, 0x8c23); + phy_write(phy, 0x1c, 0x8ca3); + phy_write(phy, 0x1c, 0x8c23); + + /* Here, Apple seems to want to reset it, do + * it as well + */ + phy_write(phy, MII_BMCR, BMCR_RESET); + phy_write(phy, MII_BMCR, 0x1340); + + data = phy_read(phy, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + phy_write(phy, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + + /* Reset and configure cascaded 10/100 PHY */ + (void)reset_one_mii_phy(phy, 0x1f); + + return 0; +} + +static int bcm5411_suspend(struct mii_phy* phy, int wol_options) +{ + phy_write(phy, MII_BMCR, BMCR_PDOWN); + + return 0; +} + +static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise) +{ + u16 ctl, adv; + + phy->autoneg = 1; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = 0; + phy->advertising = advertise; + + /* Setup standard advertise */ + adv = phy_read(phy, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + phy_write(phy, MII_ADVERTISE, adv); + + /* Setup 1000BT advertise */ + adv = phy_read(phy, MII_1000BASETCONTROL); + adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; + phy_write(phy, MII_1000BASETCONTROL, adv); + + /* Start/Restart aneg */ + ctl = phy_read(phy, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd) +{ + u16 ctl; + + phy->autoneg = 0; + phy->speed = speed; + phy->duplex = fd; + phy->pause = 0; + + ctl = phy_read(phy, MII_BMCR); + ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); + + /* First reset the PHY */ + phy_write(phy, MII_BMCR, ctl | BMCR_RESET); + + /* Select speed & duplex */ + switch(speed) { + case SPEED_10: + break; + case SPEED_100: + ctl |= BMCR_SPEED100; + break; + case SPEED_1000: + ctl |= BMCR_SPD2; + } + if (fd == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + + // XXX Should we set the sungem to GII now on 1000BT ? + + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int bcm54xx_read_link(struct mii_phy *phy) +{ + int link_mode; + u16 val; + + if (phy->autoneg) { + val = phy_read(phy, MII_BCM5400_AUXSTATUS); + link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> + MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); + phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF; + phy->speed = phy_BCM5400_link_table[link_mode][2] ? + SPEED_1000 : + (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10); + val = phy_read(phy, MII_LPA); + phy->pause = ((val & LPA_PAUSE) != 0); + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} + +static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise) +{ + u16 ctl, adv; + + phy->autoneg = 1; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = 0; + phy->advertising = advertise; + + /* Setup standard advertise */ + adv = phy_read(phy, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + phy_write(phy, MII_ADVERTISE, adv); + + /* Setup 1000BT advertise & enable crossover detect + * XXX How do we advertise 1000BT ? Darwin source is + * confusing here, they read from specific control and + * write to control... Someone has specs for those + * beasts ? + */ + adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL); + adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX; + adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | + MII_1000BASETCONTROL_HALFDUPLEXCAP); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; + phy_write(phy, MII_1000BASETCONTROL, adv); + + /* Start/Restart aneg */ + ctl = phy_read(phy, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd) +{ + u16 ctl, ctl2; + + phy->autoneg = 0; + phy->speed = speed; + phy->duplex = fd; + phy->pause = 0; + + ctl = phy_read(phy, MII_BMCR); + ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); + ctl |= BMCR_RESET; + + /* Select speed & duplex */ + switch(speed) { + case SPEED_10: + break; + case SPEED_100: + ctl |= BMCR_SPEED100; + break; + /* I'm not sure about the one below, again, Darwin source is + * quite confusing and I lack chip specs + */ + case SPEED_1000: + ctl |= BMCR_SPD2; + } + if (fd == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + + /* Disable crossover. Again, the way Apple does it is strange, + * though I don't assume they are wrong ;) + */ + ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL); + ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX | + MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX | + MII_1000BASETCONTROL_FULLDUPLEXCAP | + MII_1000BASETCONTROL_HALFDUPLEXCAP); + if (speed == SPEED_1000) + ctl2 |= (fd == DUPLEX_FULL) ? + MII_1000BASETCONTROL_FULLDUPLEXCAP : + MII_1000BASETCONTROL_HALFDUPLEXCAP; + phy_write(phy, MII_1000BASETCONTROL, ctl2); + + // XXX Should we set the sungem to GII now on 1000BT ? + + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int marvell_read_link(struct mii_phy *phy) +{ + u16 status; + + if (phy->autoneg) { + status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS); + if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) + return -EAGAIN; + if (status & MII_M1011_PHY_SPEC_STATUS_1000) + phy->speed = SPEED_1000; + else if (status & MII_M1011_PHY_SPEC_STATUS_100) + phy->speed = SPEED_100; + else + phy->speed = SPEED_10; + if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) + phy->duplex = DUPLEX_FULL; + else + phy->duplex = DUPLEX_HALF; + phy->pause = 0; /* XXX Check against spec ! */ + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} + +static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) +{ + u16 ctl, adv; + + phy->autoneg = 1; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = 0; + phy->advertising = advertise; + + /* Setup standard advertise */ + adv = phy_read(phy, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + phy_write(phy, MII_ADVERTISE, adv); + + /* Start/Restart aneg */ + ctl = phy_read(phy, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) +{ + u16 ctl; + + phy->autoneg = 0; + phy->speed = speed; + phy->duplex = fd; + phy->pause = 0; + + ctl = phy_read(phy, MII_BMCR); + ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE); + + /* First reset the PHY */ + phy_write(phy, MII_BMCR, ctl | BMCR_RESET); + + /* Select speed & duplex */ + switch(speed) { + case SPEED_10: + break; + case SPEED_100: + ctl |= BMCR_SPEED100; + break; + case SPEED_1000: + default: + return -EINVAL; + } + if (fd == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_poll_link(struct mii_phy *phy) +{ + u16 status; + + (void)phy_read(phy, MII_BMSR); + status = phy_read(phy, MII_BMSR); + if ((status & BMSR_LSTATUS) == 0) + return 0; + if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) + return 0; + return 1; +} + +static int genmii_read_link(struct mii_phy *phy) +{ + u16 lpa; + + if (phy->autoneg) { + lpa = phy_read(phy, MII_LPA); + + if (lpa & (LPA_10FULL | LPA_100FULL)) + phy->duplex = DUPLEX_FULL; + else + phy->duplex = DUPLEX_HALF; + if (lpa & (LPA_100FULL | LPA_100HALF)) + phy->speed = SPEED_100; + else + phy->speed = SPEED_10; + phy->pause = 0; + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} + + +#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII) +#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) + +/* Broadcom BCM 5201 */ +static struct mii_phy_ops bcm5201_phy_ops = { + init: bcm5201_init, + suspend: bcm5201_suspend, + setup_aneg: genmii_setup_aneg, + setup_forced: genmii_setup_forced, + poll_link: genmii_poll_link, + read_link: genmii_read_link, +}; + +static struct mii_phy_def bcm5201_phy_def = { + phy_id: 0x00406210, + phy_id_mask: 0xfffffff0, + name: "BCM5201", + features: MII_BASIC_FEATURES, + magic_aneg: 0, + ops: &bcm5201_phy_ops +}; + +/* Broadcom BCM 5221 */ +static struct mii_phy_ops bcm5221_phy_ops = { + suspend: bcm5201_suspend, + setup_aneg: genmii_setup_aneg, + setup_forced: genmii_setup_forced, + poll_link: genmii_poll_link, + read_link: genmii_read_link, +}; + +static struct mii_phy_def bcm5221_phy_def = { + phy_id: 0x004061e0, + phy_id_mask: 0xfffffff0, + name: "BCM5221", + features: MII_BASIC_FEATURES, + magic_aneg: 0, + ops: &bcm5221_phy_ops +}; + +/* Broadcom BCM 5400 */ +static struct mii_phy_ops bcm5400_phy_ops = { + init: bcm5400_init, + suspend: bcm5400_suspend, + setup_aneg: bcm54xx_setup_aneg, + setup_forced: bcm54xx_setup_forced, + poll_link: genmii_poll_link, + read_link: bcm54xx_read_link, +}; + +static struct mii_phy_def bcm5400_phy_def = { + phy_id: 0x00206040, + phy_id_mask: 0xfffffff0, + name: "BCM5400", + features: MII_GBIT_FEATURES, + magic_aneg: 1, + ops: &bcm5400_phy_ops +}; + +/* Broadcom BCM 5401 */ +static struct mii_phy_ops bcm5401_phy_ops = { + init: bcm5401_init, + suspend: bcm5401_suspend, + setup_aneg: bcm54xx_setup_aneg, + setup_forced: bcm54xx_setup_forced, + poll_link: genmii_poll_link, + read_link: bcm54xx_read_link, +}; + +static struct mii_phy_def bcm5401_phy_def = { + phy_id: 0x00206050, + phy_id_mask: 0xfffffff0, + name: "BCM5401", + features: MII_GBIT_FEATURES, + magic_aneg: 1, + ops: &bcm5401_phy_ops +}; + +/* Broadcom BCM 5411 */ +static struct mii_phy_ops bcm5411_phy_ops = { + init: bcm5411_init, + suspend: bcm5411_suspend, + setup_aneg: bcm54xx_setup_aneg, + setup_forced: bcm54xx_setup_forced, + poll_link: genmii_poll_link, + read_link: bcm54xx_read_link, +}; + +static struct mii_phy_def bcm5411_phy_def = { + phy_id: 0x00206070, + phy_id_mask: 0xfffffff0, + name: "BCM5411", + features: MII_GBIT_FEATURES, + magic_aneg: 1, + ops: &bcm5411_phy_ops +}; + +/* Broadcom BCM 5421 */ +static struct mii_phy_ops bcm5421_phy_ops = { + suspend: bcm5411_suspend, + setup_aneg: bcm54xx_setup_aneg, + setup_forced: bcm54xx_setup_forced, + poll_link: genmii_poll_link, + read_link: bcm54xx_read_link, +}; + +static struct mii_phy_def bcm5421_phy_def = { + phy_id: 0x002060e0, + phy_id_mask: 0xfffffff0, + name: "BCM5421", + features: MII_GBIT_FEATURES, + magic_aneg: 1, + ops: &bcm5421_phy_ops +}; + +/* Marvell 88E1101 (Apple seem to deal with 2 different revs, + * I masked out the 8 last bits to get both, but some specs + * would be useful here) --BenH. + */ +static struct mii_phy_ops marvell_phy_ops = { + setup_aneg: marvell_setup_aneg, + setup_forced: marvell_setup_forced, + poll_link: genmii_poll_link, + read_link: marvell_read_link +}; + +static struct mii_phy_def marvell_phy_def = { + phy_id: 0x01410c00, + phy_id_mask: 0xffffff00, + name: "Marvell 88E1101", + features: MII_GBIT_FEATURES, + magic_aneg: 1, + ops: &marvell_phy_ops +}; + +/* Generic implementation for most 10/100 PHYs */ +static struct mii_phy_ops generic_phy_ops = { + setup_aneg: genmii_setup_aneg, + setup_forced: genmii_setup_forced, + poll_link: genmii_poll_link, + read_link: genmii_read_link +}; + +static struct mii_phy_def genmii_phy_def = { + phy_id: 0x00000000, + phy_id_mask: 0x00000000, + name: "Generic MII", + features: MII_BASIC_FEATURES, + magic_aneg: 0, + ops: &generic_phy_ops +}; + +static struct mii_phy_def* mii_phy_table[] = { + &bcm5201_phy_def, + &bcm5221_phy_def, + &bcm5400_phy_def, + &bcm5401_phy_def, + &bcm5411_phy_def, + &bcm5421_phy_def, + &marvell_phy_def, + &genmii_phy_def, + NULL +}; + +int mii_phy_probe(struct mii_phy *phy, int mii_id) +{ + int rc; + u32 id; + struct mii_phy_def* def; + int i; + + /* We do not reset the mii_phy structure as the driver + * may re-probe the PHY regulary + */ + phy->mii_id = mii_id; + + /* Take PHY out of isloate mode and reset it. */ + rc = reset_one_mii_phy(phy, mii_id); + if (rc) + goto fail; + + /* Read ID and find matching entry */ + id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2)) + & 0xfffffff0; + for (i=0; (def = mii_phy_table[i]) != NULL; i++) + if ((id & def->phy_id_mask) == def->phy_id) + break; + /* Should never be NULL (we have a generic entry), but... */ + if (def == NULL) + goto fail; + + phy->def = def; + + return 0; +fail: + phy->speed = 0; + phy->duplex = 0; + phy->pause = 0; + phy->advertising = 0; + return -ENODEV; +} + +EXPORT_SYMBOL(mii_phy_probe); +MODULE_LICENSE("GPL"); + diff -uNr linux-2.4.20/drivers/net/sungem_phy.h linux-2.4.20-ben6/drivers/net/sungem_phy.h --- linux-2.4.20/drivers/net/sungem_phy.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/net/sungem_phy.h 2003-02-16 20:20:23.000000000 +0100 @@ -0,0 +1,108 @@ +#ifndef __SUNGEM_PHY_H__ +#define __SUNGEM_PHY_H__ + +struct mii_phy; + +/* Operations supported by any kind of PHY */ +struct mii_phy_ops +{ + int (*init)(struct mii_phy *phy); + int (*suspend)(struct mii_phy *phy, int wol_options); + int (*setup_aneg)(struct mii_phy *phy, u32 advertise); + int (*setup_forced)(struct mii_phy *phy, int speed, int fd); + int (*poll_link)(struct mii_phy *phy); + int (*read_link)(struct mii_phy *phy); +}; + +/* Structure used to statically define an mii/gii based PHY */ +struct mii_phy_def +{ + u32 phy_id; /* Concatenated ID1 << 16 | ID2 */ + u32 phy_id_mask; /* Significant bits */ + u32 features; /* Ethtool SUPPORTED_* defines */ + int magic_aneg; /* Autoneg does all speed test for us */ + const char* name; + const struct mii_phy_ops* ops; +}; + +/* An instance of a PHY, partially borrowed from mii_if_info */ +struct mii_phy +{ + struct mii_phy_def* def; + int advertising; + int mii_id; + + /* 1: autoneg enabled, 0: disabled */ + int autoneg; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + int pause; + + /* Provided by host chip */ + struct net_device* dev; + int (*mdio_read) (struct net_device *dev, int mii_id, int reg); + void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); +}; + +/* Pass in a struct mii_phy with dev, mdio_read and mdio_write + * filled, the remaining fields will be filled on return + */ +extern int mii_phy_probe(struct mii_phy *phy, int mii_id); + + +/* MII definitions missing from mii.h */ + +#define BMCR_SPD2 0x0040 /* Gigabit enable (bcm54xx) */ +#define LPA_PAUSE 0x0400 + +/* More PHY registers (model specific) */ + +/* MII BCM5201 MULTIPHY interrupt register */ +#define MII_BCM5201_INTERRUPT 0x1A +#define MII_BCM5201_INTERRUPT_INTENABLE 0x4000 + +#define MII_BCM5201_AUXMODE2 0x1B +#define MII_BCM5201_AUXMODE2_LOWPOWER 0x0008 + +#define MII_BCM5201_MULTIPHY 0x1E + +/* MII BCM5201 MULTIPHY register bits */ +#define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002 +#define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008 + +/* MII BCM5400 1000-BASET Control register */ +#define MII_BCM5400_GB_CONTROL 0x09 +#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 + +/* MII BCM5400 AUXCONTROL register */ +#define MII_BCM5400_AUXCONTROL 0x18 +#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004 + +/* MII BCM5400 AUXSTATUS register */ +#define MII_BCM5400_AUXSTATUS 0x19 +#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700 +#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8 + +/* 1000BT control (Marvell & BCM54xx at least) */ +#define MII_1000BASETCONTROL 0x09 +#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 +#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 + +/* Marvell 88E1011 PHY control */ +#define MII_M1011_PHY_SPEC_CONTROL 0x10 +#define MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX 0x20 +#define MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX 0x40 + +/* Marvell 88E1011 PHY status */ +#define MII_M1011_PHY_SPEC_STATUS 0x11 +#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 +#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 +#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 +#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 +#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 + +#endif /* __SUNGEM_PHY_H__ */ diff -uNr linux-2.4.20/drivers/net/tg3.c linux-2.4.20-ben6/drivers/net/tg3.c --- linux-2.4.20/drivers/net/tg3.c 2002-11-29 00:53:14.000000000 +0100 +++ linux-2.4.20-ben6/drivers/net/tg3.c 2003-02-16 20:19:50.000000000 +0100 @@ -163,6 +163,8 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { 0, } }; diff -uNr linux-2.4.20/drivers/net/tulip/tulip_core.c linux-2.4.20-ben6/drivers/net/tulip/tulip_core.c --- linux-2.4.20/drivers/net/tulip/tulip_core.c 2002-11-29 00:53:14.000000000 +0100 +++ linux-2.4.20-ben6/drivers/net/tulip/tulip_core.c 2003-02-16 20:20:05.000000000 +0100 @@ -472,6 +472,15 @@ } else tulip_select_media(dev, 1); + /* check for Apple 100BaseTX card and disable loops */ + if ((dev->dev_addr[0] == 0x00) && + (dev->dev_addr[1] == 0x05) && + (dev->dev_addr[2] == 0x02) && + (tp->chip_id == DC21140)) { + outl(0x10f, ioaddr + CSR12); + outl(0x03, ioaddr + CSR12); + } + /* Start the chip's Tx to process setup frame. */ tulip_stop_rxtx(tp); barrier(); diff -uNr linux-2.4.20/drivers/net/wireless/orinoco.c linux-2.4.20-ben6/drivers/net/wireless/orinoco.c --- linux-2.4.20/drivers/net/wireless/orinoco.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/net/wireless/orinoco.c 2003-02-16 20:21:43.000000000 +0100 @@ -1978,7 +1978,13 @@ /* 802.2 header */ memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); - + +#if 0 + /* AppleTalk hack (untested) */ + if (ntohs(eh->h_proto) == 0x8137 || ntohs(eh->h_proto) == 0x80f3) + hdr.oui[2] = 0xf8; +#endif + hdr.ethertype = eh->h_proto; err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, HERMES_802_3_OFFSET); diff -uNr linux-2.4.20/drivers/pci/pci.c linux-2.4.20-ben6/drivers/pci/pci.c --- linux-2.4.20/drivers/pci/pci.c 2002-11-29 00:53:14.000000000 +0100 +++ linux-2.4.20-ben6/drivers/pci/pci.c 2003-02-16 20:20:39.000000000 +0100 @@ -28,7 +28,7 @@ #include #include /* isa_dma_bridge_buggy */ -#undef DEBUG +#define DEBUG #ifdef DEBUG #define DBG(x...) printk(x) @@ -1051,16 +1051,23 @@ unsigned int pos, reg, next; u32 l, sz; struct resource *res; + int is_kl = (dev->device == 0x22 && dev->vendor == 0x106b); + if (is_kl) + howmany = 1; for(pos=0; posresource[pos]; res->name = dev->name; reg = PCI_BASE_ADDRESS_0 + (pos << 2); pci_read_config_dword(dev, reg, &l); - pci_write_config_dword(dev, reg, ~0); - pci_read_config_dword(dev, reg, &sz); - pci_write_config_dword(dev, reg, l); + if (is_kl) + sz = 0x00080000; + else { + pci_write_config_dword(dev, reg, ~0); + pci_read_config_dword(dev, reg, &sz); + pci_write_config_dword(dev, reg, l); + } if (!sz || sz == 0xffffffff) continue; if (l == 0xffffffff) @@ -1295,7 +1302,7 @@ if (!pass) return max; pci_read_config_word(dev, PCI_COMMAND, &cr); - pci_write_config_word(dev, PCI_COMMAND, 0x0000); + //pci_write_config_word(dev, PCI_COMMAND, 0x0000); pci_write_config_word(dev, PCI_STATUS, 0xffff); child = pci_add_new_bus(bus, dev, ++max); diff -uNr linux-2.4.20/drivers/scsi/hosts.c linux-2.4.20-ben6/drivers/scsi/hosts.c --- linux-2.4.20/drivers/scsi/hosts.c 2002-11-29 00:53:14.000000000 +0100 +++ linux-2.4.20-ben6/drivers/scsi/hosts.c 2003-02-16 20:21:28.000000000 +0100 @@ -81,8 +81,8 @@ struct Scsi_Host * scsi_hostlist; struct Scsi_Device_Template * scsi_devicelist; -int max_scsi_hosts; -int next_scsi_host; +int max_scsi_hosts; /* host_no for next new host */ +int next_scsi_host; /* count of registered scsi hosts */ void scsi_unregister(struct Scsi_Host * sh){ @@ -107,21 +107,8 @@ if (shn) shn->host_registered = 0; /* else {} : This should not happen, we should panic here... */ - /* If we are removing the last host registered, it is safe to reuse - * its host number (this avoids "holes" at boot time) (DB) - * It is also safe to reuse those of numbers directly below which have - * been released earlier (to avoid some holes in numbering). - */ - if(sh->host_no == max_scsi_hosts - 1) { - while(--max_scsi_hosts >= next_scsi_host) { - shpnt = scsi_hostlist; - while(shpnt && shpnt->host_no != max_scsi_hosts - 1) - shpnt = shpnt->next; - if(shpnt) - break; - } - } next_scsi_host--; + kfree((char *) sh); } diff -uNr linux-2.4.20/drivers/scsi/sd.c linux-2.4.20-ben6/drivers/scsi/sd.c --- linux-2.4.20/drivers/scsi/sd.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/scsi/sd.c 2003-02-16 20:20:40.000000000 +0100 @@ -668,7 +668,7 @@ * hard error. */ print_sense("sd", SCpnt); - result = 0; + SCpnt->result = 0; SCpnt->sense_buffer[0] = 0x0; good_sectors = this_count; break; @@ -1448,7 +1448,7 @@ } for (i = 0; i < N_USED_SD_MAJORS; i++) { del_gendisk(&sd_gendisks[i]); - blk_size[SD_MAJOR(i)] = NULL; /* XXX blksize_size actually? */ + blksize_size[SD_MAJOR(i)] = NULL; hardsect_size[SD_MAJOR(i)] = NULL; read_ahead[SD_MAJOR(i)] = 0; } diff -uNr linux-2.4.20/drivers/sound/dmasound/Config.in linux-2.4.20-ben6/drivers/sound/dmasound/Config.in --- linux-2.4.20/drivers/sound/dmasound/Config.in 2002-02-25 20:38:04.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/Config.in 2003-02-16 20:20:22.000000000 +0100 @@ -27,13 +27,27 @@ fi # the new dmasound_pmac driver needs access to the i2c bus +# and nvram. if [ "$CONFIG_DMASOUND_PMAC" = "y" ] ; then - define_tristate CONFIG_I2C y - define_tristate CONFIG_I2C_KEYWEST y + if [ "$CONFIG_I2C" != "y" ]; then + define_tristate CONFIG_I2C y + fi + if [ "$CONFIG_I2C_KEYWEST" != "y" ]; then + define_tristate CONFIG_I2C_KEYWEST y + fi + if [ "$CONFIG_NVRAM" != "y" -a "$CONFIG_NVRAM" != "m" ]; then + define_tristate CONFIG_NVRAM y + fi else if [ "$CONFIG_DMASOUND_PMAC" = "m" ] ; then - define_tristate CONFIG_I2C m - define_tristate CONFIG_I2C_KEYWEST m + if [ "$CONFIG_I2C" != "y" -a "$CONFIG_I2C" != "m" ]; then + define_tristate CONFIG_I2C m + fi + if [ "$CONFIG_I2C_KEYWEST" != "y" -a "$CONFIG_I2C_KEYWEST" != "m" ]; then + define_tristate CONFIG_I2C_KEYWEST m + fi + if [ "$CONFIG_NVRAM" != "y" -a "$CONFIG_NVRAM" != "m" ]; then + define_tristate CONFIG_NVRAM y + fi fi fi - diff -uNr linux-2.4.20/drivers/sound/dmasound/Makefile linux-2.4.20-ben6/drivers/sound/dmasound/Makefile --- linux-2.4.20/drivers/sound/dmasound/Makefile 2002-02-25 20:38:04.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/Makefile 2003-02-16 20:21:15.000000000 +0100 @@ -13,7 +13,8 @@ list-multi := dmasound_pmac.o -dmasound_pmac-objs := dmasound_awacs.o trans_16.o tas3001c.o dac3550a.o +dmasound_pmac-objs := dmasound_awacs.o trans_16.o dac3550a.o tas_common.o \ + tas3001c.o tas3001c_tables.o tas3004.o tas3004_tables.o obj-$(CONFIG_DMASOUND) += dmasound_core.o obj-$(CONFIG_DMASOUND_ATARI) += dmasound_atari.o diff -uNr linux-2.4.20/drivers/sound/dmasound/awacs_defs.h linux-2.4.20-ben6/drivers/sound/dmasound/awacs_defs.h --- linux-2.4.20/drivers/sound/dmasound/awacs_defs.h 2002-02-25 20:38:04.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/awacs_defs.h 2003-02-16 20:21:47.000000000 +0100 @@ -168,8 +168,9 @@ #define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */ - +/*******************/ /* Burgundy values */ +/*******************/ #define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12) #define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12) @@ -232,4 +233,19 @@ #define DEF_BURGUNDY_ATTENLINEOUT (0xCC) #define DEF_BURGUNDY_ATTENHP (0xCC) +/*********************/ +/* i2s layout values */ +/*********************/ + +#define I2S_REG_INT_CTL 0x00 +#define I2S_REG_SERIAL_FORMAT 0x10 +#define I2S_REG_CODEC_MSG_OUT 0x20 +#define I2S_REG_CODEC_MSG_IN 0x30 +#define I2S_REG_FRAME_COUNT 0x40 +#define I2S_REG_FRAME_MATCH 0x50 +#define I2S_REG_DATAWORD_SIZES 0x60 +#define I2S_REG_PEAKLEVEL_SEL 0x70 +#define I2S_REG_PEAKLEVEL_IN0 0x80 +#define I2S_REG_PEAKLEVEL_IN1 0x90 + #endif /* _AWACS_DEFS_H_ */ diff -uNr linux-2.4.20/drivers/sound/dmasound/dmasound_awacs.c linux-2.4.20-ben6/drivers/sound/dmasound/dmasound_awacs.c --- linux-2.4.20/drivers/sound/dmasound/dmasound_awacs.c 2002-08-03 02:39:44.000000000 +0200 +++ linux-2.4.20-ben6/drivers/sound/dmasound/dmasound_awacs.c 2003-02-16 20:21:48.000000000 +0100 @@ -45,7 +45,14 @@ * 01/02/2002 [0.7] - BenH * - all sort of minor bits went in since the latest update, I * bumped the version number for that reason -*/ + * + * 07/26/2002 [0.8] - BenH + * - More minor bits since last changelog (I should be more careful + * with those) + * - Support for snapper & better tumbler integration by Toby Sargeant + * - Headphone detect for scremer by Julien Blache + * - More tumbler fixed by Andreas Schwab + */ /* GENERAL FIXME/TODO: check that the assumptions about what is written to mac-io is valid for DACA & Tumbler. @@ -88,10 +95,14 @@ #include "awacs_defs.h" #include "dmasound.h" +#include "tas3001c.h" +#include "tas3004.h" +#include "tas_common.h" #define DMASOUND_AWACS_REVISION 0 #define DMASOUND_AWACS_EDITION 7 +#define AWACS_SNAPPER 110 /* fake revision # for snapper */ #define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ #define AWACS_TUMBLER 90 /* fake revision # for tumbler */ #define AWACS_DACA 80 /* fake revision # for daca (ibook) */ @@ -102,11 +113,13 @@ */ static int awacs_irq, awacs_tx_irq, awacs_rx_irq; static volatile struct awacs_regs *awacs; +static volatile u32 *i2s; static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; static int awacs_rate_index; static int awacs_subframe; static int awacs_spkr_vol; static struct device_node* awacs_node; +static struct device_node* i2s_node; static char awacs_name[64]; static int awacs_revision; @@ -163,6 +176,8 @@ static int cd_lev = 0x6363 ; /* 99 % */ static int line_lev = 0 ; +static int hdp_connected = 0; + /* * Stuff for outputting a beep. The values range from -327 to +327 * so we can multiply by an amplitude in the range 0..100 to get a @@ -293,19 +308,6 @@ extern int daca_enter_sleep(void); extern int daca_leave_sleep(void); -extern int tas_init(void); -extern int tas_cleanup(void); -extern int tumbler_set_volume(uint left_vol, uint right_vol); -extern void tumbler_get_volume(uint * left_vol, uint *right_vol); -extern void tumbler_set_treble(int treble); -extern void tumbler_get_treble(int *treble); -extern void tumbler_set_bass(int bass); -extern void tumbler_get_bass(int *bass); -extern void tumbler_set_pcm_lvl(int pcm_lvl); -extern void tumbler_get_pcm_lvl(int *pcm_lvl); -extern int tumbler_enter_sleep(void); -extern int tumbler_leave_sleep(void); - #define TRY_LOCK() \ if ((rc = down_interruptible(&dmasound_sem)) != 0) \ return rc; @@ -332,7 +334,7 @@ } -/*** AE - TUMBLER START *********************************************************/ +/*** AE - TUMBLER / SNAPPER START ************************************************/ int gpio_audio_reset, gpio_audio_reset_pol; @@ -394,17 +396,22 @@ return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0); } +/* + * Headphone interrupt via GPIO (Tumbler, Snapper, DACA) + */ static void headphone_intr(int irq, void *devid, struct pt_regs *regs) { if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) { printk(KERN_INFO "Audio jack plugged, muting speakers.\n"); - write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); + write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); + tas_output_device_change(sound_device_id,TAS_OUTPUT_HEADPHONES,0); } else { printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n"); write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); + tas_output_device_change(sound_device_id,TAS_OUTPUT_INTERNAL_SPKR,0); } } @@ -412,7 +419,7 @@ /* Initialize tumbler */ static int -awacs_tumbler_init(void) +tas_dmasound_init(void) { setup_audio_gpio( "audio-hw-reset", @@ -469,15 +476,124 @@ static int -awacs_tumbler_cleanup(void) +tas_dmasound_cleanup(void) { if (gpio_headphone_irq) free_irq(gpio_headphone_irq, 0); return 0; } +/* We don't support 48k yet */ +static int tas_freqs[1] = { 44100 } ; +static int tas_freqs_ok[1] = { 1 } ; -/*** AE - TUMBLER END *********************************************************/ +/* don't know what to do really - just have to leave it where + * OF left things +*/ + +static int +tas_set_frame_rate(void) +{ + if (i2s) { + out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); + out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); + } + dmasound.hard.speed = 44100 ; + awacs_rate_index = 0 ; + return 44100 ; +} + +static int +tas_mixer_ioctl(u_int cmd, u_long arg) +{ + int data; + int rc; + + rc=tas_device_ioctl(cmd, arg); + if (rc != -EINVAL) { + return rc; + } + + if ((cmd & ~0xff) == MIXER_WRITE(0) && + tas_supported_mixers() & (1<<(cmd & 0xff))) { + rc = get_user(data, (int *)(arg)); + if (rc<0) return rc; + tas_set_mixer_level(cmd & 0xff, data); + tas_get_mixer_level(cmd & 0xff, &data); + return ioctl_return2((int *)(arg), data); + } + if ((cmd & ~0xff) == MIXER_READ(0) && + tas_supported_mixers() & (1<<(cmd & 0xff))) { + tas_get_mixer_level(cmd & 0xff, &data); + return ioctl_return2((int *)(arg), data); + } + + switch(cmd) { + case SOUND_MIXER_READ_DEVMASK: + data = tas_supported_mixers() | SOUND_MASK_SPEAKER; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_STEREODEVS: + data = tas_stereo_mixers(); + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_CAPS: + rc = IOCTL_OUT(arg, 0); + break; + case SOUND_MIXER_READ_RECMASK: + data = 0; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_RECSRC: + data = 0; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_IN(arg, data); + data =0; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_WRITE_SPEAKER: /* really bell volume */ + IOCTL_IN(arg, data); + beep_vol = data & 0xff; + /* fall through */ + case SOUND_MIXER_READ_SPEAKER: + rc = IOCTL_OUT(arg, (beep_vol<<8) | beep_vol); + break; + case SOUND_MIXER_OUTMASK: + case SOUND_MIXER_OUTSRC: + default: + rc = -EINVAL; + } + + return rc; +} + +static void __init +tas_init_frame_rates(unsigned int *prop, unsigned int l) +{ + int i ; + if (prop) { + for (i=0; i<1; i++) + tas_freqs_ok[i] = 0; + for (l /= sizeof(int); l > 0; --l) { + unsigned int r = *prop++; + /* Apple 'Fixed' format */ + if (r >= 0x10000) + r >>= 16; + for (i = 0; i < 1; ++i) { + if (r == tas_freqs[i]) { + tas_freqs_ok[i] = 1; + break; + } + } + } + } + /* else we assume that all the rates are available */ +} + + +/*** AE - TUMBLER / SNAPPER END ************************************************/ @@ -509,8 +625,10 @@ static int __init PMacIrqInit(void) { - if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", 0) - || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", 0) + if (awacs) + if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", 0)) + return 0; + if (request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", 0) || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", 0)) return 0; return 1; @@ -523,23 +641,28 @@ DBDMA_DO_STOP(awacs_txdma); DBDMA_DO_STOP(awacs_rxdma); - /* disable interrupts from awacs interface */ - out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); - + if (awacs) + /* disable interrupts from awacs interface */ + out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); + /* Switch off the sound clock */ pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); /* Make sure proper bits are set on pismo & tipb */ - if (machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) { + if ((machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook3,2")) && awacs) { awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; awacs_write(MASK_ADDR1 | awacs_reg[1]); wait_ms(200); } - free_irq(awacs_irq, 0); + if (awacs) + free_irq(awacs_irq, 0); free_irq(awacs_tx_irq, 0); free_irq(awacs_rx_irq, 0); - /* all OF versions I've seen use this value */ - iounmap((void *)awacs); + + if (awacs) + iounmap((void *)awacs); + if (i2s) + iounmap((void *)i2s); iounmap((void *)awacs_txdma); iounmap((void *)awacs_rxdma); @@ -555,7 +678,9 @@ kfree(beep_dbdma_cmd_space); if (beep_buf) { kfree(beep_buf); +#ifdef CONFIG_VT kd_mksound = orig_mksound; +#endif } #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&awacs_sleep_notifier); @@ -569,26 +694,16 @@ DBDMA_DO_STOP(awacs_txdma); } -static int tumbler_freqs[2] = { 48000, 44100 } ; -static int tumbler_freqs_ok[2] = { 1, 1 } ; - -/* don't know what to do really - just have to leave it where - * OF left things -*/ - -static int tumbler_set_frame_rate(void) -{ - dmasound.hard.speed = 44100 ; - awacs_rate_index = 0 ; - return 44100 ; -} - /* don't know what to do really - just have to leave it where * OF left things */ static int daca_set_frame_rate(void) { + if (i2s) { + out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); + out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); + } dmasound.hard.speed = 44100 ; awacs_rate_index = 0 ; return 44100 ; @@ -599,7 +714,8 @@ }; static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; -static int awacs_set_frame_rate(int desired, int catch_r) +static int +awacs_set_frame_rate(int desired, int catch_r) { int tolerance, i = 8 ; /* @@ -623,13 +739,9 @@ return dmasound.hard.speed; } -static int burgundy_frame_rates = 1 ; -static int burgundy_set_frame_rate(void) +static int +burgundy_set_frame_rate(void) { -#ifdef DEBUG_DMASOUND -if (burgundy_frame_rates > 1) - printk("dmasound_pmac: warning Burgundy had more than one frame rate\n"); -#endif awacs_rate_index = 0 ; awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ; /* XXX disable error interrupt on burgundy for now */ @@ -637,24 +749,24 @@ return 44100 ; } -static int set_frame_rate(int desired, int catch_r) +static int +set_frame_rate(int desired, int catch_r) { switch (awacs_revision) { case AWACS_BURGUNDY: - dmasound.hard.speed = - burgundy_set_frame_rate(); + dmasound.hard.speed = burgundy_set_frame_rate(); break ; case AWACS_TUMBLER: - dmasound.hard.speed = - tumbler_set_frame_rate(); + case AWACS_SNAPPER: + dmasound.hard.speed = tas_set_frame_rate(); break ; case AWACS_DACA: dmasound.hard.speed = daca_set_frame_rate(); break ; default: - dmasound.hard.speed = - awacs_set_frame_rate(desired, catch_r); + dmasound.hard.speed = awacs_set_frame_rate(desired, + catch_r); break ; } return dmasound.hard.speed ; @@ -704,11 +816,13 @@ dmasound.trans_write = &transAwacsExpand; dmasound.trans_read = &transAwacsNormalRead; - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); - + if (awacs) { + if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) + out_le32(&awacs->byteswap, BS_VAL); + else + out_le32(&awacs->byteswap, 0); + } + expand_bal = -dmasound.soft.speed; } @@ -793,7 +907,20 @@ static int PMacSetVolume(int volume) { - return awacs_volume_setter(volume, 2, MASK_AMUTE, 6); + printk(KERN_WARNING "Bogus call to PMacSetVolume !\n"); + return 0; +} + +static void awacs_setup_for_beep(int speed) +{ + out_le32(&awacs->control, + (in_le32(&awacs->control) & ~0x1f00) + | ((speed > 0 ? speed : awacs_rate_index) << 8)); + + if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE) && speed == -1) + out_le32(&awacs->byteswap, BS_VAL); + else + out_le32(&awacs->byteswap, 0); } static void __PMacPlay(void) @@ -816,15 +943,8 @@ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); while ( (in_le32(&awacs_txdma->status) & RUN) && count--) udelay(1); - /* FIXME: check that this is OK for other chip sets */ - out_le32(&awacs->control, - (in_le32(&awacs->control) & ~0x1f00) - | (awacs_rate_index << 8)); - - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); + if (awacs) + awacs_setup_for_beep(-1); out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[next_frg]))); @@ -925,6 +1045,7 @@ { int i = write_sq.front; int stat; + int i_nowrap = write_sq.front; volatile struct dbdma_cmd *cp; /* != 0 when we are dealing with a DEAD xfer */ static int emergency_in_use = 0 ; @@ -981,6 +1102,7 @@ emergency_in_use = 0 ; /* done that */ --write_sq.count; --write_sq.active; + i_nowrap++; if (++i >= write_sq.max_count) i = 0; } @@ -993,7 +1115,7 @@ } /* if we used some data up then wake the writer to supply some more*/ - if (i != write_sq.front) + if (i_nowrap != write_sq.front) WAKE_UP(write_sq.action_queue); write_sq.front = i; @@ -1090,9 +1212,26 @@ pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs) { int ctrl = in_le32(&awacs->control); + int status = in_le32(&awacs->codec_stat); + int r1; - if (ctrl & MASK_PORTCHG) { - /* do something when headphone is plugged/unplugged? */ + if (ctrl & MASK_PORTCHG) { + /* tested on Screamer, should work on others too */ + if (awacs_revision == AWACS_SCREAMER) { + if (((status & MASK_HDPCONN) >> 3) && (hdp_connected == 0)) { + hdp_connected = 1; + + r1 = awacs_reg[1] | MASK_SPKMUTE; + awacs_reg[1] = r1; + awacs_write(r1 | MASK_ADDR_MUTE); + } else if (((status & MASK_HDPCONN) >> 3 == 0) && (hdp_connected == 1)) { + hdp_connected = 0; + + r1 = awacs_reg[1] & ~MASK_SPKMUTE; + awacs_reg[1] = r1; + awacs_write(r1 | MASK_ADDR_MUTE); + } + } } if (ctrl & MASK_CNTLERR) { int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16; @@ -1108,7 +1247,7 @@ awacs_write(int val) { int count = 300 ; - if (awacs_revision >= AWACS_DACA) + if (awacs_revision >= AWACS_DACA || !awacs) return ; while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) @@ -1131,14 +1270,8 @@ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); while ((in_le32(&awacs_txdma->status) & RUN) && count--) udelay(1); - /* FIXME: check this is OK for DACA, Tumbler */ - out_le32(&awacs->control, - (in_le32(&awacs->control) & ~0x1f00) - | (awacs_rate_index << 8)); - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); + if (awacs) + awacs_setup_for_beep(-1); beep_playing = 0; } restore_flags(flags); @@ -1233,11 +1366,8 @@ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); while ((in_le32(&awacs_txdma->status) & RUN) && count--) udelay(1); /* timeout > 2 samples at lowest rate*/ - /* FIXME: check this is OK on DACA, Tumbler */ - out_le32(&awacs->control, - (in_le32(&awacs->control) & ~0x1f00) - | (beep_speed << 8)); - out_le32(&awacs->byteswap, 0); /* force BE */ + if (awacs) + awacs_setup_for_beep(beep_speed); out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); (void)in_le32(&awacs_txdma->status); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); @@ -1263,10 +1393,12 @@ awacs_write(awacs_reg[1] + MASK_ADDR1); awacs_write(awacs_reg[7] + MASK_ADDR7); } - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); + if (awacs) { + if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) + out_le32(&awacs->byteswap, BS_VAL); + else + out_le32(&awacs->byteswap, 0); + } } #ifdef CONFIG_PMAC_PBOOK @@ -1293,9 +1425,18 @@ /* stop rx - if going - a bit of a daft user... but */ out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16)); /* deny interrupts */ + if (awacs) + disable_irq(awacs_irq); + disable_irq(awacs_tx_irq); + disable_irq(awacs_rx_irq); + /* Chip specific sleep code */ switch (awacs_revision) { case AWACS_TUMBLER: - tumbler_enter_sleep(); /* Stub for now */ + case AWACS_SNAPPER: + write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); + write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); + tas_enter_sleep(); + write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); break ; case AWACS_DACA: daca_enter_sleep(); @@ -1308,17 +1449,14 @@ out_le32(&awacs->control, 0x11) ; break ; } - disable_irq(awacs_irq); - disable_irq(awacs_tx_irq); - disable_irq(awacs_rx_irq); /* Disable sound clock */ pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); /* According to Darwin, we do that after turning off the sound * chip clock. All this will have to be cleaned up once we properly * parse the OF sound-objects */ - if (machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) { + if ((machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook3,2")) && awacs) { awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; awacs_write(MASK_ADDR1 | awacs_reg[1]); wait_ms(200); @@ -1327,8 +1465,8 @@ case PBOOK_WAKE: /* Enable sound clock */ pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1); - if (machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) { + if ((machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook3,2")) && awacs) { wait_ms(100); awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1); awacs_write(MASK_ADDR1 | awacs_reg[1]); @@ -1338,8 +1476,15 @@ /* restore settings */ switch (awacs_revision) { case AWACS_TUMBLER: + case AWACS_SNAPPER: + write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); + write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); + write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); + wait_ms(100); + write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol); + wait_ms(150); + tas_leave_sleep(); /* Stub for now */ headphone_intr(0,0,0); - tumbler_leave_sleep(); /* Stub for now */ break; case AWACS_DACA: wait_ms(10); /* Check this !!! */ @@ -1354,17 +1499,20 @@ break ; } /* Recalibrate chip */ - if (awacs_revision == AWACS_SCREAMER) + if (awacs_revision == AWACS_SCREAMER && awacs) awacs_recalibrate(); /* Make sure dma is stopped */ PMacSilence(); - enable_irq(awacs_irq); + if (awacs) + enable_irq(awacs_irq); enable_irq(awacs_tx_irq); enable_irq(awacs_rx_irq); - /* OK, allow ints back again */ - out_le32(&awacs->control, MASK_IEPC - | (awacs_rate_index << 8) | 0x11 - | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); + if (awacs) { + /* OK, allow ints back again */ + out_le32(&awacs->control, MASK_IEPC + | (awacs_rate_index << 8) | 0x11 + | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); + } if (macio_base && is_pbook_g3) { /* FIXME: should restore the setup we had...*/ out_8(macio_base + 0x37, 3); @@ -1952,7 +2100,7 @@ case SOUND_MIXER_READ_SPEAKER: data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER); data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8); - rc = IOCTL_OUT(arg, ~data); + rc = IOCTL_OUT(arg, (~data) & 0x0000ffff); break; case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ IOCTL_IN(arg, data); @@ -2007,89 +2155,6 @@ return rc; } -static int tumbler_mixer_ioctl(u_int cmd, u_long arg) -{ - int data; - int rc; - - /* We are, we are, we are... Tumbler (and very dumb) */ - /* Ok, we're not THAT dumb anymore, but still pretty dumb :-) */ - - switch(cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME | SOUND_MASK_ALTPCM | - SOUND_MASK_BASS | SOUND_MASK_TREBLE | - SOUND_MASK_PCM; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECMASK: - data = 0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - data = 0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data =0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME | SOUND_MASK_PCM; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_CAPS: - rc = IOCTL_OUT(arg, 0); - break; - case SOUND_MIXER_WRITE_BASS: - IOCTL_IN(arg, data); - tumbler_set_bass(data); - /* Fall through */ - case SOUND_MIXER_READ_BASS: - tumbler_get_bass(&data); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_TREBLE: - IOCTL_IN(arg, data); - tumbler_set_treble(data); - /* Fall through */ - case SOUND_MIXER_READ_TREBLE: - tumbler_get_treble(&data); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_PCM: - IOCTL_IN(arg, data); - tumbler_set_pcm_lvl(data); - /* Fall through */ - case SOUND_MIXER_READ_PCM: - tumbler_get_pcm_lvl(&data); - IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - tumbler_set_volume(data, data); - /* Fall through */ - case SOUND_MIXER_READ_VOLUME: - tumbler_get_volume(& data, &data); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ - IOCTL_IN(arg, data); - beep_vol = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_ALTPCM: - rc = IOCTL_OUT(arg, beep_vol); - break; - case SOUND_MIXER_OUTMASK: - case SOUND_MIXER_OUTSRC: - default: - rc = -EINVAL; - } - - return rc; -} - static int daca_mixer_ioctl(u_int cmd, u_long arg) { int data; @@ -2154,7 +2219,8 @@ rc = daca_mixer_ioctl(cmd, arg); break; case AWACS_TUMBLER: - rc = tumbler_mixer_ioctl(cmd, arg); + case AWACS_SNAPPER: + rc = tas_mixer_ioctl(cmd, arg); break ; default: /* ;-)) */ rc = awacs_mixer_ioctl(cmd, arg); @@ -2171,7 +2237,9 @@ case AWACS_TUMBLER: printk("AE-Init tumbler mixer\n"); break ; - + case AWACS_SNAPPER: + printk("AE-Init snapper mixer\n"); + break ; case AWACS_DACA: case AWACS_BURGUNDY: break ; /* don't know yet */ @@ -2362,12 +2430,12 @@ len += sprintf(b,"44100 ") ; break ; case AWACS_TUMBLER: - for (i=0; i<2; i++){ - if (tumbler_freqs_ok[i]) - len += sprintf(b+len,"%d ", tumbler_freqs[i]) ; + case AWACS_SNAPPER: + for (i=0; i<1; i++){ + if (tas_freqs_ok[i]) + len += sprintf(b+len,"%d ", tas_freqs[i]) ; } break ; - case AWACS_AWACS: case AWACS_SCREAMER: default: @@ -2469,8 +2537,8 @@ code that looks for chip properties knows how to go about it. */ -static struct device_node -__init *get_snd_io_node(void) +static struct device_node* __init +get_snd_io_node(void) { struct device_node *np = NULL; @@ -2491,7 +2559,7 @@ * this seems to be what iBooks (& Tumbler) have. */ if (np == NULL) - np = find_devices("i2s-a"); + np = i2s_node = find_devices("i2s-a"); /* if we didn't find this - perhaps we are on an early model * which _only_ has an 'awacs' node @@ -2511,8 +2579,8 @@ we have to deduce the info other ways for these. */ -static struct device_node -__init *get_snd_info_node(struct device_node *io) +static struct device_node* __init +get_snd_info_node(struct device_node *io) { struct device_node *info; @@ -2526,8 +2594,8 @@ /* Find out what type of codec we have. */ -static int -__init get_codec_type(struct device_node *info) +static int __init +get_codec_type(struct device_node *info) { /* already set if pre-davbus model and info will be NULL */ int codec = awacs_revision ; @@ -2544,14 +2612,16 @@ codec = AWACS_DACA; if (device_is_compatible(info, "tumbler")) codec = AWACS_TUMBLER; + if (device_is_compatible(info, "snapper")) + codec = AWACS_SNAPPER; } return codec ; } /* find out what type, if any, of expansion card we have */ -static void -__init get_expansion_type(void) +static void __init +get_expansion_type(void) { if (find_devices("perch") != NULL) has_perch = 1; @@ -2569,8 +2639,8 @@ * Set dmasound.mach.max_dsp_rate on the basis of these routines. */ -static void -__init init_awacs_frame_rates(unsigned int *prop, unsigned int l) +static void __init +awacs_init_frame_rates(unsigned int *prop, unsigned int l) { int i ; if (prop) { @@ -2592,31 +2662,8 @@ /* else we assume that all the rates are available */ } -static void -__init init_tumbler_frame_rates(unsigned int *prop, unsigned int l) -{ - int i ; - if (prop) { - for (i=0; i<2; i++) - tumbler_freqs_ok[i] = 0; - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - for (i = 0; i < 2; ++i) { - if (r == tumbler_freqs[i]) { - tumbler_freqs_ok[i] = 1; - break; - } - } - } - } - /* else we assume that all the rates are available */ -} - -static void -__init init_burgundy_frame_rates(unsigned int *prop, unsigned int l) +static void __init +burgundy_init_frame_rates(unsigned int *prop, unsigned int l) { int temp[9] ; int i = 0 ; @@ -2641,8 +2688,8 @@ #endif } -static void -__init init_daca_frame_rates(unsigned int *prop, unsigned int l) +static void __init +daca_init_frame_rates(unsigned int *prop, unsigned int l) { int temp[9] ; int i = 0 ; @@ -2668,21 +2715,22 @@ #endif } -static void -__init init_frame_rates(unsigned int *prop, unsigned int l) +static void __init +init_frame_rates(unsigned int *prop, unsigned int l) { - switch (awacs_revision){ + switch (awacs_revision) { case AWACS_TUMBLER: - init_tumbler_frame_rates(prop, l); + case AWACS_SNAPPER: + tas_init_frame_rates(prop, l); break ; case AWACS_DACA: - init_daca_frame_rates(prop, l); + daca_init_frame_rates(prop, l); break ; case AWACS_BURGUNDY: - init_burgundy_frame_rates(prop, l); + burgundy_init_frame_rates(prop, l); break ; - default: /* ;-))) */ - init_awacs_frame_rates(prop, l); + default: + awacs_init_frame_rates(prop, l); break ; } } @@ -2690,11 +2738,11 @@ /* find things/machines that can't do mac-io byteswap */ -static void -__init set_hw_byteswap(struct device_node *io) +static void __init +set_hw_byteswap(struct device_node *io) { struct device_node *mio ; - unsigned int *p, kl = 0 ; + unsigned int kl = 0 ; /* if seems that Keylargo can't byte-swap */ @@ -2741,9 +2789,11 @@ if( beep_dbdma_cmd_space ) kfree(beep_dbdma_cmd_space) ; return -ENOMEM ; } +#ifdef CONFIG_VT /* OK, we should be safe to claim the mksound vector now */ orig_mksound = kd_mksound; kd_mksound = awacs_mksound; +#endif return 0 ; } @@ -2839,23 +2889,26 @@ } /* all OF versions I've seen use this value */ - awacs = (volatile struct awacs_regs *) - ioremap(io->addrs[0].address, 0x1000); + if (i2s_node) + i2s = (u32 *)ioremap(io->addrs[0].address, 0x1000); + else + awacs = (volatile struct awacs_regs *) + ioremap(io->addrs[0].address, 0x1000); awacs_txdma = (volatile struct dbdma_regs *) ioremap(io->addrs[1].address, 0x100); awacs_rxdma = (volatile struct dbdma_regs *) ioremap(io->addrs[2].address, 0x100); -#ifdef CONFIG_PMAC_PBOOK /* first of all make sure that the chip is powered up....*/ pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1); - if (awacs_revision == AWACS_SCREAMER) + if (awacs_revision == AWACS_SCREAMER && awacs) awacs_recalibrate(); -#endif + awacs_irq = io->intrs[0].line; awacs_tx_irq = io->intrs[1].line; awacs_rx_irq = io->intrs[2].line; + /* Hack for legacy crap that will be killed someday */ awacs_node = io; /* if we have an awacs or screamer - probe the chip to make @@ -2906,8 +2959,9 @@ /* if it's there use it to set up frame rates */ init_frame_rates(prop, l) ; } - - out_le32(&awacs->control, 0x11); /* set everything quiesent */ + + if (awacs) + out_le32(&awacs->control, 0x11); /* set everything quiesent */ set_hw_byteswap(io) ; /* figure out if the h/w can do it */ @@ -2942,9 +2996,20 @@ #ifdef CONFIG_KMOD request_module("i2c-keywest"); #endif /* CONFIG_KMOD */ - awacs_tumbler_init(); - tas_init(); + tas_register_driver(&tas3001c_hooks); + tas_init(I2C_DRIVERID_TAS3001C, I2C_DRIVERNAME_TAS3001C); + tas_dmasound_init(); + tas_post_init(); break ; + case AWACS_SNAPPER: +#ifdef CONFIG_KMOD + request_module("i2c-keywest"); +#endif /* CONFIG_KMOD */ + tas_register_driver(&tas3004_hooks); + tas_init(I2C_DRIVERID_TAS3004,I2C_DRIVERNAME_TAS3004); + tas_dmasound_init(); + tas_post_init(); + break; case AWACS_DACA: #ifdef CONFIG_KMOD request_module("i2c-keywest"); @@ -3028,11 +3093,15 @@ dmasound.mach.hardware_afmts = AFMT_S16_BE ; /* shut out chips that do output only. - may need to extend this to machines which have no inputs - even tho' - they use screamer - IIRC one of the powerbooks is like this. - */ + * may need to extend this to machines which have no inputs - even tho' + * they use screamer - IIRC one of the powerbooks is like this. + * + * FIXME: Actually, some TUMBLER and SNAPPER do have inputs... + */ - if (awacs_revision != AWACS_TUMBLER && awacs_revision != AWACS_DACA) { + if (awacs_revision != AWACS_TUMBLER && + awacs_revision != AWACS_SNAPPER && + awacs_revision != AWACS_DACA) { dmasound.mach.capabilities = DSP_CAP_DUPLEX ; dmasound.mach.record = PMacRecord ; } @@ -3050,6 +3119,9 @@ case AWACS_TUMBLER: sprintf(awacs_name, "PowerMac Tumbler ") ; break ; + case AWACS_SNAPPER: + sprintf(awacs_name, "PowerMac Snapper ") ; + break ; case AWACS_SCREAMER: sprintf(awacs_name, "PowerMac Screamer ") ; break ; @@ -3066,7 +3138,8 @@ { switch (awacs_revision) { case AWACS_TUMBLER: - awacs_tumbler_cleanup(); + case AWACS_SNAPPER: + tas_dmasound_cleanup(); tas_cleanup(); break ; case AWACS_DACA: @@ -3081,3 +3154,10 @@ module_init(dmasound_awacs_init); module_exit(dmasound_awacs_cleanup); +/* + * Local Variables: + * tab-width: 8 + * indent-tabs-mode: t + * c-basic-offset: 8 + * End: + */ diff -uNr linux-2.4.20/drivers/sound/dmasound/tas3001c.c linux-2.4.20-ben6/drivers/sound/dmasound/tas3001c.c --- linux-2.4.20/drivers/sound/dmasound/tas3001c.c 2002-02-25 20:38:05.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/tas3001c.c 2003-02-16 20:20:09.000000000 +0100 @@ -1,38 +1,17 @@ /* - * Driver for the i2c/i2s based TA3001C sound chip used - * on some Apple hardware. Also known as "tumbler". + * Driver for the i2c/i2s based TA3004 sound chip used + * on some Apple hardware. Also known as "snapper". * - * 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. - * - * Modified by Christopher C. Chimelis : + * Tobias Sargeant + * Based upon, tas3001c.c by Christopher C. Chimelis : * * TODO: * ----- - * * Enable DRC since the TiBook speakers are less than good * * Enable control over input line 2 (is this connected?) - * * Play with the dual six-stage cascading biquad filtering to see how - * we can use it to our advantage (currently not implemented) - * * Reorganise driver a bit to make it cleaner and easier to work with - * (read: use the header file more :-P) - * * Implement sleep support - * - * Version 0.4: - * ------------ - * * Balance control finally works (can someone document OSS better please?) - * * Moved to a struct for common values referenced in the driver - * * Put stubs in for sleep/wake-up support for now. This will take some - * experimentation to make sure that the timing is right, since the - * TAS hardware requires specific timing while enabling low-power mode. - * I may cheat for now and just reset the chip on wake-up, but I'd rather - * not if I don't have to. - * - * Version 0.3: - * ------------ - * * Fixed volume control - * * Added bass and treble control - * * Added PCM line level control (mixer 1 in the TAS manual) + * * Implement sleep support (at least mute everything and + * * set gains to minimum during sleep) + * * Look into some of Darwin's tweaks regarding the mute + * * lines (delays & different behaviour on some HW) * */ @@ -45,403 +24,854 @@ #include #include #include +#include #include #include #include #include #include "dmasound.h" +#include "tas_common.h" #include "tas3001c.h" -#define I2C_DRIVERID_TAS (0xFEBA) +#include "tas_ioctl.h" -#define TAS_VERSION "0.3" -#define TAS_DATE "20011214" +#define TAS3001C_BIQUAD_FILTER_COUNT 6 +#define TAS3001C_BIQUAD_CHANNEL_COUNT 2 -#define TAS_SETTING_MAX 100 +#define VOL_DEFAULT (100 * 4 / 5) +#define INPUT_DEFAULT (100 * 4 / 5) +#define BASS_DEFAULT (100 / 2) +#define TREBLE_DEFAULT (100 / 2) + +struct tas3001c_data_t { + struct tas_data_t super; + int device_id; + int output_id; + int speaker_id; + struct tas_drce_t drce_state; +}; -#define VOL_DEFAULT (((((TAS_SETTING_MAX*4)/5)<<0)<<8) | (((TAS_SETTING_MAX*4)/5)<<0)) -#define INPUT_DEFAULT (((TAS_SETTING_MAX*4)/5)<<0) -#define BASS_DEFAULT ((TAS_SETTING_MAX/2)<<0) -#define TREBLE_DEFAULT ((TAS_SETTING_MAX/2)<<0) -static struct i2c_client * tumbler_client = NULL; +static const union tas_biquad_t +tas3001c_eq_unity={ + buf: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } +}; -int tumbler_enter_sleep(void); -int tumbler_leave_sleep(void); -static int tas_attach_adapter(struct i2c_adapter *adapter); -static int tas_detect_client(struct i2c_adapter *adapter, int address); -static int tas_detach_client(struct i2c_client *client); +static inline unsigned char db_to_regval(short db) { + int r=0; -/* Unique ID allocation */ -static int tas_id; -static int tas_initialized; + r=(db+0x59a0) / 0x60; -static struct device_node* tas_node; -static u8 tas_i2c_address = 0x34; + if (r < 0x91) return 0x91; + if (r > 0xef) return 0xef; + return r; +} -struct tas_data_t { - uint left_vol; /* left volume */ - uint right_vol; /* right volume */ - uint treble; /* treble */ - uint bass; /* bass */ - uint pcm_level; /* pcm level */ -}; +static inline short quantize_db(short db) { + return db_to_regval(db) * 0x60 - 0x59a0; +} -struct i2c_driver tas_driver = { - name: "TAS3001C driver V 0.3", - id: I2C_DRIVERID_TAS, - flags: I2C_DF_NOTIFY, - attach_adapter: &tas_attach_adapter, - detach_client: &tas_detach_client, - command: NULL, - inc_use: NULL, /* &tas_inc_use, */ - dec_use: NULL /* &tas_dev_use */ -}; -int -tumbler_get_volume(uint * left_vol, uint *right_vol) +static inline int +register_width(enum tas3001c_reg_t r) { - struct tas_data_t *data; + switch(r) { + case TAS3001C_REG_MCR: + case TAS3001C_REG_TREBLE: + case TAS3001C_REG_BASS: + return 1; - if (!tumbler_client) - return -1; + case TAS3001C_REG_DRC: + return 2; - data = (struct tas_data_t *) (tumbler_client->data); - *left_vol = data->left_vol; - *right_vol = data->right_vol; - - return 0; + case TAS3001C_REG_MIXER1: + case TAS3001C_REG_MIXER2: + return 3; + + case TAS3001C_REG_VOLUME: + return 6; + + case TAS3001C_REG_LEFT_BIQUAD0: + case TAS3001C_REG_LEFT_BIQUAD1: + case TAS3001C_REG_LEFT_BIQUAD2: + case TAS3001C_REG_LEFT_BIQUAD3: + case TAS3001C_REG_LEFT_BIQUAD4: + case TAS3001C_REG_LEFT_BIQUAD5: + case TAS3001C_REG_LEFT_BIQUAD6: + + case TAS3001C_REG_RIGHT_BIQUAD0: + case TAS3001C_REG_RIGHT_BIQUAD1: + case TAS3001C_REG_RIGHT_BIQUAD2: + case TAS3001C_REG_RIGHT_BIQUAD3: + case TAS3001C_REG_RIGHT_BIQUAD4: + case TAS3001C_REG_RIGHT_BIQUAD5: + case TAS3001C_REG_RIGHT_BIQUAD6: + return 15; + + default: + return 0; + } } -int -tumbler_set_register(uint reg, uint size, char *block) -{ - if (i2c_smbus_write_block_data(tumbler_client, reg, size, block) < 0) { - printk("tas3001c: I2C write failed \n"); - return -1; +static int +tas3001c_write_register( struct tas3001c_data_t *self, + enum tas3001c_reg_t reg_num, + char *data, + uint write_mode) +{ + if (reg_num==TAS3001C_REG_MCR || + reg_num==TAS3001C_REG_BASS || + reg_num==TAS3001C_REG_TREBLE) { + return tas_write_byte_register(&self->super, + (uint)reg_num, + *data, + write_mode); + } else { + return tas_write_register(&self->super, + (uint)reg_num, + register_width(reg_num), + data, + write_mode); } - return 0; } -int -tumbler_get_pcm_lvl(uint *pcm_lvl) +static int +tas3001c_sync_register( struct tas3001c_data_t *self, + enum tas3001c_reg_t reg_num) { - struct tas_data_t *data; - - if (!tumbler_client) - return -1; + if (reg_num==TAS3001C_REG_MCR || + reg_num==TAS3001C_REG_BASS || + reg_num==TAS3001C_REG_TREBLE) { + return tas_sync_byte_register(&self->super, + (uint)reg_num, + register_width(reg_num)); + } else { + return tas_sync_register(&self->super, + (uint)reg_num, + register_width(reg_num)); + } +} - data = (struct tas_data_t *) (tumbler_client->data); - *pcm_lvl = data->pcm_level; +static int +tas3001c_read_register( struct tas3001c_data_t *self, + enum tas3001c_reg_t reg_num, + char *data, + uint write_mode) +{ + return tas_read_register(&self->super, + (uint)reg_num, + register_width(reg_num), + data); +} + +static inline int +tas3001c_fast_load(struct tas3001c_data_t *self, int fast) +{ + if (fast) + self->super.shadow[TAS3001C_REG_MCR][0] |= 0x80; + else + self->super.shadow[TAS3001C_REG_MCR][0] &= 0x7f; + return tas3001c_sync_register(self,TAS3001C_REG_MCR); +} + +static uint +tas3001c_supported_mixers(struct tas3001c_data_t *self) +{ + return SOUND_MASK_VOLUME | + SOUND_MASK_PCM | + SOUND_MASK_ALTPCM | + SOUND_MASK_TREBLE | + SOUND_MASK_BASS; +} - return 0; +static int +tas3001c_mixer_is_stereo(struct tas3001c_data_t *self,int mixer) +{ + switch(mixer) { + case SOUND_MIXER_VOLUME: + return 1; + default: + return 0; + } } -int -tumbler_get_treble(uint *treble) +static uint +tas3001c_stereo_mixers(struct tas3001c_data_t *self) { - struct tas_data_t *data; + uint r=tas3001c_supported_mixers(self); + uint i; + + for (i=1; idata); - *treble = data->treble; + + *level=self->super.mixer[mixer]; return 0; } -int -tumbler_get_bass(uint *bass) +static int +tas3001c_set_mixer_level(struct tas3001c_data_t *self,int mixer,uint level) { - struct tas_data_t *data; - - if (!tumbler_client) - return -1; + int rc; + tas_shadow_t *shadow; - data = (struct tas_data_t *) (tumbler_client->data); - *bass = data->bass; + uint temp; + uint offset=0; + if (!self) + return -1; + + shadow=self->super.shadow; + + if (!tas3001c_mixer_is_stereo(self,mixer)) + level = tas_mono_to_stereo(level); + + switch(mixer) { + case SOUND_MIXER_VOLUME: + temp = tas3001c_gain.master[level&0xff]; + shadow[TAS3001C_REG_VOLUME][0] = (temp >> 16) & 0xff; + shadow[TAS3001C_REG_VOLUME][1] = (temp >> 8) & 0xff; + shadow[TAS3001C_REG_VOLUME][2] = (temp >> 0) & 0xff; + temp = tas3001c_gain.master[(level>>8)&0xff]; + shadow[TAS3001C_REG_VOLUME][3] = (temp >> 16) & 0xff; + shadow[TAS3001C_REG_VOLUME][4] = (temp >> 8) & 0xff; + shadow[TAS3001C_REG_VOLUME][5] = (temp >> 0) & 0xff; + rc = tas3001c_sync_register(self,TAS3001C_REG_VOLUME); + break; + case SOUND_MIXER_ALTPCM: + /* tas3001c_fast_load(self, 1); */ + level = tas_mono_to_stereo(level); + temp = tas3001c_gain.mixer[level&0xff]; + shadow[TAS3001C_REG_MIXER2][offset+0] = (temp >> 16) & 0xff; + shadow[TAS3001C_REG_MIXER2][offset+1] = (temp >> 8) & 0xff; + shadow[TAS3001C_REG_MIXER2][offset+2] = (temp >> 0) & 0xff; + rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER2); + /* tas3001c_fast_load(self, 0); */ + break; + case SOUND_MIXER_PCM: + /* tas3001c_fast_load(self, 1); */ + level = tas_mono_to_stereo(level); + temp = tas3001c_gain.mixer[level&0xff]; + shadow[TAS3001C_REG_MIXER1][offset+0] = (temp >> 16) & 0xff; + shadow[TAS3001C_REG_MIXER1][offset+1] = (temp >> 8) & 0xff; + shadow[TAS3001C_REG_MIXER1][offset+2] = (temp >> 0) & 0xff; + rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER1); + /* tas3001c_fast_load(self, 0); */ + break; + case SOUND_MIXER_TREBLE: + temp = tas3001c_gain.treble[level&0xff]; + shadow[TAS3001C_REG_TREBLE][0]=temp&0xff; + rc = tas3001c_sync_register(self,TAS3001C_REG_TREBLE); + break; + case SOUND_MIXER_BASS: + temp = tas3001c_gain.bass[level&0xff]; + shadow[TAS3001C_REG_BASS][0]=temp&0xff; + rc = tas3001c_sync_register(self,TAS3001C_REG_BASS); + break; + default: + rc = -1; + break; + } + if (rc < 0) + return rc; + self->super.mixer[mixer]=level; return 0; } -int -tumbler_set_bass(uint bass) +static int +tas3001c_leave_sleep(struct tas3001c_data_t *self) { - uint cur_bass_pers = bass; - char block; - struct tas_data_t *data; + unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - if (!tumbler_client) + if (!self) return -1; - data = (struct tas_data_t *) (tumbler_client->data); + /* Make sure something answers on the i2c bus */ + if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr, + WRITE_NORMAL|FORCE_WRITE) < 0) + return -1; + + tas3001c_fast_load(self, 1); + + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5); + + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5); - bass &= 0xff; - if (bass > TAS_SETTING_MAX) - bass = TAS_SETTING_MAX; - bass = ((bass * 72) / TAS_SETTING_MAX) << 0; - bass = tas_bass_table[bass]; - block = (bass >> 0) & 0xff; + tas3001c_fast_load(self, 0); - if (tumbler_set_register(TAS_SET_BASS, &block) < 0) { - printk("tas3001c: failed to set bass \n"); + (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); + (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); + (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); + (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); + (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); + + return 0; +} + +static int +tas3001c_enter_sleep(struct tas3001c_data_t *self) +{ + /* Stub for now, but I have the details on low-power mode */ + if (!self) return -1; - } - data->bass = cur_bass_pers; return 0; } -int -tumbler_set_treble(uint treble) +static int +tas3001c_sync_biquad( struct tas3001c_data_t *self, + u_int channel, + u_int filter) { - uint cur_treble_pers = treble; - char block; - struct tas_data_t *data; + enum tas3001c_reg_t reg; - if (!tumbler_client) - return -1; + if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || + filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; - data = (struct tas_data_t *) (tumbler_client->data); + reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; - treble &= 0xff; - if (treble > TAS_SETTING_MAX) - treble = TAS_SETTING_MAX; - treble = ((treble * 72) / TAS_SETTING_MAX) << 0; - treble = tas_treble_table[treble]; - block = (treble >> 0) & 0xff; + return tas3001c_sync_register(self,reg); +} + +static int +tas3001c_write_biquad_shadow( struct tas3001c_data_t *self, + u_int channel, + u_int filter, + const union tas_biquad_t *biquad) +{ + tas_shadow_t *shadow=self->super.shadow; + enum tas3001c_reg_t reg; + + if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || + filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; + + reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; + + SET_4_20(shadow[reg], 0,biquad->coeff.b0); + SET_4_20(shadow[reg], 3,biquad->coeff.b1); + SET_4_20(shadow[reg], 6,biquad->coeff.b2); + SET_4_20(shadow[reg], 9,biquad->coeff.a1); + SET_4_20(shadow[reg],12,biquad->coeff.a2); - if (tumbler_set_register(TAS_SET_TREBLE, &block) < 0) { - printk("tas3001c: failed to set treble \n"); - return -1; - } - data->treble = cur_treble_pers; return 0; } -int -tumbler_set_pcm_lvl(uint pcm_lvl) +static int +tas3001c_write_biquad( struct tas3001c_data_t *self, + u_int channel, + u_int filter, + const union tas_biquad_t *biquad) { - uint pcm_lvl_pers = pcm_lvl; - unsigned char block[3]; - struct tas_data_t *data; + int rc; - if (!tumbler_client) - return -1; + rc=tas3001c_write_biquad_shadow(self, channel, filter, biquad); + if (rc < 0) return rc; - data = (struct tas_data_t *) (tumbler_client->data); + return tas3001c_sync_biquad(self, channel, filter); +} - pcm_lvl &= 0xff; - if (pcm_lvl > TAS_SETTING_MAX) - pcm_lvl = TAS_SETTING_MAX; - pcm_lvl = ((pcm_lvl * 176) / TAS_SETTING_MAX) << 0; +static int +tas3001c_write_biquad_list( struct tas3001c_data_t *self, + u_int filter_count, + u_int flags, + struct tas_biquad_ctrl_t *biquads) +{ + int i; + int rc; - pcm_lvl = tas_input_table[pcm_lvl]; + if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1); - block[0] = (pcm_lvl >> 16) & 0xff; - block[1] = (pcm_lvl >> 8) & 0xff; - block[2] = (pcm_lvl >> 0) & 0xff; + for (i=0; ipcm_level = pcm_lvl_pers; - return 0; + return rc; } -int -tumbler_set_volume(uint left_vol, uint right_vol) +static int +tas3001c_read_biquad( struct tas3001c_data_t *self, + u_int channel, + u_int filter, + union tas_biquad_t *biquad) +{ + tas_shadow_t *shadow=self->super.shadow; + enum tas3001c_reg_t reg; + + if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || + filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; + + reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; + + biquad->coeff.b0=GET_4_20(shadow[reg], 0); + biquad->coeff.b1=GET_4_20(shadow[reg], 3); + biquad->coeff.b2=GET_4_20(shadow[reg], 6); + biquad->coeff.a1=GET_4_20(shadow[reg], 9); + biquad->coeff.a2=GET_4_20(shadow[reg],12); + + return 0; +} + +static int +tas3001c_eq_rw( struct tas3001c_data_t *self, + u_int cmd, + u_long arg) { - uint left_vol_pers = left_vol; - uint right_vol_pers = right_vol; - unsigned char block[6]; - struct tas_data_t *data; + int rc; + struct tas_biquad_ctrl_t biquad; - if (!tumbler_client) - return -1; + if (copy_from_user((void *)&biquad, (const void *)arg, sizeof(struct tas_biquad_ctrl_t))) { + return -EFAULT; + } - data = (struct tas_data_t *) (tumbler_client->data); + if (cmd & SIOC_IN) { + rc=tas3001c_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); + if (rc != 0) return rc; + } - left_vol &= 0xff; - if (left_vol > TAS_SETTING_MAX) - left_vol = TAS_SETTING_MAX; + if (cmd & SIOC_OUT) { + rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); + if (rc != 0) return rc; + + if (copy_to_user((void *)arg, (const void *)&biquad, sizeof(struct tas_biquad_ctrl_t))) { + return -EFAULT; + } - right_vol = (right_vol >> 8) & 0xff; - if (right_vol > TAS_SETTING_MAX) - right_vol = TAS_SETTING_MAX; + } + return 0; +} - left_vol = ((left_vol * 176) / TAS_SETTING_MAX) << 0; - right_vol = ((right_vol * 176) / TAS_SETTING_MAX) << 0; +static int +tas3001c_eq_list_rw( struct tas3001c_data_t *self, + u_int cmd, + u_long arg) +{ + int rc; + int filter_count; + int flags; + int i,j; + char sync_required[2][6]; + struct tas_biquad_ctrl_t biquad; + + memset(sync_required,0,sizeof(sync_required)); + + if (copy_from_user((void *)&filter_count, + (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t,filter_count), + sizeof(int))) { + return -EFAULT; + } - left_vol = tas_volume_table[left_vol]; - right_vol = tas_volume_table[right_vol]; + if (copy_from_user((void *)&flags, + (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t,flags), + sizeof(int))) { + return -EFAULT; + } - block[0] = (left_vol >> 16) & 0xff; - block[1] = (left_vol >> 8) & 0xff; - block[2] = (left_vol >> 0) & 0xff; + if (cmd & SIOC_IN) { + } - block[3] = (right_vol >> 16) & 0xff; - block[4] = (right_vol >> 8) & 0xff; - block[5] = (right_vol >> 0) & 0xff; + for (i=0; i < filter_count; i++) { + if (copy_from_user((void *)&biquad, + (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t, biquads[i]), + sizeof(struct tas_biquad_ctrl_t))) { + return -EFAULT; + } + + if (cmd & SIOC_IN) { + sync_required[biquad.channel][biquad.filter]=1; + rc=tas3001c_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); + if (rc != 0) return rc; + } + + if (cmd & SIOC_OUT) { + rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); + if (rc != 0) return rc; + + if (copy_to_user((void *)arg + offsetof(struct tas_biquad_ctrl_list_t, biquads[i]), + (const void *)&biquad, + sizeof(struct tas_biquad_ctrl_t))) { + return -EFAULT; + } + } + } - if (tumbler_set_register(TAS_SET_VOLUME, block) < 0) { - printk("tas3001c: failed to set volume \n"); - return -1; + if (cmd & SIOC_IN) { + if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1); + for (i=0; i<2; i++) { + for (j=0; j<6; j++) { + if (sync_required[i][j]) { + rc=tas3001c_sync_biquad(self, i, j); + if (rc < 0) return rc; + } + } + } + if (flags & TAS_BIQUAD_FAST_LOAD) { + tas3001c_fast_load(self,0); + /* now we need to set up the mixers again, + because leaving fast mode resets them. */ + (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); + (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); + (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); + (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); + (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); + } } - data->left_vol = left_vol_pers; - data->right_vol = right_vol_pers; return 0; } -int -tumbler_leave_sleep(void) -{ - /* Stub for now, but I have the details on low-power mode */ - if (!tumbler_client) - return -1; +static int +tas3001c_update_drce( struct tas3001c_data_t *self, + int flags, + struct tas_drce_t *drce) +{ + tas_shadow_t *shadow; + shadow=self->super.shadow; + + shadow[TAS3001C_REG_DRC][1] = 0xc1; + + if (flags & TAS_DRCE_THRESHOLD) { + self->drce_state.threshold=quantize_db(drce->threshold); + shadow[TAS3001C_REG_DRC][2] = db_to_regval(self->drce_state.threshold); + } - return 0; + if (flags & TAS_DRCE_ENABLE) { + self->drce_state.enable = drce->enable; + } + + if (!self->drce_state.enable) { + shadow[TAS3001C_REG_DRC][0] = 0xf0; + } + +#ifdef DEBUG_DRCE + printk("DRCE IOCTL: set [ ENABLE:%x THRESH:%x\n", + self->drce_state.enable, + self->drce_state.threshold); + + printk("DRCE IOCTL: reg [ %02x %02x ]\n", + (unsigned char)shadow[TAS3001C_REG_DRC][0], + (unsigned char)shadow[TAS3001C_REG_DRC][1]); +#endif + + return tas3001c_sync_register(self, TAS3001C_REG_DRC); } -int -tumbler_enter_sleep(void) +static int +tas3001c_drce_rw( struct tas3001c_data_t *self, + u_int cmd, + u_long arg) { - /* Stub for now, but I have the details on low-power mode */ - if (!tumbler_client) - return -1; + int rc; + struct tas_drce_ctrl_t drce_ctrl; + + if (copy_from_user((void *)&drce_ctrl, + (const void *)arg, + sizeof(struct tas_drce_ctrl_t))) { + return -EFAULT; + } + +#ifdef DEBUG_DRCE + printk("DRCE IOCTL: input [ FLAGS:%x ENABLE:%x THRESH:%x\n", + drce_ctrl.flags, + drce_ctrl.data.enable, + drce_ctrl.data.threshold); +#endif + + if (cmd & SIOC_IN) { + rc = tas3001c_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); + if (rc < 0) + return rc; + } + + if (cmd & SIOC_OUT) { + if (drce_ctrl.flags & TAS_DRCE_ENABLE) + drce_ctrl.data.enable = self->drce_state.enable; + + if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) + drce_ctrl.data.threshold = self->drce_state.threshold; + + if (copy_to_user((void *)arg, + (const void *)&drce_ctrl, + sizeof(struct tas_drce_ctrl_t))) { + return -EFAULT; + } + } return 0; } -static int -tas_attach_adapter(struct i2c_adapter *adapter) +static void +tas3001c_update_device_parameters(struct tas3001c_data_t *self) { - if (!strncmp(adapter->name, "mac-io", 6)) - tas_detect_client(adapter, tas_i2c_address); + int i,j; - return 0; + if (!self) return; + + if (self->output_id == TAS_OUTPUT_HEADPHONES) { + tas3001c_fast_load(self, 1); + + for (i=0; idevice_id == self->device_id && + (eq->output_id == 0 || eq->output_id == self->output_id) && + (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { + + tas3001c_update_drce(self, TAS_DRCE_ALL, eq->drce); + tas3001c_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); + + break; + } + } } -static int -tas_init_client(struct i2c_client * new_client) +static void +tas3001c_device_change_handler(void *self) { - /* Make sure something answers on the i2c bus - */ + if (!self) return; - if (i2c_smbus_write_byte_data(new_client, 1, (1<<6)+(2<<4)+(2<<2)+0) < 0) - return -1; + tas3001c_update_device_parameters((struct tas3001c_data_t *)self); +} + +static struct tq_struct device_change_task; - tumbler_client = new_client; +static int +tas3001c_output_device_change( struct tas3001c_data_t *self, + int device_id, + int output_id, + int speaker_id) +{ + self->device_id=device_id; + self->output_id=output_id; + self->speaker_id=speaker_id; - tumbler_set_volume(VOL_DEFAULT, VOL_DEFAULT); - tumbler_set_pcm_lvl(INPUT_DEFAULT); - tumbler_set_bass(BASS_DEFAULT); - tumbler_set_treble(TREBLE_DEFAULT); + schedule_task(&device_change_task); return 0; } static int -tas_detect_client(struct i2c_adapter *adapter, int address) -{ - int rc = 0; - struct i2c_client *new_client; - struct tas_data_t *data; - const char *client_name = "tas 3001c Digital Equalizer"; - - new_client = kmalloc( - sizeof(struct i2c_client) + sizeof(struct tas_data_t), - GFP_KERNEL); - if (!new_client) { - rc = -ENOMEM; - goto bail; - } +tas3001c_device_ioctl( struct tas3001c_data_t *self, + u_int cmd, + u_long arg) +{ + switch (cmd) { + case TAS_READ_EQ: + case TAS_WRITE_EQ: + return tas3001c_eq_rw(self, cmd, arg); + + case TAS_READ_EQ_LIST: + case TAS_WRITE_EQ_LIST: + return tas3001c_eq_list_rw(self, cmd, arg); - /* This is tricky, but it will set the data to the right value. */ - new_client->data = new_client + 1; - data = (struct tas_data_t *) (new_client->data); + case TAS_READ_EQ_FILTER_COUNT: + put_user(TAS3001C_BIQUAD_FILTER_COUNT, (uint *)(arg)); + return 0; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &tas_driver; - new_client->flags = 0; + case TAS_READ_EQ_CHANNEL_COUNT: + put_user(TAS3001C_BIQUAD_CHANNEL_COUNT, (uint *)(arg)); + return 0; - strcpy(new_client->name,client_name); + case TAS_READ_DRCE: + case TAS_WRITE_DRCE: + return tas3001c_drce_rw(self, cmd, arg); - new_client->id = tas_id++; /* Automatically unique */ + case TAS_READ_DRCE_CAPS: + put_user(TAS_DRCE_ENABLE | TAS_DRCE_THRESHOLD, (uint *)(arg)); + return 0; - if (tas_init_client(new_client)) { - rc = -ENODEV; - goto bail; + case TAS_READ_DRCE_MIN: + case TAS_READ_DRCE_MAX: { + struct tas_drce_ctrl_t drce_ctrl; + + if (copy_from_user((void *)&drce_ctrl, + (const void *)arg, + sizeof(struct tas_drce_ctrl_t))) { + return -EFAULT; + } + + if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { + if (cmd == TAS_READ_DRCE_MIN) { + drce_ctrl.data.threshold=-36<<8; + } else { + drce_ctrl.data.threshold=-6<<8; + } + } + + if (copy_to_user((void *)arg, + (const void *)&drce_ctrl, + sizeof(struct tas_drce_ctrl_t))) { + return -EFAULT; + } } - - /* Tell the i2c layer a new client has arrived */ - if (i2c_attach_client(new_client)) { - rc = -ENODEV; - goto bail; } -bail: - if (rc && new_client) - kfree(new_client); - return rc; + + return -EINVAL; } static int -tas_detach_client(struct i2c_client *client) +tas3001c_init_mixer(struct tas3001c_data_t *self) { - if (client == tumbler_client) - tumbler_client = NULL; + unsigned char mcr = (1<<6)+(2<<4)+(2<<2); + + /* Make sure something answers on the i2c bus */ + if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr, + WRITE_NORMAL|FORCE_WRITE) < 0) + return -1; + + tas3001c_fast_load(self, 1); + + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5); + (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD6); + + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5); + (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD6); + + tas3001c_fast_load(self, 0); + + tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); + tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); + tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - i2c_detach_client(client); - kfree(client); + tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); + tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); return 0; } -int -tas_cleanup(void) +static int +tas3001c_uninit_mixer(struct tas3001c_data_t *self) { - if (!tas_initialized) - return -ENODEV; - i2c_del_driver(&tas_driver); - tas_initialized = 0; + tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); + tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, 0); + tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); + + tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, 0); + tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); return 0; } -int -tas_init(void) +static int +tas3001c_init(struct i2c_client *client) { - int rc; - u32* paddr; - - if (tas_initialized) - return 0; + struct tas3001c_data_t *self; + int i,j; - tas_node = find_devices("deq"); - if (tas_node == NULL) - return -ENODEV; - - printk(KERN_INFO "tas3001c driver version %s (%s)\n",TAS_VERSION,TAS_DATE); - paddr = (u32 *)get_property(tas_node, "i2c-address", NULL); - if (paddr) { - tas_i2c_address = (*paddr) >> 1; - printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", - tas_i2c_address); - } else - printk(KERN_INFO "using i2c address: 0x%x (default)\n", tas_i2c_address); - - if ((rc = i2c_add_driver(&tas_driver))) { - printk("tas3001c: Driver registration failed, module not inserted.\n"); - tas_cleanup(); - return rc; + self = kmalloc(sizeof(struct tas3001c_data_t) + + TAS3001C_REG_MAX * sizeof(tas_shadow_t), + GFP_KERNEL); + if (self == NULL) + return -ENOMEM; + client->data = (void *)self; + self->super.client = client; + self->super.shadow = (tas_shadow_t *)(self+1); + + self->output_id=TAS_OUTPUT_HEADPHONES; + self->device_id=0; + self->speaker_id=0; + + for (i=0; i */ -#ifndef _tas3001c_h_ -#define _tas3001c_h_ +#ifndef _TAS3001C_H_ +#define _TAS3001C_H_ -/* - * Macros that correspond to the registers that we write to - * when setting the various values. - */ -#define TAS_DRC 0x02 /* DRC */ -#define TAS_VOLUME 0x04 /* Volume */ -#define TAS_TREBLE 0x05 /* Treble */ -#define TAS_BASS 0x06 /* Bass */ -#define TAS_MIXER1 0x07 /* PCM line */ -#define TAS_MIXER2 0x08 /* Input (Unk) */ - -/* - * Macros that define various arguments to tas_set_register() - */ -#define TAS_SET_DRC TAS_DRC, 2 -#define TAS_SET_VOLUME TAS_VOLUME, 6 -#define TAS_SET_TREBLE TAS_TREBLE, 1 -#define TAS_SET_BASS TAS_BASS, 1 -#define TAS_SET_MIXER1 TAS_MIXER1, 3 -#define TAS_SET_MIXER2 TAS_MIXER2, 3 +#include +#include "tas_common.h" +#include "tas_eq_prefs.h" /* - * tas_volume_table contains lookup values for the volume settings - * for tumbler. This is straight from the programming manual - * for the chip, however, it's zero-sourced for your shopping pleasure - * (meaning, you'll have to compute the difference between the desired - * dB and the index value of the proper setting. - * - * This table should've been replaced by the formula: - * dB = 20 log(x) - * but, since there's no log() or supporting functions like exp(), - * my implementation of the above won't work. Yeah, I could do it - * the hard way, but this table is just easier :-) - * - * For reference, -70 dB = tas_volume_table[0] + * Macros that correspond to the registers that we write to + * when setting the various values. */ -static unsigned int tas_volume_table[] = { - 0x00000015, 0x00000016, 0x00000017, /* -70.0, -69.5, -69.0 */ - 0x00000019, 0x0000001a, 0x0000001c, /* -68.5, -68.0, -67.5 */ - 0x0000001d, 0x0000001f, 0x00000021, /* -67.0, -66.5, -66.0 */ - 0x00000023, 0x00000025, 0x00000027, /* -65.5, -65.0, -64.5 */ - 0x00000029, 0x0000002c, 0x0000002e, /* -64.0, -63.5, -63.0 */ - 0x00000031, 0x00000034, 0x00000037, /* -62.5, -62.0, -61.5 */ - 0x0000003a, 0x0000003e, 0x00000042, /* -61.0, -60.5, -60.0 */ - 0x00000045, 0x0000004a, 0x0000004e, /* -59.5, -59.0, -58.5 */ - 0x00000053, 0x00000057, 0x0000005d, /* -58.0, -57.5, -57.0 */ - 0x00000062, 0x00000068, 0x0000006e, /* -56.5, -56.0, -55.5 */ - 0x00000075, 0x0000007b, 0x00000083, /* -55.0, -54.5, -54.0 */ - 0x0000008b, 0x00000093, 0x0000009b, /* -53.5, -53.0, -52.5 */ - 0x000000a5, 0x000000ae, 0x000000b9, /* -52.0, -51.5, -51.0 */ - 0x000000c4, 0x000000cf, 0x000000dc, /* -50.5, -50.0, -49.5 */ - 0x000000e9, 0x000000f6, 0x00000105, /* -49.0, -48.5, -48.0 */ - 0x00000114, 0x00000125, 0x00000136, /* -47.5, -47.0, -46.5 */ - 0x00000148, 0x0000015c, 0x00000171, /* -46.0, -45.5, -45.0 */ - 0x00000186, 0x0000019e, 0x000001b6, /* -44.5, -44.0, -43.5 */ - 0x000001d0, 0x000001eb, 0x00000209, /* -43.0, -42.5, -42.0 */ - 0x00000227, 0x00000248, 0x0000026b, /* -41.5, -41.0, -40.5 */ - 0x0000028f, 0x000002b6, 0x000002df, /* -40.0, -39.5, -39.0 */ - 0x0000030b, 0x00000339, 0x0000036a, /* -38.5, -38.0, -37.5 */ - 0x0000039e, 0x000003d5, 0x0000040f, /* -37.0, -36.5, -36.0 */ - 0x0000044c, 0x0000048d, 0x000004d2, /* -35.5, -35.0, -34.5 */ - 0x0000051c, 0x00000569, 0x000005bb, /* -34.0, -33.5, -33.0 */ - 0x00000612, 0x0000066e, 0x000006d0, /* -32.5, -32.0, -31.5 */ - 0x00000737, 0x000007a5, 0x00000818, /* -31.0, -30.5, -30.0 */ - 0x00000893, 0x00000915, 0x0000099f, /* -29.5, -29.0, -28.5 */ - 0x00000a31, 0x00000acc, 0x00000b6f, /* -28.0, -27.5, -27.0 */ - 0x00000c1d, 0x00000cd5, 0x00000d97, /* -26.5, -26.0, -25.5 */ - 0x00000e65, 0x00000f40, 0x00001027, /* -25.0, -24.5, -24.0 */ - 0x0000111c, 0x00001220, 0x00001333, /* -23.5, -23.0, -22.5 */ - 0x00001456, 0x0000158a, 0x000016d1, /* -22.0, -21.5, -21.0 */ - 0x0000182b, 0x0000199a, 0x00001b1e, /* -20.5, -20.0, -19.5 */ - 0x00001cb9, 0x00001e6d, 0x0000203a, /* -19.0, -18.5, -18.0 */ - 0x00002223, 0x00002429, 0x0000264e, /* -17.5, -17.0, -16.5 */ - 0x00002893, 0x00002afa, 0x00002d86, /* -16.0, -15.5, -15.0 */ - 0x00003039, 0x00003314, 0x0000361b, /* -14.5, -14.0, -13.5 */ - 0x00003950, 0x00003cb5, 0x0000404e, /* -13.0, -12.5, -12.0 */ - 0x0000441d, 0x00004827, 0x00004c6d, /* -11.5, -11.0, -10.5 */ - 0x000050f4, 0x000055c0, 0x00005ad5, /* -10.0, -09.5, -09.0 */ - 0x00006037, 0x000065ea, 0x00006bf4, /* -08.5, -08.0, -07.5 */ - 0x0000725a, 0x00007920, 0x0000804e, /* -07.0, -06.5, -06.0 */ - 0x000087e8, 0x00008ff6, 0x0000987d, /* -05.5, -05.0, -04.5 */ - 0x0000a186, 0x0000ab19, 0x0000b53c, /* -04.0, -03.5, -03.0 */ - 0x0000bff9, 0x0000cb59, 0x0000d766, /* -02.5, -02.0, -01.5 */ - 0x0000e429, 0x0000f1ae, 0x00010000, /* -01.0, -00.5, 00.0 */ - 0x00010f2b, 0x00011f3d, 0x00013042, /* +00.5, +01.0, +01.5 */ - 0x00014249, 0x00015562, 0x0001699c, /* +02.0, +02.5, +03.0 */ - 0x00017f09, 0x000195bc, 0x0001adc6, /* +03.5, +04.0, +04.5 */ - 0x0001c73d, 0x0001e237, 0x0001feca, /* +05.0, +05.5, +06.0 */ - 0x00021d0e, 0x00023d1d, 0x00025f12, /* +06.5, +07.0, +07.5 */ - 0x0002830b, 0x0002a925, 0x0002d182, /* +08.0, +08.5, +09.0 */ - 0x0002fc42, 0x0003298b, 0x00035983, /* +09.5, +10.0, +10.5 */ - 0x00038c53, 0x0003c225, 0x0003fb28, /* +11.0, +11.5, +12.0 */ - 0x0004378b, 0x00047783, 0x0004bb44, /* +12.5, +13.0, +13.5 */ - 0x0005030a, 0x00054f10, 0x00059f98, /* +14.0, +14.5, +15.0 */ - 0x0005f4e5, 0x00064f40, 0x0006aef6, /* +15.5, +16.0, +16.5 */ - 0x00071457, 0x00077fbb, 0x0007f17b /* +17.0, +17.5, +18.0 */ -}; +#define TAS3001C_VERSION "0.3" +#define TAS3001C_DATE "20011214" -/* tas_treble_table[] is a lookup table that holds the values to drop into - * the treble setting register on the TAS. Again, there is a formula for - * this one, but we use this instead due to lack of real math functions - * in the kernel. - */ -static char tas_treble_table[] = { - 0x96, 0x95, 0x94, /* -18.0, -17.5, -17.0 */ - 0x93, 0x92, 0x91, /* -16.5, -16.0, -15.5 */ - 0x90, 0x8f, 0x8e, /* -15.0, -14.5, -14.0 */ - 0x8d, 0x8c, 0x8b, /* -13.5, -13.0, -12.5 */ - 0x8a, 0x89, 0x88, /* -12.0, -11.5, -11.0 */ - 0x87, 0x86, 0x85, /* -10.5, -10.0, -09.5 */ - 0x84, 0x83, 0x82, /* -09.0, -08.5, -08.0 */ - 0x81, 0x80, 0x7f, /* -07.5, -07.0, -06.5 */ - 0x7e, 0x7d, 0x7c, /* -06.0, -05.5, -05.0 */ - 0x7b, 0x7a, 0x79, /* -04.5, -04.0, -03.5 */ - 0x78, 0x77, 0x76, /* -03.0, -02.5, -02.0 */ - 0x75, 0x74, 0x73, /* -01.5, -01.0, -00.5 */ - 0x72, 0x71, 0x70, /* 00.0, +00.5, +01.0 */ - 0x6e, 0x6d, 0x6c, /* +01.5, +02.0, +02.5 */ - 0x6b, 0x69, 0x68, /* +03.0, +03.5, +04.0 */ - 0x66, 0x65, 0x63, /* +04.5, +05.0, +05.5 */ - 0x62, 0x60, 0x5e, /* +06.0, +06.5, +07.0 */ - 0x5c, 0x5a, 0x57, /* +07.5, +08.0, +08.5 */ - 0x55, 0x52, 0x4f, /* +09.0, +09.5, +10.0 */ - 0x4c, 0x49, 0x45, /* +10.5, +11.0, +11.5 */ - 0x42, 0x3e, 0x3a, /* +12.0, +12.5, +13.0 */ - 0x36, 0x32, 0x2d, /* +13.5, +14.0, +14.5 */ - 0x28, 0x22, 0x1c, /* +15.0, +15.5, +16.0 */ - 0x16, 0x10, 0x09, /* +16.5, +17.0, +17.5 */ - 0x01 /* +18.0 */ -}; +#define I2C_DRIVERNAME_TAS3001C "TAS3001c driver V " TAS3001C_VERSION +#define I2C_DRIVERID_TAS3001C (I2C_DRIVERID_TAS_BASE+0) -/* tas_bass_table[] is a lookup table that holds the values to drop into - * the bass setting register on the TAS. Again, there is a formula for - * this one, but we use this instead due to lack of real math functions - * in the kernel. - */ -static char tas_bass_table[] = { - 0x86, 0x82, 0x7f, /* -18.0, -17.5, -17.0 */ - 0x7d, 0x7a, 0x78, /* -16.5, -16.0, -15.5 */ - 0x76, 0x74, 0x72, /* -15.0, -14.5, -14.0 */ - 0x70, 0x6e, 0x6d, /* -13.5, -13.0, -12.5 */ - 0x6b, 0x69, 0x66, /* -12.0, -11.5, -11.0 */ - 0x64, 0x61, 0x5f, /* -10.5, -10.0, -09.5 */ - 0x5d, 0x5c, 0x5a, /* -09.0, -08.5, -08.0 */ - 0x59, 0x58, 0x56, /* -07.5, -07.0, -06.5 */ - 0x55, 0x54, 0x53, /* -06.0, -05.5, -05.0 */ - 0x51, 0x4f, 0x4d, /* -04.5, -04.0, -03.5 */ - 0x4b, 0x49, 0x46, /* -03.0, -02.5, -02.0 */ - 0x44, 0x42, 0x40, /* -01.5, -01.0, -00.5 */ - 0x3e, 0x3c, 0x3b, /* 00.0, +00.5, +01.0 */ - 0x39, 0x38, 0x36, /* +01.5, +02.0, +02.5 */ - 0x35, 0x33, 0x31, /* +03.0, +03.5, +04.0 */ - 0x30, 0x2e, 0x2c, /* +04.5, +05.0, +05.5 */ - 0x2b, 0x29, 0x28, /* +06.0, +06.5, +07.0 */ - 0x26, 0x25, 0x23, /* +07.5, +08.0, +08.5 */ - 0x21, 0x1f, 0x1c, /* +09.0, +09.5, +10.0 */ - 0x19, 0x18, 0x17, /* +10.5, +11.0, +11.5 */ - 0x16, 0x14, 0x13, /* +12.0, +12.5, +13.0 */ - 0x12, 0x10, 0x0f, /* +13.5, +14.0, +14.5 */ - 0x0d, 0x0b, 0x0a, /* +15.0, +15.5, +16.0 */ - 0x08, 0x06, 0x03, /* +16.5, +17.0, +17.5 */ - 0x01 /* +18.0 */ -}; +extern struct tas_driver_hooks_t tas3001c_hooks; +extern struct tas_gain_t tas3001c_gain; +extern struct tas_eq_pref_t *tas3001c_eq_prefs[]; + +enum tas3001c_reg_t { + TAS3001C_REG_MCR = 0x01, + TAS3001C_REG_DRC = 0x02, + + TAS3001C_REG_VOLUME = 0x04, + TAS3001C_REG_TREBLE = 0x05, + TAS3001C_REG_BASS = 0x06, + TAS3001C_REG_MIXER1 = 0x07, + TAS3001C_REG_MIXER2 = 0x08, + + TAS3001C_REG_LEFT_BIQUAD0 = 0x0a, + TAS3001C_REG_LEFT_BIQUAD1 = 0x0b, + TAS3001C_REG_LEFT_BIQUAD2 = 0x0c, + TAS3001C_REG_LEFT_BIQUAD3 = 0x0d, + TAS3001C_REG_LEFT_BIQUAD4 = 0x0e, + TAS3001C_REG_LEFT_BIQUAD5 = 0x0f, + TAS3001C_REG_LEFT_BIQUAD6 = 0x10, + + TAS3001C_REG_RIGHT_BIQUAD0 = 0x13, + TAS3001C_REG_RIGHT_BIQUAD1 = 0x14, + TAS3001C_REG_RIGHT_BIQUAD2 = 0x15, + TAS3001C_REG_RIGHT_BIQUAD3 = 0x16, + TAS3001C_REG_RIGHT_BIQUAD4 = 0x17, + TAS3001C_REG_RIGHT_BIQUAD5 = 0x18, + TAS3001C_REG_RIGHT_BIQUAD6 = 0x19, -/* tas_input_table[] is a lookup table that holds the values to drop into - * the setting registers on the TAS for "mixers 1 & 2" (which are the input - * lines). Again, there is a formula for these, but we use this instead - * due to lack of real math functions in the kernel. - */ -static unsigned int tas_input_table[] = { - 0x00014b, 0x00015f, 0x000174, /* -70.0, -69.5, -69.0 */ - 0x00018a, 0x0001a1, 0x0001ba, /* -68.5, -68.0, -67.5 */ - 0x0001d4, 0x0001f0, 0x00020d, /* -67.0, -66.5, -66.0 */ - 0x00022c, 0x00024d, 0x000270, /* -65.5, -65.0, -64.5 */ - 0x000295, 0x0002bc, 0x0002e6, /* -64.0, -63.5, -63.0 */ - 0x000312, 0x000340, 0x000372, /* -62.5, -62.0, -61.5 */ - 0x0003a6, 0x0003dd, 0x000418, /* -61.0, -60.5, -60.0 */ - 0x000456, 0x000498, 0x0004de, /* -59.5, -59.0, -58.5 */ - 0x000528, 0x000576, 0x0005c9, /* -58.0, -57.5, -57.0 */ - 0x000620, 0x00067d, 0x0006e0, /* -56.5, -56.0, -55.5 */ - 0x000748, 0x0007b7, 0x00082c, /* -55.0, -54.5, -54.0 */ - 0x0008a8, 0x00092b, 0x0009b6, /* -53.5, -53.0, -52.5 */ - 0x000a49, 0x000ae5, 0x000b8b, /* -52.0, -51.5, -51.0 */ - 0x000c3a, 0x000cf3, 0x000db8, /* -50.5, -50.0, -49.5 */ - 0x000e88, 0x000f64, 0x00104e, /* -49.0, -48.5, -48.0 */ - 0x001145, 0x00124b, 0x001361, /* -47.5, -47.0, -46.5 */ - 0x001487, 0x0015be, 0x001708, /* -46.0, -45.5, -45.0 */ - 0x001865, 0x0019d8, 0x001b60, /* -44.5, -44.0, -43.5 */ - 0x001cff, 0x001eb7, 0x002089, /* -43.0, -42.5, -42.0 */ - 0x002276, 0x002481, 0x0026ab, /* -41.5, -41.0, -40.5 */ - 0x0028f5, 0x002b63, 0x002df5, /* -40.0, -39.5, -39.0 */ - 0x0030ae, 0x003390, 0x00369e, /* -38.5, -38.0, -37.5 */ - 0x0039db, 0x003d49, 0x0040ea, /* -37.0, -36.5, -36.0 */ - 0x0044c3, 0x0048d6, 0x004d27, /* -35.5, -35.0, -34.5 */ - 0x0051b9, 0x005691, 0x005bb2, /* -34.0, -33.5, -33.0 */ - 0x006121, 0x0066e3, 0x006cfb, /* -32.5, -32.0, -31.5 */ - 0x007370, 0x007a48, 0x008186, /* -31.0, -30.5, -30.0 */ - 0x008933, 0x009154, 0x0099f1, /* -29.5, -29.0, -28.5 */ - 0x00a310, 0x00acba, 0x00b6f6, /* -28.0, -27.5, -27.0 */ - 0x00c1cd, 0x00cd49, 0x00d973, /* -26.5, -26.0, -25.5 */ - 0x00e655, 0x00f3fb, 0x010270, /* -25.0, -24.5, -24.0 */ - 0x0111c0, 0x0121f9, 0x013328, /* -23.5, -23.0, -22.5 */ - 0x01455b, 0x0158a2, 0x016d0e, /* -22.0, -21.5, -21.0 */ - 0x0182af, 0x019999, 0x01b1de, /* -20.5, -20.0, -19.5 */ - 0x01cb94, 0x01e6cf, 0x0203a7, /* -19.0, -18.5, -18.0 */ - 0x022235, 0x024293, 0x0264db, /* -17.5, -17.0, -16.5 */ - 0x02892c, 0x02afa3, 0x02d862, /* -16.0, -15.5, -15.0 */ - 0x03038a, 0x033142, 0x0361af, /* -14.5, -14.0, -13.5 */ - 0x0394fa, 0x03cb50, 0x0404de, /* -13.0, -12.5, -12.0 */ - 0x0441d5, 0x048268, 0x04c6d0, /* -11.5, -11.0, -10.5 */ - 0x050f44, 0x055c04, 0x05ad50, /* -10.0, -09.5, -09.0 */ - 0x06036e, 0x065ea5, 0x06bf44, /* -08.5, -08.0, -07.5 */ - 0x07259d, 0x079207, 0x0804dc, /* -07.0, -06.5, -06.0 */ - 0x087e80, 0x08ff59, 0x0987d5, /* -05.5, -05.0, -04.5 */ - 0x0a1866, 0x0ab189, 0x0b53be, /* -04.0, -03.5, -03.0 */ - 0x0bff91, 0x0cb591, 0x0d765a, /* -02.5, -02.0, -01.5 */ - 0x0e4290, 0x0f1adf, 0x100000, /* -01.0, -00.5, 00.0 */ - 0x10f2b4, 0x11f3c9, 0x13041a, /* +00.5, +01.0, +01.5 */ - 0x14248e, 0x15561a, 0x1699c0, /* +02.0, +02.5, +03.0 */ - 0x17f094, 0x195bb8, 0x1adc61, /* +03.5, +04.0, +04.5 */ - 0x1c73d5, 0x1e236d, 0x1fec98, /* +05.0, +05.5, +06.0 */ - 0x21d0d9, 0x23d1cd, 0x25f125, /* +06.5, +07.0, +07.5 */ - 0x2830af, 0x2a9254, 0x2d1818, /* +08.0, +08.5, +09.0 */ - 0x2fc420, 0x3298b0, 0x35982f, /* +09.5, +10.0, +10.5 */ - 0x38c528, 0x3c224c, 0x3fb278, /* +11.0, +11.5, +12.0 */ - 0x437880, 0x477828, 0x4bb446, /* +12.5, +13.0, +13.5 */ - 0x5030a1, 0x54f106, 0x59f980, /* +14.0, +14.5, +15.0 */ - 0x5f4e52, 0x64f403, 0x6aef5d, /* +15.5, +16.0, +16.5 */ - 0x714575, 0x77fbaa, 0x7f17af /* +17.0, +17.5, +18.0 */ + TAS3001C_REG_MAX = 0x20 }; -#endif /* _tas3001c_h_ */ +#endif /* _TAS3001C_H_ */ diff -uNr linux-2.4.20/drivers/sound/dmasound/tas3001c_tables.c linux-2.4.20-ben6/drivers/sound/dmasound/tas3001c_tables.c --- linux-2.4.20/drivers/sound/dmasound/tas3001c_tables.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/tas3001c_tables.c 2003-02-16 20:21:33.000000000 +0100 @@ -0,0 +1,375 @@ +#include "tas_common.h" +#include "tas_eq_prefs.h" + +static struct tas_drce_t eqp_0e_2_1_drce = { + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -15.33 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_0e_2_1_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, + { channel: 0, filter: 1, data: { coeff: { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, + { channel: 0, filter: 5, data: { coeff: { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, + { channel: 1, filter: 1, data: { coeff: { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, + { channel: 1, filter: 5, data: { coeff: { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, +}; + +static struct tas_eq_pref_t eqp_0e_2_1 = { + sample_rate: 44100, + device_id: 0x0e, + output_id: TAS_OUTPUT_EXTERNAL_SPKR, + speaker_id: 0x01, + + drce: &eqp_0e_2_1_drce, + + filter_count: 12, + biquads: eqp_0e_2_1_biquads +}; + +/* ======================================================================== */ + +static struct tas_drce_t eqp_10_1_0_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -12.46 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_10_1_0_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } }, + { channel: 0, filter: 1, data: { coeff: { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } }, + { channel: 0, filter: 4, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, + { channel: 0, filter: 5, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } }, + { channel: 1, filter: 1, data: { coeff: { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } }, + { channel: 1, filter: 4, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, + { channel: 1, filter: 5, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, +}; + +static struct tas_eq_pref_t eqp_10_1_0 = { + sample_rate: 44100, + device_id: 0x10, + output_id: TAS_OUTPUT_INTERNAL_SPKR, + speaker_id: 0x00, + + drce: &eqp_10_1_0_drce, + + filter_count: 12, + biquads: eqp_10_1_0_biquads +}; + +/* ======================================================================== */ + +static struct tas_drce_t eqp_15_2_1_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -15.33 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_15_2_1_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, + { channel: 0, filter: 1, data: { coeff: { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, + { channel: 0, filter: 5, data: { coeff: { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, + { channel: 1, filter: 1, data: { coeff: { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, + { channel: 1, filter: 5, data: { coeff: { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, +}; + +static struct tas_eq_pref_t eqp_15_2_1 = { + sample_rate: 44100, + device_id: 0x15, + output_id: TAS_OUTPUT_EXTERNAL_SPKR, + speaker_id: 0x01, + + drce: &eqp_15_2_1_drce, + + filter_count: 12, + biquads: eqp_15_2_1_biquads +}; + +/* ======================================================================== */ + +static struct tas_drce_t eqp_15_1_0_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: 0.0 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_15_1_0_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } }, + { channel: 0, filter: 1, data: { coeff: { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } }, + { channel: 0, filter: 5, data: { coeff: { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } }, + { channel: 1, filter: 1, data: { coeff: { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } }, + { channel: 1, filter: 5, data: { coeff: { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } }, +}; + +static struct tas_eq_pref_t eqp_15_1_0 = { + sample_rate: 44100, + device_id: 0x15, + output_id: TAS_OUTPUT_INTERNAL_SPKR, + speaker_id: 0x00, + + drce: &eqp_15_1_0_drce, + + filter_count: 12, + biquads: eqp_15_1_0_biquads +}; + +/* ======================================================================== */ + +static struct tas_drce_t eqp_0f_2_1_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -15.33 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_0f_2_1_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, + { channel: 0, filter: 1, data: { coeff: { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, + { channel: 0, filter: 5, data: { coeff: { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, + { channel: 1, filter: 1, data: { coeff: { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, + { channel: 1, filter: 5, data: { coeff: { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, +}; + +static struct tas_eq_pref_t eqp_0f_2_1 = { + sample_rate: 44100, + device_id: 0x0f, + output_id: TAS_OUTPUT_EXTERNAL_SPKR, + speaker_id: 0x01, + + drce: &eqp_0f_2_1_drce, + + filter_count: 12, + biquads: eqp_0f_2_1_biquads +}; + +/* ======================================================================== */ + +static struct tas_drce_t eqp_0f_1_0_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -15.33 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_0f_1_0_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, + { channel: 0, filter: 1, data: { coeff: { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, + { channel: 0, filter: 5, data: { coeff: { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, + { channel: 1, filter: 1, data: { coeff: { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, + { channel: 1, filter: 5, data: { coeff: { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, +}; + +static struct tas_eq_pref_t eqp_0f_1_0 = { + sample_rate: 44100, + device_id: 0x0f, + output_id: TAS_OUTPUT_INTERNAL_SPKR, + speaker_id: 0x00, + + drce: &eqp_0f_1_0_drce, + + filter_count: 12, + biquads: eqp_0f_1_0_biquads +}; + +/* ======================================================================== */ + +static uint tas3001c_master_tab[]={ + 0x0, 0x75, 0x9c, 0xbb, + 0xdb, 0xfb, 0x11e, 0x143, + 0x16b, 0x196, 0x1c3, 0x1f5, + 0x229, 0x263, 0x29f, 0x2e1, + 0x328, 0x373, 0x3c5, 0x41b, + 0x478, 0x4dc, 0x547, 0x5b8, + 0x633, 0x6b5, 0x740, 0x7d5, + 0x873, 0x91c, 0x9d2, 0xa92, + 0xb5e, 0xc39, 0xd22, 0xe19, + 0xf20, 0x1037, 0x1161, 0x129e, + 0x13ed, 0x1551, 0x16ca, 0x185d, + 0x1a08, 0x1bcc, 0x1dac, 0x1fa7, + 0x21c1, 0x23fa, 0x2655, 0x28d6, + 0x2b7c, 0x2e4a, 0x3141, 0x3464, + 0x37b4, 0x3b35, 0x3ee9, 0x42d3, + 0x46f6, 0x4b53, 0x4ff0, 0x54ce, + 0x59f2, 0x5f5f, 0x6519, 0x6b24, + 0x7183, 0x783c, 0x7f53, 0x86cc, + 0x8ead, 0x96fa, 0x9fba, 0xa8f2, + 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa, + 0xdee8, 0xeb75, 0xf8aa, 0x1068e, + 0x1152a, 0x12487, 0x134ad, 0x145a5, + 0x1577b, 0x16a37, 0x17df5, 0x192bd, + 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1, + 0x20b55, 0x22727, 0x24456, 0x262f2, + 0x2830b +}; + +static uint tas3001c_mixer_tab[]={ + 0x0, 0x748, 0x9be, 0xbaf, + 0xda4, 0xfb1, 0x11de, 0x1431, + 0x16ad, 0x1959, 0x1c37, 0x1f4b, + 0x2298, 0x2628, 0x29fb, 0x2e12, + 0x327d, 0x3734, 0x3c47, 0x41b4, + 0x4787, 0x4dbe, 0x546d, 0x5b86, + 0x632e, 0x6b52, 0x7400, 0x7d54, + 0x873b, 0x91c6, 0x9d1a, 0xa920, + 0xb5e5, 0xc38c, 0xd21b, 0xe18f, + 0xf1f5, 0x1036a, 0x1160f, 0x129d6, + 0x13ed0, 0x1550c, 0x16ca0, 0x185c9, + 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75, + 0x21c0f, 0x23fa3, 0x26552, 0x28d64, + 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b, + 0x37b44, 0x3b353, 0x3ee94, 0x42d30, + 0x46f55, 0x4b533, 0x4fefc, 0x54ce5, + 0x59f25, 0x5f5f6, 0x65193, 0x6b23c, + 0x71835, 0x783c3, 0x7f52c, 0x86cc0, + 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a, + 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0, + 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4, + 0x1152a3, 0x12486a, 0x134ac8, 0x145a55, + 0x1577ac, 0x16a370, 0x17df51, 0x192bc2, + 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04, + 0x20b542, 0x227268, 0x244564, 0x262f26, + 0x2830af +}; + +static uint tas3001c_treble_tab[]={ + 0x96, 0x95, 0x95, 0x94, + 0x93, 0x92, 0x92, 0x91, + 0x90, 0x90, 0x8f, 0x8e, + 0x8d, 0x8d, 0x8c, 0x8b, + 0x8a, 0x8a, 0x89, 0x88, + 0x88, 0x87, 0x86, 0x85, + 0x85, 0x84, 0x83, 0x83, + 0x82, 0x81, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x7d, + 0x7c, 0x7b, 0x7b, 0x7a, + 0x79, 0x78, 0x78, 0x77, + 0x76, 0x76, 0x75, 0x74, + 0x73, 0x73, 0x72, 0x71, + 0x71, 0x70, 0x6e, 0x6d, + 0x6d, 0x6c, 0x6b, 0x6a, + 0x69, 0x68, 0x67, 0x66, + 0x65, 0x63, 0x62, 0x62, + 0x60, 0x5f, 0x5d, 0x5c, + 0x5a, 0x58, 0x56, 0x55, + 0x53, 0x51, 0x4f, 0x4c, + 0x4a, 0x48, 0x45, 0x43, + 0x40, 0x3d, 0x3a, 0x37, + 0x35, 0x32, 0x2e, 0x2a, + 0x27, 0x22, 0x1e, 0x1a, + 0x15, 0x11, 0xc, 0x7, + 0x1 +}; + +static uint tas3001c_bass_tab[]={ + 0x86, 0x83, 0x81, 0x7f, + 0x7d, 0x7b, 0x79, 0x78, + 0x76, 0x75, 0x74, 0x72, + 0x71, 0x6f, 0x6e, 0x6d, + 0x6c, 0x6b, 0x69, 0x67, + 0x65, 0x64, 0x61, 0x60, + 0x5e, 0x5d, 0x5c, 0x5b, + 0x5a, 0x59, 0x58, 0x57, + 0x56, 0x55, 0x55, 0x54, + 0x53, 0x52, 0x50, 0x4f, + 0x4d, 0x4c, 0x4b, 0x49, + 0x47, 0x45, 0x44, 0x42, + 0x41, 0x3f, 0x3e, 0x3d, + 0x3c, 0x3b, 0x39, 0x38, + 0x37, 0x36, 0x35, 0x34, + 0x33, 0x31, 0x30, 0x2f, + 0x2e, 0x2c, 0x2b, 0x2b, + 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x22, 0x21, + 0x20, 0x1e, 0x1c, 0x19, + 0x18, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, + 0x11, 0x10, 0xf, 0xe, + 0xd, 0xb, 0xa, 0x9, + 0x8, 0x6, 0x4, 0x2, + 0x1 +}; + +struct tas_gain_t tas3001c_gain = { + master: tas3001c_master_tab, + treble: tas3001c_treble_tab, + bass: tas3001c_bass_tab, + mixer: tas3001c_mixer_tab +}; + +struct tas_eq_pref_t *tas3001c_eq_prefs[]={ + &eqp_0e_2_1, + &eqp_10_1_0, + &eqp_15_2_1, + &eqp_15_1_0, + &eqp_0f_2_1, + &eqp_0f_1_0, + NULL +}; diff -uNr linux-2.4.20/drivers/sound/dmasound/tas3004.c linux-2.4.20-ben6/drivers/sound/dmasound/tas3004.c --- linux-2.4.20/drivers/sound/dmasound/tas3004.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/tas3004.c 2003-02-16 20:19:52.000000000 +0100 @@ -0,0 +1,1173 @@ +/* + * Driver for the i2c/i2s based TA3004 sound chip used + * on some Apple hardware. Also known as "snapper". + * + * Tobias Sargeant + * Based upon tas3001c.c by Christopher C. Chimelis : + * + * TODO: + * ----- + * * Enable control over input line 2 (is this connected?) + * * Implement sleep support (at least mute everything and + * * set gains to minimum during sleep) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dmasound.h" +#include "tas_common.h" +#include "tas3004.h" + +#include "tas_ioctl.h" + +/* #define DEBUG_DRCE */ + +#define TAS3004_BIQUAD_FILTER_COUNT 7 +#define TAS3004_BIQUAD_CHANNEL_COUNT 2 + +#define VOL_DEFAULT (100 * 4 / 5) +#define INPUT_DEFAULT (100 * 4 / 5) +#define BASS_DEFAULT (100 / 2) +#define TREBLE_DEFAULT (100 / 2) + +struct tas3004_data_t { + struct tas_data_t super; + int device_id; + int output_id; + int speaker_id; + struct tas_drce_t drce_state; +}; + +#define MAKE_TIME(sec,usec) (((sec)<<12) + (50000+(usec/10)*(1<<12))/100000) + +#define MAKE_RATIO(i,f) (((i)<<8) + ((500+(f)*(1<<8))/1000)) + + +static const union tas_biquad_t +tas3004_eq_unity={ + buf: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } +}; + + +static const struct tas_drce_t +tas3004_drce_min={ + enable: 1, + above: { val: MAKE_RATIO(16,0), expand:0 }, + below: { val: MAKE_RATIO(2,0), expand:0 }, + threshold: -0x59a0, + energy: MAKE_TIME(0, 1700), + attack: MAKE_TIME(0, 1700), + decay: MAKE_TIME(0, 1700) +}; + + +static const struct tas_drce_t +tas3004_drce_max={ + enable: 1, + above: { val: MAKE_RATIO(1,500), expand:1 }, + below: { val: MAKE_RATIO(2,0), expand:1 }, + threshold: -0x0, + energy: MAKE_TIME(2,400000), + attack: MAKE_TIME(2,400000), + decay: MAKE_TIME(2,400000) +}; + + +static const unsigned short time_constants[]={ + MAKE_TIME(0, 1700), + MAKE_TIME(0, 3500), + MAKE_TIME(0, 6700), + MAKE_TIME(0, 13000), + MAKE_TIME(0, 26000), + MAKE_TIME(0, 53000), + MAKE_TIME(0,106000), + MAKE_TIME(0,212000), + MAKE_TIME(0,425000), + MAKE_TIME(0,850000), + MAKE_TIME(1,700000), + MAKE_TIME(2,400000), +}; + +static const unsigned short above_threshold_compression_ratio[]={ + MAKE_RATIO( 1, 70), + MAKE_RATIO( 1,140), + MAKE_RATIO( 1,230), + MAKE_RATIO( 1,330), + MAKE_RATIO( 1,450), + MAKE_RATIO( 1,600), + MAKE_RATIO( 1,780), + MAKE_RATIO( 2, 0), + MAKE_RATIO( 2,290), + MAKE_RATIO( 2,670), + MAKE_RATIO( 3,200), + MAKE_RATIO( 4, 0), + MAKE_RATIO( 5,330), + MAKE_RATIO( 8, 0), + MAKE_RATIO(16, 0), +}; + +static const unsigned short above_threshold_expansion_ratio[]={ + MAKE_RATIO(1, 60), + MAKE_RATIO(1,130), + MAKE_RATIO(1,190), + MAKE_RATIO(1,250), + MAKE_RATIO(1,310), + MAKE_RATIO(1,380), + MAKE_RATIO(1,440), + MAKE_RATIO(1,500) +}; + +static const unsigned short below_threshold_compression_ratio[]={ + MAKE_RATIO(1, 70), + MAKE_RATIO(1,140), + MAKE_RATIO(1,230), + MAKE_RATIO(1,330), + MAKE_RATIO(1,450), + MAKE_RATIO(1,600), + MAKE_RATIO(1,780), + MAKE_RATIO(2, 0) +}; + +static const unsigned short below_threshold_expansion_ratio[]={ + MAKE_RATIO(1, 60), + MAKE_RATIO(1,130), + MAKE_RATIO(1,190), + MAKE_RATIO(1,250), + MAKE_RATIO(1,310), + MAKE_RATIO(1,380), + MAKE_RATIO(1,440), + MAKE_RATIO(1,500), + MAKE_RATIO(1,560), + MAKE_RATIO(1,630), + MAKE_RATIO(1,690), + MAKE_RATIO(1,750), + MAKE_RATIO(1,810), + MAKE_RATIO(1,880), + MAKE_RATIO(1,940), + MAKE_RATIO(2, 0) +}; + +static inline int +search( unsigned short val, + const unsigned short *arr, + const int arrsize) { + /* + * This could be a binary search, but for small tables, + * a linear search is likely to be faster + */ + + int i; + + for (i=0; i < arrsize; i++) + if (arr[i] >= val) + goto _1; + return arrsize-1; + _1: + if (i == 0) + return 0; + return (arr[i]-val < val-arr[i-1]) ? i : i-1; +} + +#define SEARCH(a, b) search(a, b, ARRAY_SIZE(b)) + +static inline int +time_index(unsigned short time) { + return SEARCH(time, time_constants); +} + + +static inline int +above_threshold_compression_index(unsigned short ratio) { + return SEARCH(ratio, above_threshold_compression_ratio); +} + + +static inline int +above_threshold_expansion_index(unsigned short ratio) { + return SEARCH(ratio, above_threshold_expansion_ratio); +} + + +static inline int +below_threshold_compression_index(unsigned short ratio) { + return SEARCH(ratio, below_threshold_compression_ratio); +} + + +static inline int +below_threshold_expansion_index(unsigned short ratio) { + return SEARCH(ratio, below_threshold_expansion_ratio); +} + + +static inline unsigned char db_to_regval(short db) { + int r=0; + + r=(db+0x59a0) / 0x60; + + if (r < 0x91) return 0x91; + if (r > 0xef) return 0xef; + return r; +} + + +static inline short quantize_db(short db) { + return db_to_regval(db) * 0x60 - 0x59a0; +} + + +static inline int +register_width(enum tas3004_reg_t r) +{ + switch(r) { + case TAS3004_REG_MCR: + case TAS3004_REG_TREBLE: + case TAS3004_REG_BASS: + case TAS3004_REG_ANALOG_CTRL: + case TAS3004_REG_TEST1: + case TAS3004_REG_TEST2: + case TAS3004_REG_MCR2: + return 1; + + case TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN: + case TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN: + return 3; + + case TAS3004_REG_DRC: + case TAS3004_REG_VOLUME: + return 6; + + case TAS3004_REG_LEFT_MIXER: + case TAS3004_REG_RIGHT_MIXER: + return 9; + + case TAS3004_REG_TEST: + return 10; + + case TAS3004_REG_LEFT_BIQUAD0: + case TAS3004_REG_LEFT_BIQUAD1: + case TAS3004_REG_LEFT_BIQUAD2: + case TAS3004_REG_LEFT_BIQUAD3: + case TAS3004_REG_LEFT_BIQUAD4: + case TAS3004_REG_LEFT_BIQUAD5: + case TAS3004_REG_LEFT_BIQUAD6: + + case TAS3004_REG_RIGHT_BIQUAD0: + case TAS3004_REG_RIGHT_BIQUAD1: + case TAS3004_REG_RIGHT_BIQUAD2: + case TAS3004_REG_RIGHT_BIQUAD3: + case TAS3004_REG_RIGHT_BIQUAD4: + case TAS3004_REG_RIGHT_BIQUAD5: + case TAS3004_REG_RIGHT_BIQUAD6: + + case TAS3004_REG_LEFT_LOUD_BIQUAD: + case TAS3004_REG_RIGHT_LOUD_BIQUAD: + return 15; + + default: + return 0; + } +} + + +static int +tas3004_write_register( struct tas3004_data_t *self, + enum tas3004_reg_t reg_num, + char *data, + uint write_mode) +{ + if (reg_num==TAS3004_REG_MCR || + reg_num==TAS3004_REG_BASS || + reg_num==TAS3004_REG_TREBLE) { + return tas_write_byte_register(&self->super, + (uint)reg_num, + *data, + write_mode); + } else { + return tas_write_register(&self->super, + (uint)reg_num, + register_width(reg_num), + data, + write_mode); + } +} + + +static int +tas3004_sync_register( struct tas3004_data_t *self, + enum tas3004_reg_t reg_num) +{ + if (reg_num==TAS3004_REG_MCR || + reg_num==TAS3004_REG_BASS || + reg_num==TAS3004_REG_TREBLE) { + return tas_sync_byte_register(&self->super, + (uint)reg_num, + register_width(reg_num)); + } else { + return tas_sync_register(&self->super, + (uint)reg_num, + register_width(reg_num)); + } +} + + +static int +tas3004_read_register( struct tas3004_data_t *self, + enum tas3004_reg_t reg_num, + char *data, + uint write_mode) +{ + return tas_read_register(&self->super, + (uint)reg_num, + register_width(reg_num), + data); +} + + +static inline int +tas3004_fast_load(struct tas3004_data_t *self, int fast) +{ + if (fast) + self->super.shadow[TAS3004_REG_MCR][0] |= 0x80; + else + self->super.shadow[TAS3004_REG_MCR][0] &= 0x7f; + return tas3004_sync_register(self,TAS3004_REG_MCR); +} + + +static uint +tas3004_supported_mixers(struct tas3004_data_t *self) +{ + return SOUND_MASK_VOLUME | + SOUND_MASK_PCM | + SOUND_MASK_ALTPCM | + SOUND_MASK_IMIX | + SOUND_MASK_TREBLE | + SOUND_MASK_BASS; +} + + +static int +tas3004_mixer_is_stereo(struct tas3004_data_t *self, int mixer) +{ + switch(mixer) { + case SOUND_MIXER_VOLUME: + case SOUND_MIXER_PCM: + case SOUND_MIXER_ALTPCM: + case SOUND_MIXER_IMIX: + return 1; + default: + return 0; + } +} + + +static uint +tas3004_stereo_mixers(struct tas3004_data_t *self) +{ + uint r = tas3004_supported_mixers(self); + uint i; + + for (i=1; isuper.mixer[mixer]; + + return 0; +} + + +static int +tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level) +{ + int rc; + tas_shadow_t *shadow; + uint temp; + uint offset=0; + + if (!self) + return -1; + + shadow = self->super.shadow; + + if (!tas3004_mixer_is_stereo(self,mixer)) + level = tas_mono_to_stereo(level); + switch(mixer) { + case SOUND_MIXER_VOLUME: + temp = tas3004_gain.master[level&0xff]; + SET_4_20(shadow[TAS3004_REG_VOLUME], 0, temp); + temp = tas3004_gain.master[(level>>8)&0xff]; + SET_4_20(shadow[TAS3004_REG_VOLUME], 3, temp); + rc = tas3004_sync_register(self,TAS3004_REG_VOLUME); + break; + case SOUND_MIXER_IMIX: + offset += 3; + case SOUND_MIXER_ALTPCM: + offset += 3; + case SOUND_MIXER_PCM: + /* + * Don't load these in fast mode. The documentation + * says it can be done in either mode, but testing it + * shows that fast mode produces ugly clicking. + */ + /* tas3004_fast_load(self,1); */ + temp = tas3004_gain.mixer[level&0xff]; + SET_4_20(shadow[TAS3004_REG_LEFT_MIXER], offset, temp); + temp = tas3004_gain.mixer[(level>>8)&0xff]; + SET_4_20(shadow[TAS3004_REG_RIGHT_MIXER], offset, temp); + rc = tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); + if (rc == 0) + rc=tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); + /* tas3004_fast_load(self,0); */ + break; + case SOUND_MIXER_TREBLE: + temp = tas3004_gain.treble[level&0xff]; + shadow[TAS3004_REG_TREBLE][0]=temp&0xff; + rc = tas3004_sync_register(self,TAS3004_REG_TREBLE); + break; + case SOUND_MIXER_BASS: + temp = tas3004_gain.bass[level&0xff]; + shadow[TAS3004_REG_BASS][0]=temp&0xff; + rc = tas3004_sync_register(self,TAS3004_REG_BASS); + break; + default: + rc = -1; + break; + } + if (rc < 0) + return rc; + self->super.mixer[mixer] = level; + + return 0; +} + + +static int +tas3004_leave_sleep(struct tas3004_data_t *self) +{ + unsigned char mcr = (1<<6)+(2<<4)+(2<<2); + + if (!self) + return -1; + + /* Make sure something answers on the i2c bus */ + if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, + WRITE_NORMAL | FORCE_WRITE) < 0) + return -1; + + tas3004_fast_load(self, 1); + + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); + + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); + + tas3004_fast_load(self, 0); + + (void)tas3004_sync_register(self,TAS3004_REG_VOLUME); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); + (void)tas3004_sync_register(self,TAS3004_REG_TREBLE); + (void)tas3004_sync_register(self,TAS3004_REG_BASS); + + return 0; +} + + +static int +tas3004_enter_sleep(struct tas3004_data_t *self) +{ + if (!self) + return -1; + return 0; +} + + +static int +tas3004_sync_biquad( struct tas3004_data_t *self, + u_int channel, + u_int filter) +{ + enum tas3004_reg_t reg; + + if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || + filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; + + reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; + + return tas3004_sync_register(self,reg); +} + + +static int +tas3004_write_biquad_shadow( struct tas3004_data_t *self, + u_int channel, + u_int filter, + const union tas_biquad_t *biquad) +{ + tas_shadow_t *shadow=self->super.shadow; + enum tas3004_reg_t reg; + + if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || + filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; + + reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; + + SET_4_20(shadow[reg], 0,biquad->coeff.b0); + SET_4_20(shadow[reg], 3,biquad->coeff.b1); + SET_4_20(shadow[reg], 6,biquad->coeff.b2); + SET_4_20(shadow[reg], 9,biquad->coeff.a1); + SET_4_20(shadow[reg],12,biquad->coeff.a2); + + return 0; +} + + +static int +tas3004_write_biquad( struct tas3004_data_t *self, + u_int channel, + u_int filter, + const union tas_biquad_t *biquad) +{ + int rc; + + rc=tas3004_write_biquad_shadow(self, channel, filter, biquad); + if (rc < 0) return rc; + + return tas3004_sync_biquad(self, channel, filter); +} + + +static int +tas3004_write_biquad_list( struct tas3004_data_t *self, + u_int filter_count, + u_int flags, + struct tas_biquad_ctrl_t *biquads) +{ + int i; + int rc; + + if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); + + for (i=0; isuper.shadow; + enum tas3004_reg_t reg; + + if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || + filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; + + reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; + + biquad->coeff.b0=GET_4_20(shadow[reg], 0); + biquad->coeff.b1=GET_4_20(shadow[reg], 3); + biquad->coeff.b2=GET_4_20(shadow[reg], 6); + biquad->coeff.a1=GET_4_20(shadow[reg], 9); + biquad->coeff.a2=GET_4_20(shadow[reg],12); + + return 0; +} + + +static int +tas3004_eq_rw( struct tas3004_data_t *self, + u_int cmd, + u_long arg) +{ + int rc; + struct tas_biquad_ctrl_t biquad; + + if (copy_from_user((void *)&biquad, (const void *)arg, sizeof(struct tas_biquad_ctrl_t))) { + return -EFAULT; + } + + if (cmd & SIOC_IN) { + rc=tas3004_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); + if (rc != 0) return rc; + } + + if (cmd & SIOC_OUT) { + rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); + if (rc != 0) return rc; + + if (copy_to_user((void *)arg, (const void *)&biquad, sizeof(struct tas_biquad_ctrl_t))) { + return -EFAULT; + } + + } + return 0; +} + + +static int +tas3004_eq_list_rw( struct tas3004_data_t *self, + u_int cmd, + u_long arg) +{ + int rc = 0; + int filter_count; + int flags; + int i,j; + char sync_required[TAS3004_BIQUAD_CHANNEL_COUNT][TAS3004_BIQUAD_FILTER_COUNT]; + struct tas_biquad_ctrl_t biquad; + + memset(sync_required,0,sizeof(sync_required)); + + if (copy_from_user((void *)&filter_count, + (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t,filter_count), + sizeof(int))) { + return -EFAULT; + } + + if (copy_from_user((void *)&flags, + (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t,flags), + sizeof(int))) { + return -EFAULT; + } + + if (cmd & SIOC_IN) { + } + + for (i=0; i < filter_count; i++) { + if (copy_from_user((void *)&biquad, + (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t, biquads[i]), + sizeof(struct tas_biquad_ctrl_t))) { + return -EFAULT; + } + + if (cmd & SIOC_IN) { + sync_required[biquad.channel][biquad.filter]=1; + rc=tas3004_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); + if (rc != 0) return rc; + } + + if (cmd & SIOC_OUT) { + rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); + if (rc != 0) return rc; + + if (copy_to_user((void *)arg + offsetof(struct tas_biquad_ctrl_list_t, biquads[i]), + (const void *)&biquad, + sizeof(struct tas_biquad_ctrl_t))) { + return -EFAULT; + } + } + } + + if (cmd & SIOC_IN) { + /* + * This is OK for the tas3004. For the + * tas3001c, going into fast load mode causes + * the treble and bass to be reset to 0dB, and + * volume controls to be muted. + */ + if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); + for (i=0; isuper.shadow; + + if (flags & TAS_DRCE_ABOVE_RATIO) { + self->drce_state.above.expand = drce->above.expand; + if (drce->above.val == (1<<8)) { + self->drce_state.above.val = 1<<8; + shadow[TAS3004_REG_DRC][0] = 0x02; + + } else if (drce->above.expand) { + i=above_threshold_expansion_index(drce->above.val); + self->drce_state.above.val=above_threshold_expansion_ratio[i]; + shadow[TAS3004_REG_DRC][0] = 0x0a + (i<<3); + } else { + i=above_threshold_compression_index(drce->above.val); + self->drce_state.above.val=above_threshold_compression_ratio[i]; + shadow[TAS3004_REG_DRC][0] = 0x08 + (i<<3); + } + } + + if (flags & TAS_DRCE_BELOW_RATIO) { + self->drce_state.below.expand = drce->below.expand; + if (drce->below.val == (1<<8)) { + self->drce_state.below.val = 1<<8; + shadow[TAS3004_REG_DRC][1] = 0x02; + + } else if (drce->below.expand) { + i=below_threshold_expansion_index(drce->below.val); + self->drce_state.below.val=below_threshold_expansion_ratio[i]; + shadow[TAS3004_REG_DRC][1] = 0x08 + (i<<3); + } else { + i=below_threshold_compression_index(drce->below.val); + self->drce_state.below.val=below_threshold_compression_ratio[i]; + shadow[TAS3004_REG_DRC][1] = 0x0a + (i<<3); + } + } + + if (flags & TAS_DRCE_THRESHOLD) { + self->drce_state.threshold=quantize_db(drce->threshold); + shadow[TAS3004_REG_DRC][2] = db_to_regval(self->drce_state.threshold); + } + + if (flags & TAS_DRCE_ENERGY) { + i=time_index(drce->energy); + self->drce_state.energy=time_constants[i]; + shadow[TAS3004_REG_DRC][3] = 0x40 + (i<<4); + } + + if (flags & TAS_DRCE_ATTACK) { + i=time_index(drce->attack); + self->drce_state.attack=time_constants[i]; + shadow[TAS3004_REG_DRC][4] = 0x40 + (i<<4); + } + + if (flags & TAS_DRCE_DECAY) { + i=time_index(drce->decay); + self->drce_state.decay=time_constants[i]; + shadow[TAS3004_REG_DRC][5] = 0x40 + (i<<4); + } + + if (flags & TAS_DRCE_ENABLE) { + self->drce_state.enable = drce->enable; + } + + if (!self->drce_state.enable) { + shadow[TAS3004_REG_DRC][0] |= 0x01; + } + +#ifdef DEBUG_DRCE + printk("DRCE: set [ ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", + self->drce_state.enable, + self->drce_state.above.expand,self->drce_state.above.val, + self->drce_state.below.expand,self->drce_state.below.val, + self->drce_state.threshold, + self->drce_state.energy, + self->drce_state.attack, + self->drce_state.decay); + + printk("DRCE: reg [ %02x %02x %02x %02x %02x %02x ]\n", + (unsigned char)shadow[TAS3004_REG_DRC][0], + (unsigned char)shadow[TAS3004_REG_DRC][1], + (unsigned char)shadow[TAS3004_REG_DRC][2], + (unsigned char)shadow[TAS3004_REG_DRC][3], + (unsigned char)shadow[TAS3004_REG_DRC][4], + (unsigned char)shadow[TAS3004_REG_DRC][5]); +#endif + + return tas3004_sync_register(self, TAS3004_REG_DRC); +} + + +static int +tas3004_drce_rw( struct tas3004_data_t *self, + u_int cmd, + u_long arg) +{ + int rc; + struct tas_drce_ctrl_t drce_ctrl; + + if (copy_from_user((void *)&drce_ctrl, + (const void *)arg, + sizeof(struct tas_drce_ctrl_t))) { + return -EFAULT; + } + +#ifdef DEBUG_DRCE + printk("DRCE: input [ FLAGS:%x ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", + drce_ctrl.flags, + drce_ctrl.data.enable, + drce_ctrl.data.above.expand,drce_ctrl.data.above.val, + drce_ctrl.data.below.expand,drce_ctrl.data.below.val, + drce_ctrl.data.threshold, + drce_ctrl.data.energy, + drce_ctrl.data.attack, + drce_ctrl.data.decay); +#endif + + if (cmd & SIOC_IN) { + rc = tas3004_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); + if (rc < 0) return rc; + } + + if (cmd & SIOC_OUT) { + if (drce_ctrl.flags & TAS_DRCE_ENABLE) + drce_ctrl.data.enable = self->drce_state.enable; + if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) + drce_ctrl.data.above = self->drce_state.above; + if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) + drce_ctrl.data.below = self->drce_state.below; + if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) + drce_ctrl.data.threshold = self->drce_state.threshold; + if (drce_ctrl.flags & TAS_DRCE_ENERGY) + drce_ctrl.data.energy = self->drce_state.energy; + if (drce_ctrl.flags & TAS_DRCE_ATTACK) + drce_ctrl.data.attack = self->drce_state.attack; + if (drce_ctrl.flags & TAS_DRCE_DECAY) + drce_ctrl.data.decay = self->drce_state.decay; + + if (copy_to_user((void *)arg, + (const void *)&drce_ctrl, + sizeof(struct tas_drce_ctrl_t))) { + return -EFAULT; + } + } + + return 0; +} + + +static void +tas3004_update_device_parameters(struct tas3004_data_t *self) +{ + char data; + int i; + + if (!self) return; + + if (self->output_id == TAS_OUTPUT_HEADPHONES) { + /* turn on allPass when headphones are plugged in */ + data = 0x02; + } else { + data = 0x00; + } + + tas3004_write_register(self, TAS3004_REG_MCR2, &data, WRITE_NORMAL | FORCE_WRITE); + + for (i=0; tas3004_eq_prefs[i]; i++) { + struct tas_eq_pref_t *eq = tas3004_eq_prefs[i]; + + if (eq->device_id == self->device_id && + (eq->output_id == 0 || eq->output_id == self->output_id) && + (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { + + tas3004_update_drce(self, TAS_DRCE_ALL, eq->drce); + tas3004_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); + + break; + } + } +} + +static void +tas3004_device_change_handler(void *self) +{ + if (!self) return; + + tas3004_update_device_parameters((struct tas3004_data_t *)self); +} + +static struct tq_struct device_change_task; + +static int +tas3004_output_device_change( struct tas3004_data_t *self, + int device_id, + int output_id, + int speaker_id) +{ + self->device_id=device_id; + self->output_id=output_id; + self->speaker_id=speaker_id; + + schedule_task(&device_change_task); + + return 0; +} + + +static int +tas3004_device_ioctl( struct tas3004_data_t *self, + u_int cmd, + u_long arg) +{ + switch (cmd) { + case TAS_READ_EQ: + case TAS_WRITE_EQ: + return tas3004_eq_rw(self, cmd, arg); + + case TAS_READ_EQ_LIST: + case TAS_WRITE_EQ_LIST: + return tas3004_eq_list_rw(self, cmd, arg); + + case TAS_READ_EQ_FILTER_COUNT: + put_user(TAS3004_BIQUAD_FILTER_COUNT, (uint *)(arg)); + return 0; + + case TAS_READ_EQ_CHANNEL_COUNT: + put_user(TAS3004_BIQUAD_CHANNEL_COUNT, (uint *)(arg)); + return 0; + + case TAS_READ_DRCE: + case TAS_WRITE_DRCE: + return tas3004_drce_rw(self, cmd, arg); + + case TAS_READ_DRCE_CAPS: + put_user(TAS_DRCE_ENABLE | + TAS_DRCE_ABOVE_RATIO | + TAS_DRCE_BELOW_RATIO | + TAS_DRCE_THRESHOLD | + TAS_DRCE_ENERGY | + TAS_DRCE_ATTACK | + TAS_DRCE_DECAY, + (uint *)(arg)); + return 0; + + case TAS_READ_DRCE_MIN: + case TAS_READ_DRCE_MAX: { + struct tas_drce_ctrl_t drce_ctrl; + const struct tas_drce_t *drce_copy; + + if (copy_from_user((void *)&drce_ctrl, + (const void *)arg, + sizeof(struct tas_drce_ctrl_t))) { + return -EFAULT; + } + + if (cmd == TAS_READ_DRCE_MIN) { + drce_copy=&tas3004_drce_min; + } else { + drce_copy=&tas3004_drce_max; + } + + if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) { + drce_ctrl.data.above=drce_copy->above; + } + if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) { + drce_ctrl.data.below=drce_copy->below; + } + if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { + drce_ctrl.data.threshold=drce_copy->threshold; + } + if (drce_ctrl.flags & TAS_DRCE_ENERGY) { + drce_ctrl.data.energy=drce_copy->energy; + } + if (drce_ctrl.flags & TAS_DRCE_ATTACK) { + drce_ctrl.data.attack=drce_copy->attack; + } + if (drce_ctrl.flags & TAS_DRCE_DECAY) { + drce_ctrl.data.decay=drce_copy->decay; + } + + if (copy_to_user((void *)arg, + (const void *)&drce_ctrl, + sizeof(struct tas_drce_ctrl_t))) { + return -EFAULT; + } + } + } + + return -EINVAL; +} + + +static int +tas3004_init_mixer(struct tas3004_data_t *self) +{ + unsigned char mcr = (1<<6)+(2<<4)+(2<<2); + + /* Make sure something answers on the i2c bus */ + if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, + WRITE_NORMAL | FORCE_WRITE) < 0) + return -1; + + tas3004_fast_load(self, 1); + + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); + (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); + + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); + (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); + + tas3004_sync_register(self, TAS3004_REG_DRC); + + tas3004_sync_register(self, TAS3004_REG_MCR2); + + tas3004_fast_load(self, 0); + + tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); + tas3004_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); + tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); + tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); + + tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); + tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); + + return 0; +} + + +static int +tas3004_uninit_mixer(struct tas3004_data_t *self) +{ + tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); + tas3004_set_mixer_level(self, SOUND_MIXER_PCM, 0); + tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); + tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); + + tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0); + tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); + + return 0; +} + + +static int +tas3004_init(struct i2c_client *client) +{ + char drce_init[]={ 0x69, 0x22, 0x9f, 0xb0, 0x60, 0xa0 }; + char mcr2 = 0; + + struct tas3004_data_t *self; + int i, j; + + self = kmalloc(sizeof(struct tas3004_data_t) + + TAS3004_REG_MAX * sizeof(tas_shadow_t), + GFP_KERNEL); + if (self == NULL) + return -ENOMEM; + + memset(self, + 0, + sizeof(struct tas3004_data_t) + + TAS3004_REG_MAX * sizeof(tas_shadow_t)); + + client->data = (void *)self; + + self->super.client = client; + self->super.shadow = (tas_shadow_t *)(self+1); + + self->output_id=TAS_OUTPUT_HEADPHONES; + self->device_id=0; + self->speaker_id=0; + + for (i=0; i + */ + +#ifndef _TAS3004_H_ +#define _TAS3004_H_ + +#include + +#include "tas_common.h" +#include "tas_eq_prefs.h" + +/* + * Macros that correspond to the registers that we write to + * when setting the various values. + */ + +#define TAS3004_VERSION "0.3" +#define TAS3004_DATE "20011214" + +#define I2C_DRIVERNAME_TAS3004 "TAS3004 driver V " TAS3004_VERSION +#define I2C_DRIVERID_TAS3004 (I2C_DRIVERID_TAS_BASE+1) + +extern struct tas_driver_hooks_t tas3004_hooks; +extern struct tas_gain_t tas3004_gain; +extern struct tas_eq_pref_t *tas3004_eq_prefs[]; + +enum tas3004_reg_t { + TAS3004_REG_MCR = 0x01, + TAS3004_REG_DRC = 0x02, + + TAS3004_REG_VOLUME = 0x04, + TAS3004_REG_TREBLE = 0x05, + TAS3004_REG_BASS = 0x06, + TAS3004_REG_LEFT_MIXER = 0x07, + TAS3004_REG_RIGHT_MIXER = 0x08, + + TAS3004_REG_LEFT_BIQUAD0 = 0x0a, + TAS3004_REG_LEFT_BIQUAD1 = 0x0b, + TAS3004_REG_LEFT_BIQUAD2 = 0x0c, + TAS3004_REG_LEFT_BIQUAD3 = 0x0d, + TAS3004_REG_LEFT_BIQUAD4 = 0x0e, + TAS3004_REG_LEFT_BIQUAD5 = 0x0f, + TAS3004_REG_LEFT_BIQUAD6 = 0x10, + + TAS3004_REG_RIGHT_BIQUAD0 = 0x13, + TAS3004_REG_RIGHT_BIQUAD1 = 0x14, + TAS3004_REG_RIGHT_BIQUAD2 = 0x15, + TAS3004_REG_RIGHT_BIQUAD3 = 0x16, + TAS3004_REG_RIGHT_BIQUAD4 = 0x17, + TAS3004_REG_RIGHT_BIQUAD5 = 0x18, + TAS3004_REG_RIGHT_BIQUAD6 = 0x19, + + TAS3004_REG_LEFT_LOUD_BIQUAD = 0x21, + TAS3004_REG_RIGHT_LOUD_BIQUAD = 0x22, + + TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN = 0x23, + TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN = 0x24, + + TAS3004_REG_TEST = 0x29, + + TAS3004_REG_ANALOG_CTRL = 0x40, + TAS3004_REG_TEST1 = 0x41, + TAS3004_REG_TEST2 = 0x42, + TAS3004_REG_MCR2 = 0x43, + + TAS3004_REG_MAX = 0x44 +}; + +#endif /* _TAS3004_H_ */ diff -uNr linux-2.4.20/drivers/sound/dmasound/tas3004_tables.c linux-2.4.20-ben6/drivers/sound/dmasound/tas3004_tables.c --- linux-2.4.20/drivers/sound/dmasound/tas3004_tables.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/tas3004_tables.c 2003-02-16 20:21:12.000000000 +0100 @@ -0,0 +1,301 @@ +#include "tas3004.h" +#include "tas_eq_prefs.h" + +static struct tas_drce_t eqp_17_1_0_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -19.12 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_17_1_0_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } }, + { channel: 0, filter: 1, data: { coeff: { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } }, + { channel: 0, filter: 5, data: { coeff: { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } }, + { channel: 0, filter: 6, data: { coeff: { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } }, + { channel: 1, filter: 1, data: { coeff: { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } }, + { channel: 1, filter: 5, data: { coeff: { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } }, + { channel: 1, filter: 6, data: { coeff: { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } } +}; + +static struct tas_eq_pref_t eqp_17_1_0 = { + sample_rate: 44100, + device_id: 0x17, + output_id: TAS_OUTPUT_INTERNAL_SPKR, + speaker_id: 0x00, + + drce: &eqp_17_1_0_drce, + + filter_count: 14, + biquads: eqp_17_1_0_biquads +}; + +/* ======================================================================== */ + +static struct tas_drce_t eqp_18_1_0_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -13.14 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_18_1_0_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } }, + { channel: 0, filter: 1, data: { coeff: { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } }, + { channel: 0, filter: 5, data: { coeff: { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } }, + { channel: 0, filter: 6, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } }, + { channel: 1, filter: 1, data: { coeff: { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } }, + { channel: 1, filter: 5, data: { coeff: { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } }, + { channel: 1, filter: 6, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } } +}; + +static struct tas_eq_pref_t eqp_18_1_0 = { + sample_rate: 44100, + device_id: 0x18, + output_id: TAS_OUTPUT_INTERNAL_SPKR, + speaker_id: 0x00, + + drce: &eqp_18_1_0_drce, + + filter_count: 14, + biquads: eqp_18_1_0_biquads +}; + +/* ======================================================================== */ + +static struct tas_drce_t eqp_1a_1_0_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -10.75 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_1a_1_0_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } }, + { channel: 0, filter: 1, data: { coeff: { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } }, + { channel: 0, filter: 5, data: { coeff: { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } }, + { channel: 0, filter: 6, data: { coeff: { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } }, + { channel: 1, filter: 1, data: { coeff: { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } }, + { channel: 1, filter: 5, data: { coeff: { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } }, + { channel: 1, filter: 6, data: { coeff: { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } } +}; + +static struct tas_eq_pref_t eqp_1a_1_0 = { + sample_rate: 44100, + device_id: 0x1a, + output_id: TAS_OUTPUT_INTERNAL_SPKR, + speaker_id: 0x00, + + drce: &eqp_1a_1_0_drce, + + filter_count: 14, + biquads: eqp_1a_1_0_biquads +}; + +/* ======================================================================== */ + +static struct tas_drce_t eqp_1c_1_0_drce={ + enable: 1, + above: { val: 3.0 * (1<<8), expand: 0 }, + below: { val: 1.0 * (1<<8), expand: 0 }, + threshold: -14.34 * (1<<8), + energy: 2.4 * (1<<12), + attack: 0.013 * (1<<12), + decay: 0.212 * (1<<12), +}; + +static struct tas_biquad_ctrl_t eqp_1c_1_0_biquads[]={ + { channel: 0, filter: 0, data: { coeff: { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } }, + { channel: 0, filter: 1, data: { coeff: { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } }, + { channel: 0, filter: 2, data: { coeff: { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } }, + { channel: 0, filter: 3, data: { coeff: { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } }, + { channel: 0, filter: 4, data: { coeff: { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } }, + { channel: 0, filter: 5, data: { coeff: { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } }, + { channel: 0, filter: 6, data: { coeff: { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } }, + + { channel: 1, filter: 0, data: { coeff: { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } }, + { channel: 1, filter: 1, data: { coeff: { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } }, + { channel: 1, filter: 2, data: { coeff: { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } }, + { channel: 1, filter: 3, data: { coeff: { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } }, + { channel: 1, filter: 4, data: { coeff: { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } }, + { channel: 1, filter: 5, data: { coeff: { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } }, + { channel: 1, filter: 6, data: { coeff: { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } } +}; + +static struct tas_eq_pref_t eqp_1c_1_0 = { + sample_rate: 44100, + device_id: 0x1c, + output_id: TAS_OUTPUT_INTERNAL_SPKR, + speaker_id: 0x00, + + drce: &eqp_1c_1_0_drce, + + filter_count: 14, + biquads: eqp_1c_1_0_biquads +}; + +/* ======================================================================== */ + +static uint tas3004_master_tab[]={ + 0x0, 0x75, 0x9c, 0xbb, + 0xdb, 0xfb, 0x11e, 0x143, + 0x16b, 0x196, 0x1c3, 0x1f5, + 0x229, 0x263, 0x29f, 0x2e1, + 0x328, 0x373, 0x3c5, 0x41b, + 0x478, 0x4dc, 0x547, 0x5b8, + 0x633, 0x6b5, 0x740, 0x7d5, + 0x873, 0x91c, 0x9d2, 0xa92, + 0xb5e, 0xc39, 0xd22, 0xe19, + 0xf20, 0x1037, 0x1161, 0x129e, + 0x13ed, 0x1551, 0x16ca, 0x185d, + 0x1a08, 0x1bcc, 0x1dac, 0x1fa7, + 0x21c1, 0x23fa, 0x2655, 0x28d6, + 0x2b7c, 0x2e4a, 0x3141, 0x3464, + 0x37b4, 0x3b35, 0x3ee9, 0x42d3, + 0x46f6, 0x4b53, 0x4ff0, 0x54ce, + 0x59f2, 0x5f5f, 0x6519, 0x6b24, + 0x7183, 0x783c, 0x7f53, 0x86cc, + 0x8ead, 0x96fa, 0x9fba, 0xa8f2, + 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa, + 0xdee8, 0xeb75, 0xf8aa, 0x1068e, + 0x1152a, 0x12487, 0x134ad, 0x145a5, + 0x1577b, 0x16a37, 0x17df5, 0x192bd, + 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1, + 0x20b55, 0x22727, 0x24456, 0x262f2, + 0x2830b +}; + +static uint tas3004_mixer_tab[]={ + 0x0, 0x748, 0x9be, 0xbaf, + 0xda4, 0xfb1, 0x11de, 0x1431, + 0x16ad, 0x1959, 0x1c37, 0x1f4b, + 0x2298, 0x2628, 0x29fb, 0x2e12, + 0x327d, 0x3734, 0x3c47, 0x41b4, + 0x4787, 0x4dbe, 0x546d, 0x5b86, + 0x632e, 0x6b52, 0x7400, 0x7d54, + 0x873b, 0x91c6, 0x9d1a, 0xa920, + 0xb5e5, 0xc38c, 0xd21b, 0xe18f, + 0xf1f5, 0x1036a, 0x1160f, 0x129d6, + 0x13ed0, 0x1550c, 0x16ca0, 0x185c9, + 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75, + 0x21c0f, 0x23fa3, 0x26552, 0x28d64, + 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b, + 0x37b44, 0x3b353, 0x3ee94, 0x42d30, + 0x46f55, 0x4b533, 0x4fefc, 0x54ce5, + 0x59f25, 0x5f5f6, 0x65193, 0x6b23c, + 0x71835, 0x783c3, 0x7f52c, 0x86cc0, + 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a, + 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0, + 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4, + 0x1152a3, 0x12486a, 0x134ac8, 0x145a55, + 0x1577ac, 0x16a370, 0x17df51, 0x192bc2, + 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04, + 0x20b542, 0x227268, 0x244564, 0x262f26, + 0x2830af +}; + +static uint tas3004_treble_tab[]={ + 0x96, 0x95, 0x95, 0x94, + 0x93, 0x92, 0x92, 0x91, + 0x90, 0x90, 0x8f, 0x8e, + 0x8d, 0x8d, 0x8c, 0x8b, + 0x8a, 0x8a, 0x89, 0x88, + 0x88, 0x87, 0x86, 0x85, + 0x85, 0x84, 0x83, 0x83, + 0x82, 0x81, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x7d, + 0x7c, 0x7b, 0x7b, 0x7a, + 0x79, 0x78, 0x78, 0x77, + 0x76, 0x76, 0x75, 0x74, + 0x73, 0x73, 0x72, 0x71, + 0x71, 0x68, 0x45, 0x5b, + 0x6d, 0x6c, 0x6b, 0x6a, + 0x69, 0x68, 0x67, 0x66, + 0x65, 0x63, 0x62, 0x62, + 0x60, 0x5e, 0x5c, 0x5b, + 0x59, 0x57, 0x55, 0x53, + 0x52, 0x4f, 0x4d, 0x4a, + 0x48, 0x46, 0x43, 0x40, + 0x3d, 0x3a, 0x36, 0x33, + 0x2f, 0x2c, 0x27, 0x23, + 0x1f, 0x1a, 0x15, 0xf, + 0x8, 0x5, 0x2, 0x1, + 0x1 +}; + +static uint tas3004_bass_tab[]={ + 0x96, 0x95, 0x95, 0x94, + 0x93, 0x92, 0x92, 0x91, + 0x90, 0x90, 0x8f, 0x8e, + 0x8d, 0x8d, 0x8c, 0x8b, + 0x8a, 0x8a, 0x89, 0x88, + 0x88, 0x87, 0x86, 0x85, + 0x85, 0x84, 0x83, 0x83, + 0x82, 0x81, 0x80, 0x80, + 0x7f, 0x7e, 0x7e, 0x7d, + 0x7c, 0x7b, 0x7b, 0x7a, + 0x79, 0x78, 0x78, 0x77, + 0x76, 0x76, 0x75, 0x74, + 0x73, 0x73, 0x72, 0x71, + 0x70, 0x6f, 0x6e, 0x6d, + 0x6c, 0x6b, 0x6a, 0x6a, + 0x69, 0x67, 0x66, 0x66, + 0x65, 0x63, 0x62, 0x62, + 0x61, 0x60, 0x5e, 0x5d, + 0x5b, 0x59, 0x57, 0x55, + 0x53, 0x51, 0x4f, 0x4c, + 0x4a, 0x48, 0x46, 0x44, + 0x41, 0x3e, 0x3b, 0x38, + 0x36, 0x33, 0x2f, 0x2b, + 0x28, 0x24, 0x20, 0x1c, + 0x17, 0x12, 0xd, 0x7, + 0x1 +}; + +struct tas_gain_t tas3004_gain={ + master: tas3004_master_tab, + treble: tas3004_treble_tab, + bass: tas3004_bass_tab, + mixer: tas3004_mixer_tab +}; + +struct tas_eq_pref_t *tas3004_eq_prefs[]={ + &eqp_17_1_0, + &eqp_18_1_0, + &eqp_1a_1_0, + &eqp_1c_1_0, + NULL +}; diff -uNr linux-2.4.20/drivers/sound/dmasound/tas_common.c linux-2.4.20-ben6/drivers/sound/dmasound/tas_common.c --- linux-2.4.20/drivers/sound/dmasound/tas_common.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/tas_common.c 2003-02-16 20:20:04.000000000 +0100 @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tas_common.h" + +#define CALL0(proc) \ + do { \ + struct tas_data_t *self; \ + if (!tas_client || driver_hooks == NULL) \ + return -1; \ + self = (struct tas_data_t *)tas_client->data; \ + if (driver_hooks->proc) \ + return driver_hooks->proc(self); \ + else \ + return -EINVAL; \ + } while (0) + +#define CALL(proc,arg...) \ + do { \ + struct tas_data_t *self; \ + if (!tas_client || driver_hooks == NULL) \ + return -1; \ + self = (struct tas_data_t *)tas_client->data; \ + if (driver_hooks->proc) \ + return driver_hooks->proc(self, ## arg); \ + else \ + return -EINVAL; \ + } while (0) + + +static u8 tas_i2c_address = 0x34; +static struct i2c_client * tas_client = NULL; + +static int tas_initialized = 0; +static struct device_node* tas_node = NULL; + +static int tas_attach_adapter(struct i2c_adapter *); +static int tas_detach_client(struct i2c_client *); + +struct i2c_driver tas_driver = { + name: "", + id: 0, + flags: I2C_DF_NOTIFY, + attach_adapter: &tas_attach_adapter, + detach_client: &tas_detach_client, + command: NULL, + inc_use: NULL, + dec_use: NULL +}; + +struct tas_driver_hooks_t *driver_hooks; + +int +tas_register_driver(struct tas_driver_hooks_t *hooks) +{ + driver_hooks = hooks; + return 0; +} + +int +tas_get_mixer_level(int mixer, uint *level) +{ + CALL(get_mixer_level,mixer,level); +} + +int +tas_set_mixer_level(int mixer,uint level) +{ + CALL(set_mixer_level,mixer,level); +} + +int +tas_enter_sleep(void) +{ + CALL0(enter_sleep); +} + +int +tas_leave_sleep(void) +{ + CALL0(leave_sleep); +} + +int +tas_supported_mixers(void) +{ + CALL0(supported_mixers); +} + +int +tas_mixer_is_stereo(int mixer) +{ + CALL(mixer_is_stereo,mixer); +} + +int +tas_stereo_mixers(void) +{ + CALL0(stereo_mixers); +} + +int +tas_output_device_change(int device_id,int layout_id,int speaker_id) +{ + CALL(output_device_change,device_id,layout_id,speaker_id); +} + +int +tas_device_ioctl(u_int cmd, u_long arg) +{ + CALL(device_ioctl,cmd,arg); +} + +int +tas_post_init(void) +{ + CALL0(post_init); +} + +static int +tas_detect_client(struct i2c_adapter *adapter, int address) +{ + int rc = 0; + struct i2c_client *new_client; + struct tas_data_t *data; + const char *client_name = "tas Digital Equalizer"; + + if (driver_hooks == NULL) { + printk(KERN_ERR "tas_detect_client called with no hooks !\n"); + return -ENODEV; + } + + new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!new_client) { + rc = -ENOMEM; + goto bail; + } + + new_client->data = NULL; + + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &tas_driver; + new_client->flags = 0; + + strcpy(new_client->name,client_name); + + new_client->id = 0; /* Only one instance supported */ + + if (driver_hooks->init && driver_hooks->init(new_client)) { + rc = -ENODEV; + goto bail; + } + + /* Tell the i2c layer a new client has arrived */ + if (i2c_attach_client(new_client)) { + if (driver_hooks->uninit) + driver_hooks->uninit((struct tas_data_t *)new_client->data); + rc = -ENODEV; + goto bail; + } + + tas_client = new_client; +bail: + if (rc && new_client) { + tas_client = NULL; + kfree(new_client); + } + return rc; +} + +static int +tas_attach_adapter(struct i2c_adapter *adapter) +{ + if (!strncmp(adapter->name, "mac-io", 6)) + return tas_detect_client(adapter, tas_i2c_address); + return 0; +} + +static int +tas_detach_client(struct i2c_client *client) +{ + if (client == tas_client) { + driver_hooks->uninit((struct tas_data_t *)client->data); + + i2c_detach_client(client); + kfree(client); + } + return 0; +} + +int __init +tas_cleanup(void) +{ + if (!tas_initialized) + return -ENODEV; + i2c_del_driver(&tas_driver); + tas_initialized = 0; + + return 0; +} + +int __init +tas_init(int driver_id, const char *driver_name) +{ + int rc; + u32* paddr; + + if (tas_initialized) + return 0; + + strncpy(tas_driver.name,driver_name,31); + tas_driver.name[31]=0; + tas_driver.id=driver_id; + + tas_node = find_devices("deq"); + if (tas_node == NULL) + return -ENODEV; + + printk(KERN_INFO "tas driver [%s])\n",tas_driver.name); + paddr = (u32 *)get_property(tas_node, "i2c-address", NULL); + if (paddr) { + tas_i2c_address = (*paddr) >> 1; + printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", + tas_i2c_address); + } else + printk(KERN_INFO "using i2c address: 0x%x (default)\n", tas_i2c_address); + + if ((rc = i2c_add_driver(&tas_driver))) { + printk("tas: Driver registration failed, module not inserted.\n"); + tas_cleanup(); + return rc; + } + tas_initialized = 1; + return 0; +} +/* + * Local Variables: + * tab-width: 8 + * indent-tabs-mode: t + * c-basic-offset: 8 + * End: + */ diff -uNr linux-2.4.20/drivers/sound/dmasound/tas_common.h linux-2.4.20-ben6/drivers/sound/dmasound/tas_common.h --- linux-2.4.20/drivers/sound/dmasound/tas_common.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/tas_common.h 2003-02-16 20:20:39.000000000 +0100 @@ -0,0 +1,284 @@ +#ifndef _TAS_COMMON_H_ +#define _TAS_COMMON_H_ + +#include +#include +#include + +#define I2C_DRIVERID_TAS_BASE (0xFEBA) + +#define SET_4_20(shadow, offset, val) \ + do { \ + (shadow)[(offset)+0] = ((val) >> 16) & 0xff; \ + (shadow)[(offset)+1] = ((val) >> 8) & 0xff; \ + (shadow)[(offset)+2] = ((val) >> 0) & 0xff; \ + } while (0) + +#define GET_4_20(shadow, offset) \ + (((u_int)((shadow)[(offset)+0]) << 16) | \ + ((u_int)((shadow)[(offset)+1]) << 8) | \ + ((u_int)((shadow)[(offset)+2]) << 0)) + + +#define TAS_BIQUAD_FAST_LOAD 0x01 + +#define TAS_DRCE_ENABLE 0x01 +#define TAS_DRCE_ABOVE_RATIO 0x02 +#define TAS_DRCE_BELOW_RATIO 0x04 +#define TAS_DRCE_THRESHOLD 0x08 +#define TAS_DRCE_ENERGY 0x10 +#define TAS_DRCE_ATTACK 0x20 +#define TAS_DRCE_DECAY 0x40 + +#define TAS_DRCE_ALL 0x7f + + +#define TAS_OUTPUT_HEADPHONES 0x00 +#define TAS_OUTPUT_INTERNAL_SPKR 0x01 +#define TAS_OUTPUT_EXTERNAL_SPKR 0x02 + + +union tas_biquad_t { + struct { + int b0,b1,b2,a1,a2; + } coeff; + int buf[5]; +}; + +struct tas_biquad_ctrl_t { + u_int channel:4; + u_int filter:4; + + union tas_biquad_t data; +}; + +struct tas_biquad_ctrl_list_t { + int flags; + int filter_count; + struct tas_biquad_ctrl_t biquads[0]; +}; + +struct tas_ratio_t { + unsigned short val; /* 8.8 */ + unsigned short expand; /* 0 = compress, !0 = expand. */ +}; + +struct tas_drce_t { + unsigned short enable; + struct tas_ratio_t above; + struct tas_ratio_t below; + short threshold; /* dB, 8.8 signed */ + unsigned short energy; /* seconds, 4.12 unsigned */ + unsigned short attack; /* seconds, 4.12 unsigned */ + unsigned short decay; /* seconds, 4.12 unsigned */ +}; + +struct tas_drce_ctrl_t { + uint flags; + + struct tas_drce_t data; +}; + +struct tas_gain_t +{ + unsigned int *master; + unsigned int *treble; + unsigned int *bass; + unsigned int *mixer; +}; + +typedef char tas_shadow_t[16]; + +struct tas_data_t +{ + struct i2c_client *client; + tas_shadow_t *shadow; + uint mixer[SOUND_MIXER_NRDEVICES]; +}; + +typedef int (*tas_hook_init_t)(struct i2c_client *); +typedef int (*tas_hook_post_init_t)(struct tas_data_t *); +typedef void (*tas_hook_uninit_t)(struct tas_data_t *); + +typedef int (*tas_hook_get_mixer_level_t)(struct tas_data_t *,int,uint *); +typedef int (*tas_hook_set_mixer_level_t)(struct tas_data_t *,int,uint); + +typedef int (*tas_hook_enter_sleep_t)(struct tas_data_t *); +typedef int (*tas_hook_leave_sleep_t)(struct tas_data_t *); + +typedef int (*tas_hook_supported_mixers_t)(struct tas_data_t *); +typedef int (*tas_hook_mixer_is_stereo_t)(struct tas_data_t *,int); +typedef int (*tas_hook_stereo_mixers_t)(struct tas_data_t *); + +typedef int (*tas_hook_output_device_change_t)(struct tas_data_t *,int,int,int); +typedef int (*tas_hook_device_ioctl_t)(struct tas_data_t *,u_int,u_long); + +struct tas_driver_hooks_t { + /* + * All hardware initialisation must be performed in + * post_init(), as tas_dmasound_init() does a hardware reset. + * + * init() is called before tas_dmasound_init() so that + * ouput_device_change() is always called after i2c driver + * initialisation. The implication is that + * output_device_change() must cope with the fact that it + * may be called before post_init(). + */ + + tas_hook_init_t init; + tas_hook_post_init_t post_init; + tas_hook_uninit_t uninit; + + tas_hook_get_mixer_level_t get_mixer_level; + tas_hook_set_mixer_level_t set_mixer_level; + + tas_hook_enter_sleep_t enter_sleep; + tas_hook_leave_sleep_t leave_sleep; + + tas_hook_supported_mixers_t supported_mixers; + tas_hook_mixer_is_stereo_t mixer_is_stereo; + tas_hook_stereo_mixers_t stereo_mixers; + + tas_hook_output_device_change_t output_device_change; + tas_hook_device_ioctl_t device_ioctl; +}; + +enum tas_write_mode_t { + WRITE_HW = 0x01, + WRITE_SHADOW = 0x02, + WRITE_NORMAL = 0x03, + FORCE_WRITE = 0x04 +}; + +static inline uint +tas_mono_to_stereo(uint mono) +{ + mono &=0xff; + return mono | (mono<<8); +} + +/* + * Todo: make these functions a bit more efficient ! + */ +static inline int +tas_write_register( struct tas_data_t *self, + uint reg_num, + uint reg_width, + char *data, + uint write_mode) +{ + int rc; + + if (reg_width==0 || data==NULL || self==NULL) + return -EINVAL; + if (!(write_mode & FORCE_WRITE) && + !memcmp(data,self->shadow[reg_num],reg_width)) + return 0; + + if (write_mode & WRITE_SHADOW) + memcpy(self->shadow[reg_num],data,reg_width); + if (write_mode & WRITE_HW) { + rc=i2c_smbus_write_block_data(self->client, + reg_num, + reg_width, + data); + if (rc < 0) { + printk("tas: I2C block write failed \n"); + return rc; + } + } + return 0; +} + +static inline int +tas_sync_register( struct tas_data_t *self, + uint reg_num, + uint reg_width) +{ + int rc; + + if (reg_width==0 || self==NULL) + return -EINVAL; + rc=i2c_smbus_write_block_data(self->client, + reg_num, + reg_width, + self->shadow[reg_num]); + if (rc < 0) { + printk("tas: I2C block write failed \n"); + return rc; + } + return 0; +} + +static inline int +tas_write_byte_register( struct tas_data_t *self, + uint reg_num, + char data, + uint write_mode) +{ + if (self==NULL) + return -1; + if (!(write_mode & FORCE_WRITE) && data != self->shadow[reg_num][0]) + return 0; + if (write_mode & WRITE_SHADOW) + self->shadow[reg_num][0]=data; + if (write_mode & WRITE_HW) { + if (i2c_smbus_write_byte_data(self->client, reg_num, data) < 0) { + printk("tas: I2C byte write failed \n"); + return -1; + } + } + return 0; +} + +static inline int +tas_sync_byte_register( struct tas_data_t *self, + uint reg_num, + uint reg_width) +{ + if (reg_width==0 || self==NULL) + return -1; + if (i2c_smbus_write_byte_data( + self->client, reg_num, self->shadow[reg_num][0]) < 0) { + printk("tas: I2C byte write failed \n"); + return -1; + } + return 0; +} + +static inline int +tas_read_register( struct tas_data_t *self, + uint reg_num, + uint reg_width, + char *data) +{ + if (reg_width==0 || data==NULL || self==NULL) + return -1; + memcpy(data,self->shadow[reg_num],reg_width); + return 0; +} + +extern int tas_register_driver(struct tas_driver_hooks_t *hooks); + +extern int tas_get_mixer_level(int mixer,uint *level); +extern int tas_set_mixer_level(int mixer,uint level); +extern int tas_enter_sleep(void); +extern int tas_leave_sleep(void); +extern int tas_supported_mixers(void); +extern int tas_mixer_is_stereo(int mixer); +extern int tas_stereo_mixers(void); +extern int tas_output_device_change(int,int,int); +extern int tas_device_ioctl(u_int, u_long); + +extern int tas_cleanup(void); +extern int tas_init(int driver_id,const char *driver_name); +extern int tas_post_init(void); + +#endif /* _TAS_COMMON_H_ */ +/* + * Local Variables: + * tab-width: 8 + * indent-tabs-mode: t + * c-basic-offset: 8 + * End: + */ diff -uNr linux-2.4.20/drivers/sound/dmasound/tas_eq_prefs.h linux-2.4.20-ben6/drivers/sound/dmasound/tas_eq_prefs.h --- linux-2.4.20/drivers/sound/dmasound/tas_eq_prefs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/tas_eq_prefs.h 2003-02-16 20:20:35.000000000 +0100 @@ -0,0 +1,24 @@ +#ifndef _TAS_EQ_PREFS_H_ +#define _TAS_EQ_PREFS_H_ + +struct tas_eq_pref_t { + u_int sample_rate; + u_int device_id; + u_int output_id; + u_int speaker_id; + + struct tas_drce_t *drce; + + u_int filter_count; + struct tas_biquad_ctrl_t *biquads; +}; + +#endif /* _TAS_EQ_PREFS_H_ */ + +/* + * Local Variables: + * tab-width: 8 + * indent-tabs-mode: t + * c-basic-offset: 8 + * End: + */ diff -uNr linux-2.4.20/drivers/sound/dmasound/tas_ioctl.h linux-2.4.20-ben6/drivers/sound/dmasound/tas_ioctl.h --- linux-2.4.20/drivers/sound/dmasound/tas_ioctl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-ben6/drivers/sound/dmasound/tas_ioctl.h 2003-02-16 20:20:39.000000000 +0100 @@ -0,0 +1,24 @@ +#ifndef _TAS_IOCTL_H_ +#define _TAS_IOCTL_H_ + +#include +#include + + +#define TAS_READ_EQ _SIOR('t',0,struct tas_biquad_ctrl_t) +#define TAS_WRITE_EQ _SIOW('t',0,struct tas_biquad_ctrl_t) + +#define TAS_READ_EQ_LIST _SIOR('t',1,struct tas_biquad_ctrl_t) +#define TAS_WRITE_EQ_LIST _SIOW('t',1,struct tas_biquad_ctrl_t) + +#define TAS_READ_EQ_FILTER_COUNT _SIOR('t',2,int) +#define TAS_READ_EQ_CHANNEL_COUNT _SIOR('t',3,int) + +#define TAS_READ_DRCE _SIOR('t',4,struct tas_drce_ctrl_t) +#define TAS_WRITE_DRCE _SIOW('t',4,struct tas_drce_ctrl_t) + +#define TAS_READ_DRCE_CAPS _SIOR('t',5,int) +#define TAS_READ_DRCE_MIN _SIOR('t',6,int) +#define TAS_READ_DRCE_MAX _SIOR('t',7,int) + +#endif diff -uNr linux-2.4.20/drivers/usb/CDCEther.c linux-2.4.20-ben6/drivers/usb/CDCEther.c --- linux-2.4.20/drivers/usb/CDCEther.c 2002-11-29 00:53:14.000000000 +0100 +++ linux-2.4.20-ben6/drivers/usb/CDCEther.c 2003-02-16 20:20:22.000000000 +0100 @@ -313,7 +313,7 @@ // into an integer number of USB packets, we force it to send one // more byte so the device will get a runt USB packet signalling the // end of the ethernet frame - if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) { + if ( (skb->len) & (ether_dev->data_ep_out_size) ) { // It was not an exact multiple // no need to add anything extra count = skb->len; diff -uNr linux-2.4.20/drivers/usb/storage/scsiglue.c linux-2.4.20-ben6/drivers/usb/storage/scsiglue.c --- linux-2.4.20/drivers/usb/storage/scsiglue.c 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.20-ben6/drivers/usb/storage/scsiglue.c 2003-02-16 20:20:02.000000000 +0100 @@ -75,7 +75,8 @@ { struct us_data *us; char local_name[32]; - + spin_unlock_irq(&io_request_lock); + /* This is not nice at all, but how else are we to get the * data here? */ us = (struct us_data *)sht->proc_dir; @@ -83,8 +84,10 @@ /* set up the name of our subdirectory under /proc/scsi/ */ sprintf(local_name, "usb-storage-%d", us->host_number); sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL); - if (!sht->proc_name) + if (!sht->proc_name) { + spin_lock_irq(&io_request_lock); return 0; + } strcpy(sht->proc_name, local_name); /* we start with no /proc directory entry */ @@ -95,12 +98,14 @@ if (us->host) { us->host->hostdata[0] = (unsigned long)us; us->host_no = us->host->host_no; + spin_lock_irq(&io_request_lock); return 1; } /* odd... didn't register properly. Abort and free pointers */ kfree(sht->proc_name); sht->proc_name = NULL; + spin_lock_irq(&io_request_lock); return 0; } @@ -149,6 +154,8 @@ US_DEBUGP("queuecommand() called\n"); srb->host_scribble = (unsigned char *)us; + spin_unlock_irq(&io_request_lock); + /* get exclusive access to the structures we want */ down(&(us->queue_exclusion)); @@ -163,6 +170,8 @@ /* wake up the process task */ up(&(us->sema)); + spin_lock_irq(&io_request_lock); + return 0; } @@ -190,12 +199,16 @@ } /* if we have an urb pending, let's wake the control thread up */ - if (!us->current_done.done) { + if (us->current_urb->status == -EINPROGRESS) { + spin_unlock_irq(&io_request_lock); + /* cancel the URB -- this will automatically wake the thread */ usb_unlink_urb(us->current_urb); /* wait for us to be done */ wait_for_completion(&(us->notify)); + + spin_lock_irq(&io_request_lock); return SUCCESS; } @@ -208,9 +221,14 @@ static int device_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - + int rc; + US_DEBUGP("device_reset() called\n" ); - return us->transport_reset(us); + spin_unlock_irq(&io_request_lock); + rc = us->transport_reset(us); + spin_lock_irq(&io_request_lock); + + return rc; } /* This resets the device port, and simulates the device @@ -230,6 +248,7 @@ US_DEBUGP("-- device removed already\n"); return SUCCESS; } + spin_unlock_irq(&io_request_lock); /* release the IRQ, if we have one */ down(&(us->irq_urb_sem)); @@ -241,8 +260,10 @@ up(&(us->irq_urb_sem)); /* attempt to reset the port */ - if (usb_reset_device(us->pusb_dev) < 0) + if (usb_reset_device(us->pusb_dev) < 0) { + spin_lock_irq(&io_request_lock); return FAILED; + } /* FIXME: This needs to lock out driver probing while it's working * or we can have race conditions */ @@ -283,6 +304,8 @@ up(&(us->irq_urb_sem)); } + spin_lock_irq(&io_request_lock); + US_DEBUGP("bus_reset() complete\n"); return SUCCESS; } diff -uNr linux-2.4.20/drivers/usb/storage/usb.c linux-2.4.20-ben6/drivers/usb/storage/usb.c --- linux-2.4.20/drivers/usb/storage/usb.c 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.20-ben6/drivers/usb/storage/usb.c 2003-02-16 20:21:36.000000000 +0100 @@ -310,6 +310,7 @@ { struct us_data *us = (struct us_data *)__us; int action; + unsigned long flags; lock_kernel(); @@ -369,7 +370,9 @@ US_DEBUGP("UNKNOWN data direction\n"); us->srb->result = DID_ERROR << 16; set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&io_request_lock, flags); us->srb->scsi_done(us->srb); + spin_unlock_irqrestore(&io_request_lock, flags); us->srb = NULL; break; } @@ -384,7 +387,9 @@ us->srb->result = DID_BAD_TARGET << 16; set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&io_request_lock, flags); us->srb->scsi_done(us->srb); + spin_unlock_irqrestore(&io_request_lock, flags); us->srb = NULL; break; } @@ -395,7 +400,9 @@ us->srb->result = DID_BAD_TARGET << 16; set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&io_request_lock, flags); us->srb->scsi_done(us->srb); + spin_unlock_irqrestore(&io_request_lock, flags); us->srb = NULL; break; } @@ -407,7 +414,9 @@ us->srb->result = GOOD << 1; set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&io_request_lock, flags); us->srb->scsi_done(us->srb); + spin_unlock_irqrestore(&io_request_lock, flags); us->srb = NULL; break; } @@ -468,7 +477,9 @@ US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&io_request_lock, flags); us->srb->scsi_done(us->srb); + spin_unlock_irqrestore(&io_request_lock, flags); } else { US_DEBUGP("scsi command aborted\n"); set_current_state(TASK_INTERRUPTIBLE); diff -uNr linux-2.4.20/drivers/usb/usb-ohci.c linux-2.4.20-ben6/drivers/usb/usb-ohci.c --- linux-2.4.20/drivers/usb/usb-ohci.c 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.20-ben6/drivers/usb/usb-ohci.c 2003-02-16 20:21:03.000000000 +0100 @@ -489,12 +489,16 @@ usb_pipeout (urb->pipe) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - urb->complete (urb); - + if (urb->interval == 0) { + urb_rm_priv (urb); + urb->complete (urb); + break; + } /* implicitly requeued */ - urb->actual_length = 0; - urb->status = -EINPROGRESS; - td_submit_urb (urb); + urb->complete (urb); + urb->actual_length = 0; + urb->status = -EINPROGRESS; + td_submit_urb (urb); break; case PIPE_ISOCHRONOUS: @@ -709,7 +713,8 @@ list_add (&urb->urb_list, entry); /* drive timeouts by SF (messy, but works) */ - writel (OHCI_INTR_SF, &ohci->regs->intrenable); + if (!ohci->sleeping) + writel (OHCI_INTR_SF, &ohci->regs->intrenable); } #endif @@ -1002,6 +1007,7 @@ case PIPE_CONTROL: ed->hwNextED = 0; if (ohci->ed_controltail == NULL) { + io_barrier(); writel (ed->dma, &ohci->regs->ed_controlhead); } else { ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma); @@ -1010,6 +1016,7 @@ if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && !ohci->ed_rm_list[1] && !ohci->sleeping) { ohci->hc_control |= OHCI_CTRL_CLE; + io_barrier(); writel (ohci->hc_control, &ohci->regs->control); } ohci->ed_controltail = edi; @@ -1018,6 +1025,7 @@ case PIPE_BULK: ed->hwNextED = 0; if (ohci->ed_bulktail == NULL) { + io_barrier(); writel (ed->dma, &ohci->regs->ed_bulkhead); } else { ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma); @@ -1026,6 +1034,7 @@ if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && !ohci->ed_rm_list[1] && !ohci->sleeping) { ohci->hc_control |= OHCI_CTRL_BLE; + io_barrier(); writel (ohci->hc_control, &ohci->regs->control); } ohci->ed_bulktail = edi; @@ -1118,7 +1127,8 @@ if (ed->ed_prev == NULL) { if (!ed->hwNextED) { ohci->hc_control &= ~OHCI_CTRL_CLE; - writel (ohci->hc_control, &ohci->regs->control); + if (!ohci->sleeping) + writel (ohci->hc_control, &ohci->regs->control); } writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead); } else { @@ -1135,7 +1145,8 @@ if (ed->ed_prev == NULL) { if (!ed->hwNextED) { ohci->hc_control &= ~OHCI_CTRL_BLE; - writel (ohci->hc_control, &ohci->regs->control); + if (!ohci->sleeping) + writel (ohci->hc_control, &ohci->regs->control); } writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead); } else { @@ -1264,16 +1275,19 @@ return; ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP); + io_barrier(); if (!ohci->disabled) { switch (ed->type) { case PIPE_CONTROL: /* stop control list */ ohci->hc_control &= ~OHCI_CTRL_CLE; - writel (ohci->hc_control, &ohci->regs->control); + if (!ohci->sleeping) + writel (ohci->hc_control, &ohci->regs->control); break; case PIPE_BULK: /* stop bulk list */ ohci->hc_control &= ~OHCI_CTRL_BLE; - writel (ohci->hc_control, &ohci->regs->control); + if (!ohci->sleeping) + writel (ohci->hc_control, &ohci->regs->control); break; } } @@ -1404,7 +1418,7 @@ } if (!ohci->sleeping) { - wmb(); + io_barrier(); writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ } break; @@ -1432,7 +1446,7 @@ TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; td_fill (ohci, info, data, 0, urb, cnt++); if (!ohci->sleeping) { - wmb(); + io_barrier(); writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ } break; @@ -1539,6 +1553,7 @@ td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0; ohci->hcca->done_head = 0; + wmb(); while (td_list_hc) { td_list = dma_to_td (ohci, td_list_hc); @@ -1647,6 +1662,7 @@ /* maybe reenable control and bulk lists */ if (!ohci->disabled) { + io_barrier(); if (ctrl) /* reset control list */ writel (0, &ohci->regs->ed_controlcurrent); if (bulk) /* reset bulk list */ @@ -2301,6 +2317,10 @@ struct ohci_regs * regs = ohci->regs; int ints; + /* Sanity check */ + if (ohci->sleeping) + return; + /* avoid (slow) readl if only WDH happened */ if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { @@ -2694,6 +2714,12 @@ info ("USB suspend: usb-%s", dev->slot_name); ohci->sleeping = 1; +#ifdef CONFIG_PMAC_PBOOK + if (_machine == _MACH_Pmac) + disable_irq (ohci->irq); + /* else, 2.4 assumes shared irqs -- don't disable */ +#endif + /* First stop processing */ spin_lock_irqsave (&usb_ed_lock, flags); ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); @@ -2707,11 +2733,6 @@ if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) mdelay (1); -#ifdef CONFIG_PMAC_PBOOK - if (_machine == _MACH_Pmac) - disable_irq (ohci->irq); - /* else, 2.4 assumes shared irqs -- don't disable */ -#endif /* Enable remote wakeup */ writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable); diff -uNr linux-2.4.20/drivers/usb/usb-ohci.h linux-2.4.20-ben6/drivers/usb/usb-ohci.h --- linux-2.4.20/drivers/usb/usb-ohci.h 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.20-ben6/drivers/usb/usb-ohci.h 2003-02-16 20:20:40.000000000 +0100 @@ -58,7 +58,7 @@ dma_addr_t dma; __u32 unused[3]; -} __attribute((aligned(16))); +} __attribute((aligned(32))); typedef struct ed ed_t; @@ -568,7 +568,7 @@ return -ENOMEM; ohci->dev_cache = pci_pool_create ("ohci_dev", ohci->ohci_dev, sizeof (struct ohci_device), - 16 /* byte alignment */, + 32 /* byte alignment */, 0 /* no page-crossing issues */, GFP_KERNEL | OHCI_MEM_FLAGS); if (!ohci->dev_cache) diff -uNr linux-2.4.20/drivers/video/Config.in linux-2.4.20-ben6/drivers/video/Config.in --- linux-2.4.20/drivers/video/Config.in 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.20-ben6/drivers/video/Config.in 2003-02-16 20:20:01.000000000 +0100 @@ -73,7 +73,7 @@ dep_bool ' Apple "valkyrie" display support' CONFIG_FB_VALKYRIE $CONFIG_ALL_PPC bool ' Chips 65550 display support' CONFIG_FB_CT65550 bool ' IMS Twin Turbo display support' CONFIG_FB_IMSTT - bool ' S3 Trio display support' CONFIG_FB_S3TRIO + dep_bool ' S3 Trio display support' CONFIG_FB_S3TRIO $CONFIG_ALL_PPC tristate ' VGA 16-color graphics console' CONFIG_FB_VGA16 fi if [ "$CONFIG_PARISC" = "y" ]; then diff -uNr linux-2.4.20/drivers/video/aty/atyfb.h linux-2.4.20-ben6/drivers/video/aty/atyfb.h --- linux-2.4.20/drivers/video/aty/atyfb.h 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.20-ben6/drivers/video/aty/atyfb.h 2003-02-16 20:21:06.000000000 +0100 @@ -124,6 +124,7 @@ #endif } fbcon_cmap; u8 blitter_may_be_busy; + int asleep; #ifdef __sparc__ u8 mmaped; int open; diff -uNr linux-2.4.20/drivers/video/aty/atyfb_base.c linux-2.4.20-ben6/drivers/video/aty/atyfb_base.c --- linux-2.4.20/drivers/video/aty/atyfb_base.c 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.20-ben6/drivers/video/aty/atyfb_base.c 2003-02-16 20:20:23.000000000 +0100 @@ -748,6 +748,8 @@ info->current_par = *par; + if (info->asleep) + return; if (info->blitter_may_be_busy) wait_for_idle(info); tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); @@ -1192,6 +1194,10 @@ return -EINVAL; par->crtc.xoffset = xoffset; par->crtc.yoffset = yoffset; + + if (info->asleep) + return 0; + set_off_pitch(par, info); return 0; } @@ -1660,6 +1666,7 @@ } break; case PBOOK_SLEEP_NOW: + acquire_console_sem(); if (currcon >= 0) fb_display[currcon].dispsw = &fbcon_dummy; if (info->blitter_may_be_busy) @@ -1675,11 +1682,14 @@ /* Blank display and LCD */ atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); + info->asleep = 1; /* Set chip to "suspend" mode */ result = aty_power_mgmt(1, info); + release_console_sem(); break; case PBOOK_WAKE: + acquire_console_sem(); /* Wakeup chip */ result = aty_power_mgmt(0, info); @@ -1690,6 +1700,7 @@ vfree(info->save_framebuffer); info->save_framebuffer = 0; } + info->asleep = 0; /* Restore display */ if (currcon >= 0) { atyfb_set_dispsw(&fb_display[currcon], @@ -1697,6 +1708,11 @@ info->current_par.accel_flags & FB_ACCELF_TEXT); } atyfbcon_blank(0, (struct fb_info *)info); + /* XXX We may want to re-call atyfb_set_par and make + * sure panning & cursor & palette are correct as we + * skipped any change to these during suspend. + */ + release_console_sem(); break; } } @@ -2720,6 +2736,9 @@ struct fb_info_aty *info = (struct fb_info_aty *)fb; u8 gen_cntl; + if (info->asleep) + return; + #ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && blank) set_backlight_enable(0); @@ -2792,23 +2811,25 @@ info->palette[regno].red = red; info->palette[regno].green = green; info->palette[regno].blue = blue; - i = aty_ld_8(DAC_CNTL, info) & 0xfc; - if (M64_HAS(EXTRA_BRIGHT)) - i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ - aty_st_8(DAC_CNTL, i, info); - aty_st_8(DAC_MASK, 0xff, info); - scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0; + if (!info->asleep) { + i = aty_ld_8(DAC_CNTL, info) & 0xfc; + if (M64_HAS(EXTRA_BRIGHT)) + i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ + aty_st_8(DAC_CNTL, i, info); + aty_st_8(DAC_MASK, 0xff, info); + scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0; #ifdef CONFIG_ATARI - out_8(&info->aty_cmap_regs->windex, regno << scale); - out_8(&info->aty_cmap_regs->lut, red); - out_8(&info->aty_cmap_regs->lut, green); - out_8(&info->aty_cmap_regs->lut, blue); + out_8(&info->aty_cmap_regs->windex, regno << scale); + out_8(&info->aty_cmap_regs->lut, red); + out_8(&info->aty_cmap_regs->lut, green); + out_8(&info->aty_cmap_regs->lut, blue); #else - writeb(regno << scale, &info->aty_cmap_regs->windex); - writeb(red, &info->aty_cmap_regs->lut); - writeb(green, &info->aty_cmap_regs->lut); - writeb(blue, &info->aty_cmap_regs->lut); + writeb(regno << scale, &info->aty_cmap_regs->windex); + writeb(red, &info->aty_cmap_regs->lut); + writeb(green, &info->aty_cmap_regs->lut); + writeb(blue, &info->aty_cmap_regs->lut); #endif + } if (regno < 16) switch (info->current_par.crtc.bpp) { #ifdef FBCON_HAS_CFB16 @@ -2859,6 +2880,9 @@ struct vc_data *conp = p->conp; u32 yres, yoffset, sy, height; + if (info->asleep) + return 0; + yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1; yoffset = fb_display[con].var.yoffset; diff -uNr linux-2.4.20/drivers/video/aty/mach64_cursor.c linux-2.4.20-ben6/drivers/video/aty/mach64_cursor.c --- linux-2.4.20/drivers/video/aty/mach64_cursor.c 2001-10-25 22:53:52.000000000 +0200 +++ linux-2.4.20-ben6/drivers/video/aty/mach64_cursor.c 2003-02-16 20:20:39.000000000 +0100 @@ -54,7 +54,7 @@ const u8 *blue = cursor_color_map; int i; - if (!c) + if (!c || fb->asleep) return; #ifdef __sparc__ @@ -81,7 +81,7 @@ u8 *ram, m, b; int x, y; - if (!c) + if (!c || fb->asleep) return; #ifdef __sparc__ @@ -118,7 +118,7 @@ u16 xoff, yoff; int x, y; - if (!c) + if (!c || fb->asleep) return; #ifdef __sparc__ @@ -297,8 +297,10 @@ c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j)); } - aty_set_cursor_color(fb); - aty_set_cursor_shape(fb); + if (!fb->asleep) { + aty_set_cursor_color(fb); + aty_set_cursor_shape(fb); + } } return 1; } diff -uNr linux-2.4.20/drivers/video/aty128fb.c linux-2.4.20-ben6/drivers/video/aty128fb.c --- linux-2.4.20/drivers/video/aty128fb.c 2002-11-29 00:53:15.000000000 +0100 +++ linux-2.4.20-ben6/drivers/video/aty128fb.c 2003-02-16 20:20:25.000000000 +0100 @@ -55,7 +55,7 @@ #include #include -#ifdef CONFIG_PPC +#ifdef CONFIG_ALL_PPC #include #include #include