Loading Documentation/sparc/sbus_drivers.txt +65 −30 Original line number Diff line number Diff line Loading @@ -25,42 +25,84 @@ the bits necessary to run your device. The most commonly used members of this structure, and their typical usage, will be detailed below. Here is how probing is performed by an SBUS driver under Linux: Here is a piece of skeleton code for perofming a device probe in an SBUS driverunder Linux: static void init_one_mydevice(struct sbus_dev *sdev) static int __devinit mydevice_probe_one(struct sbus_dev *sdev) { struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL); if (!mp) return -ENODEV; ... dev_set_drvdata(&sdev->ofdev.dev, mp); return 0; ... } static int mydevice_match(struct sbus_dev *sdev) static int __devinit mydevice_probe(struct of_device *dev, const struct of_device_id *match) { if (some_criteria(sdev)) return 1; return 0; struct sbus_dev *sdev = to_sbus_device(&dev->dev); return mydevice_probe_one(sdev); } static void mydevice_probe(void) static int __devexit mydevice_remove(struct of_device *dev) { struct sbus_bus *sbus; struct sbus_dev *sdev; struct sbus_dev *sdev = to_sbus_device(&dev->dev); struct mydevice *mp = dev_get_drvdata(&dev->dev); for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { if (mydevice_match(sdev)) init_one_mydevice(sdev); return mydevice_remove_one(sdev, mp); } static struct of_device_id mydevice_match[] = { { .name = "mydevice", }, {}, }; MODULE_DEVICE_TABLE(of, mydevice_match); static struct of_platform_driver mydevice_driver = { .name = "mydevice", .match_table = mydevice_match, .probe = mydevice_probe, .remove = __devexit_p(mydevice_remove), }; static int __init mydevice_init(void) { return of_register_driver(&mydevice_driver, &sbus_bus_type); } static void __exit mydevice_exit(void) { of_unregister_driver(&mydevice_driver); } All this does is walk through all SBUS devices in the system, checks each to see if it is of the type which your driver is written for, and if so it calls the init routine to attach the device and prepare to drive it. module_init(mydevice_init); module_exit(mydevice_exit); "init_one_mydevice" might do things like allocate software state structures, map in I/O registers, place the hardware into an initialized state, etc. The mydevice_match table is a series of entries which describes what SBUS devices your driver is meant for. In the simplest case you specify a string for the 'name' field. Every SBUS device with a 'name' property matching your string will be passed one-by-one to your .probe method. You should store away your device private state structure pointer in the drvdata area so that you can retrieve it later on in your .remove method. Any memory allocated, registers mapped, IRQs registered, etc. must be undone by your .remove method so that all resources of your device are relased by the time it returns. You should _NOT_ use the for_each_sbus(), for_each_sbusdev(), and for_all_sbusdev() interfaces. They are deprecated, will be removed, and no new driver should reference them ever. Mapping and Accessing I/O Registers Loading Loading @@ -263,10 +305,3 @@ discussed above and plus it handles both PCI and SBUS boards. Lance driver abuses consistent mappings for data transfer. It is a nifty trick which we do not particularly recommend... Just check it out and know that it's legal. Bad examples, do NOT use drivers/video/cgsix.c This one uses result of sbus_ioremap as if it is an address. This does NOT work on sparc64 and therefore is broken. We will convert it at a later date. arch/arm/kernel/iwmmxt.S +1 −1 Original line number Diff line number Diff line Loading @@ -273,7 +273,7 @@ ENTRY(iwmmxt_task_restore) * * r0 = previous task_struct pointer (must be preserved) * r1 = previous thread_info pointer * r2 = next thread_info.cpu_domain pointer (must be preserved) * r2 = next thread_info pointer (must be preserved) * * Called only from __switch_to with task preemption disabled. * No need to care about preserving r4 and above. Loading arch/arm/kernel/signal.c +82 −125 Original line number Diff line number Diff line Loading @@ -134,17 +134,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, #ifdef CONFIG_IWMMXT /* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */ #define IWMMXT_STORAGE_SIZE (0x98 + 8) #define IWMMXT_MAGIC0 0x12ef842a #define IWMMXT_MAGIC1 0x1c07ca71 struct iwmmxt_sigframe { unsigned long magic0; unsigned long magic1; unsigned long storage[0x98/4]; }; static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) { char kbuf[sizeof(*frame) + 8]; Loading @@ -152,8 +141,8 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) /* the iWMMXt context must be 64 bit aligned */ kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); kframe->magic0 = IWMMXT_MAGIC0; kframe->magic1 = IWMMXT_MAGIC1; kframe->magic = IWMMXT_MAGIC; kframe->size = IWMMXT_STORAGE_SIZE; iwmmxt_task_copy(current_thread_info(), &kframe->storage); return __copy_to_user(frame, kframe, sizeof(*frame)); } Loading @@ -167,8 +156,8 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); if (__copy_from_user(kframe, frame, sizeof(*frame))) return -1; if (kframe->magic0 != IWMMXT_MAGIC0 || kframe->magic1 != IWMMXT_MAGIC1) if (kframe->magic != IWMMXT_MAGIC || kframe->size != IWMMXT_STORAGE_SIZE) return -1; iwmmxt_task_restore(current_thread_info(), &kframe->storage); return 0; Loading @@ -176,71 +165,62 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) #endif /* * Auxiliary signal frame. This saves stuff like FP state. * The layout of this structure is not part of the user ABI. */ struct aux_sigframe { #ifdef CONFIG_IWMMXT struct iwmmxt_sigframe iwmmxt; #endif #ifdef CONFIG_VFP union vfp_state vfp; #endif }; /* * Do a signal return; undo the signal stack. These are aligned to 64-bit. */ struct sigframe { struct sigcontext sc; unsigned long extramask[_NSIG_WORDS-1]; struct ucontext uc; unsigned long retcode[2]; struct aux_sigframe aux __attribute__((aligned(8))); }; struct rt_sigframe { struct siginfo __user *pinfo; void __user *puc; struct siginfo info; struct ucontext uc; unsigned long retcode[2]; struct aux_sigframe aux __attribute__((aligned(8))); struct sigframe sig; }; static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, struct aux_sigframe __user *aux) static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) { int err = 0; struct aux_sigframe __user *aux; sigset_t set; int err; err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); if (err == 0) { sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } __get_user_error(regs->ARM_r0, &sc->arm_r0, err); __get_user_error(regs->ARM_r1, &sc->arm_r1, err); __get_user_error(regs->ARM_r2, &sc->arm_r2, err); __get_user_error(regs->ARM_r3, &sc->arm_r3, err); __get_user_error(regs->ARM_r4, &sc->arm_r4, err); __get_user_error(regs->ARM_r5, &sc->arm_r5, err); __get_user_error(regs->ARM_r6, &sc->arm_r6, err); __get_user_error(regs->ARM_r7, &sc->arm_r7, err); __get_user_error(regs->ARM_r8, &sc->arm_r8, err); __get_user_error(regs->ARM_r9, &sc->arm_r9, err); __get_user_error(regs->ARM_r10, &sc->arm_r10, err); __get_user_error(regs->ARM_fp, &sc->arm_fp, err); __get_user_error(regs->ARM_ip, &sc->arm_ip, err); __get_user_error(regs->ARM_sp, &sc->arm_sp, err); __get_user_error(regs->ARM_lr, &sc->arm_lr, err); __get_user_error(regs->ARM_pc, &sc->arm_pc, err); __get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); __get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); __get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); __get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); __get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); __get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); __get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); __get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); __get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); __get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); __get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); __get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); __get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); __get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); __get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); __get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); __get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); err |= !valid_user_regs(regs); aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; #ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) err |= restore_iwmmxt_context(&aux->iwmmxt); #endif #ifdef CONFIG_VFP // if (err == 0) // err |= vfp_restore_state(&aux->vfp); // err |= vfp_restore_state(&sf->aux.vfp); #endif return err; Loading @@ -249,7 +229,6 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, asmlinkage int sys_sigreturn(struct pt_regs *regs) { struct sigframe __user *frame; sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; Loading @@ -266,19 +245,8 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask)))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->sc, &frame->aux)) if (restore_sigframe(regs, frame)) goto badframe; /* Send SIGTRAP if we're single-stepping */ Loading @@ -297,7 +265,6 @@ badframe: asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe __user *frame; sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; Loading @@ -314,19 +281,11 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux)) if (restore_sigframe(regs, &frame->sig)) goto badframe; if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) goto badframe; /* Send SIGTRAP if we're single-stepping */ Loading @@ -343,42 +302,46 @@ badframe: } static int setup_sigcontext(struct sigcontext __user *sc, struct aux_sigframe __user *aux, struct pt_regs *regs, unsigned long mask) setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { struct aux_sigframe __user *aux; int err = 0; __put_user_error(regs->ARM_r0, &sc->arm_r0, err); __put_user_error(regs->ARM_r1, &sc->arm_r1, err); __put_user_error(regs->ARM_r2, &sc->arm_r2, err); __put_user_error(regs->ARM_r3, &sc->arm_r3, err); __put_user_error(regs->ARM_r4, &sc->arm_r4, err); __put_user_error(regs->ARM_r5, &sc->arm_r5, err); __put_user_error(regs->ARM_r6, &sc->arm_r6, err); __put_user_error(regs->ARM_r7, &sc->arm_r7, err); __put_user_error(regs->ARM_r8, &sc->arm_r8, err); __put_user_error(regs->ARM_r9, &sc->arm_r9, err); __put_user_error(regs->ARM_r10, &sc->arm_r10, err); __put_user_error(regs->ARM_fp, &sc->arm_fp, err); __put_user_error(regs->ARM_ip, &sc->arm_ip, err); __put_user_error(regs->ARM_sp, &sc->arm_sp, err); __put_user_error(regs->ARM_lr, &sc->arm_lr, err); __put_user_error(regs->ARM_pc, &sc->arm_pc, err); __put_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); __put_user_error(current->thread.trap_no, &sc->trap_no, err); __put_user_error(current->thread.error_code, &sc->error_code, err); __put_user_error(current->thread.address, &sc->fault_address, err); __put_user_error(mask, &sc->oldmask, err); __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); __put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); __put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); __put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); __put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); __put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); __put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); __put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); __put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); __put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); __put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); __put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); __put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); __put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); __put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); __put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); __put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err); __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err); __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err); __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; #ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) err |= preserve_iwmmxt_context(&aux->iwmmxt); #endif #ifdef CONFIG_VFP // if (err == 0) // err |= vfp_save_state(&aux->vfp); // err |= vfp_save_state(&sf->aux.vfp); #endif __put_user_error(0, &aux->end_magic, err); return err; } Loading Loading @@ -487,13 +450,12 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg if (!frame) return 1; err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]); if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } /* * Set uc.uc_flags to a value which sc.trap_no would never have. */ __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err); err |= setup_sigframe(frame, regs, set); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); Loading @@ -511,25 +473,20 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, if (!frame) return 1; __put_user_error(&frame->info, &frame->pinfo, err); __put_user_error(&frame->uc, &frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); __put_user_error(0, &frame->uc.uc_flags, err); __put_user_error(NULL, &frame->uc.uc_link, err); __put_user_error(0, &frame->sig.uc.uc_flags, err); __put_user_error(NULL, &frame->sig.uc.uc_link, err); memset(&stack, 0, sizeof(stack)); stack.ss_sp = (void __user *)current->sas_ss_sp; stack.ss_flags = sas_ss_flags(regs->ARM_sp); stack.ss_size = current->sas_ss_size; err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack)); err |= setup_sigframe(&frame->sig, regs, set); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); err = setup_return(regs, ka, frame->sig.retcode, frame, usig); if (err == 0) { /* Loading @@ -538,7 +495,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06 */ regs->ARM_r1 = (unsigned long)&frame->info; regs->ARM_r2 = (unsigned long)&frame->uc; regs->ARM_r2 = (unsigned long)&frame->sig.uc; } return err; Loading arch/arm/mach-ep93xx/Makefile +1 −1 Original line number Diff line number Diff line # # Makefile for the linux kernel. # obj-y := core.o obj-y := core.o clock.o obj-m := obj-n := obj- := Loading arch/arm/mach-ep93xx/clock.c 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * arch/arm/mach-ep93xx/clock.c * Clock control for Cirrus EP93xx chips. * * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. */ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/string.h> #include <asm/div64.h> #include <asm/hardware.h> #include <asm/io.h> struct clk { char *name; unsigned long rate; int users; u32 enable_reg; u32 enable_mask; }; static struct clk clk_pll1 = { .name = "pll1", }; static struct clk clk_f = { .name = "fclk", }; static struct clk clk_h = { .name = "hclk", }; static struct clk clk_p = { .name = "pclk", }; static struct clk clk_pll2 = { .name = "pll2", }; static struct clk clk_usb_host = { .name = "usb_host", .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, }; static struct clk *clocks[] = { &clk_pll1, &clk_f, &clk_h, &clk_p, &clk_pll2, &clk_usb_host, }; struct clk *clk_get(struct device *dev, const char *id) { int i; for (i = 0; i < ARRAY_SIZE(clocks); i++) { if (!strcmp(clocks[i]->name, id)) return clocks[i]; } return ERR_PTR(-ENOENT); } int clk_enable(struct clk *clk) { if (!clk->users++ && clk->enable_reg) { u32 value; value = __raw_readl(clk->enable_reg); __raw_writel(value | clk->enable_mask, clk->enable_reg); } return 0; } void clk_disable(struct clk *clk) { if (!--clk->users && clk->enable_reg) { u32 value; value = __raw_readl(clk->enable_reg); __raw_writel(value & ~clk->enable_mask, clk->enable_reg); } } unsigned long clk_get_rate(struct clk *clk) { return clk->rate; } void clk_put(struct clk *clk) { } static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; static char pclk_divisors[] = { 1, 2, 4, 8 }; /* * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS */ static unsigned long calc_pll_rate(u32 config_word) { unsigned long long rate; int i; rate = 14745600; rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */ rate >>= 1; return (unsigned long)rate; } void ep93xx_clock_init(void) { u32 value; value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); if (!(value & 0x00800000)) { /* PLL1 bypassed? */ clk_pll1.rate = 14745600; } else { clk_pll1.rate = calc_pll_rate(value); } clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7]; clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7]; clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3]; value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); if (!(value & 0x00080000)) { /* PLL2 bypassed? */ clk_pll2.rate = 14745600; } else if (value & 0x00040000) { /* PLL2 enabled? */ clk_pll2.rate = calc_pll_rate(value); } else { clk_pll2.rate = 0; } clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1); printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n", clk_pll1.rate / 1000000, clk_pll2.rate / 1000000); printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", clk_f.rate / 1000000, clk_h.rate / 1000000, clk_p.rate / 1000000); } Loading
Documentation/sparc/sbus_drivers.txt +65 −30 Original line number Diff line number Diff line Loading @@ -25,42 +25,84 @@ the bits necessary to run your device. The most commonly used members of this structure, and their typical usage, will be detailed below. Here is how probing is performed by an SBUS driver under Linux: Here is a piece of skeleton code for perofming a device probe in an SBUS driverunder Linux: static void init_one_mydevice(struct sbus_dev *sdev) static int __devinit mydevice_probe_one(struct sbus_dev *sdev) { struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL); if (!mp) return -ENODEV; ... dev_set_drvdata(&sdev->ofdev.dev, mp); return 0; ... } static int mydevice_match(struct sbus_dev *sdev) static int __devinit mydevice_probe(struct of_device *dev, const struct of_device_id *match) { if (some_criteria(sdev)) return 1; return 0; struct sbus_dev *sdev = to_sbus_device(&dev->dev); return mydevice_probe_one(sdev); } static void mydevice_probe(void) static int __devexit mydevice_remove(struct of_device *dev) { struct sbus_bus *sbus; struct sbus_dev *sdev; struct sbus_dev *sdev = to_sbus_device(&dev->dev); struct mydevice *mp = dev_get_drvdata(&dev->dev); for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { if (mydevice_match(sdev)) init_one_mydevice(sdev); return mydevice_remove_one(sdev, mp); } static struct of_device_id mydevice_match[] = { { .name = "mydevice", }, {}, }; MODULE_DEVICE_TABLE(of, mydevice_match); static struct of_platform_driver mydevice_driver = { .name = "mydevice", .match_table = mydevice_match, .probe = mydevice_probe, .remove = __devexit_p(mydevice_remove), }; static int __init mydevice_init(void) { return of_register_driver(&mydevice_driver, &sbus_bus_type); } static void __exit mydevice_exit(void) { of_unregister_driver(&mydevice_driver); } All this does is walk through all SBUS devices in the system, checks each to see if it is of the type which your driver is written for, and if so it calls the init routine to attach the device and prepare to drive it. module_init(mydevice_init); module_exit(mydevice_exit); "init_one_mydevice" might do things like allocate software state structures, map in I/O registers, place the hardware into an initialized state, etc. The mydevice_match table is a series of entries which describes what SBUS devices your driver is meant for. In the simplest case you specify a string for the 'name' field. Every SBUS device with a 'name' property matching your string will be passed one-by-one to your .probe method. You should store away your device private state structure pointer in the drvdata area so that you can retrieve it later on in your .remove method. Any memory allocated, registers mapped, IRQs registered, etc. must be undone by your .remove method so that all resources of your device are relased by the time it returns. You should _NOT_ use the for_each_sbus(), for_each_sbusdev(), and for_all_sbusdev() interfaces. They are deprecated, will be removed, and no new driver should reference them ever. Mapping and Accessing I/O Registers Loading Loading @@ -263,10 +305,3 @@ discussed above and plus it handles both PCI and SBUS boards. Lance driver abuses consistent mappings for data transfer. It is a nifty trick which we do not particularly recommend... Just check it out and know that it's legal. Bad examples, do NOT use drivers/video/cgsix.c This one uses result of sbus_ioremap as if it is an address. This does NOT work on sparc64 and therefore is broken. We will convert it at a later date.
arch/arm/kernel/iwmmxt.S +1 −1 Original line number Diff line number Diff line Loading @@ -273,7 +273,7 @@ ENTRY(iwmmxt_task_restore) * * r0 = previous task_struct pointer (must be preserved) * r1 = previous thread_info pointer * r2 = next thread_info.cpu_domain pointer (must be preserved) * r2 = next thread_info pointer (must be preserved) * * Called only from __switch_to with task preemption disabled. * No need to care about preserving r4 and above. Loading
arch/arm/kernel/signal.c +82 −125 Original line number Diff line number Diff line Loading @@ -134,17 +134,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, #ifdef CONFIG_IWMMXT /* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */ #define IWMMXT_STORAGE_SIZE (0x98 + 8) #define IWMMXT_MAGIC0 0x12ef842a #define IWMMXT_MAGIC1 0x1c07ca71 struct iwmmxt_sigframe { unsigned long magic0; unsigned long magic1; unsigned long storage[0x98/4]; }; static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) { char kbuf[sizeof(*frame) + 8]; Loading @@ -152,8 +141,8 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) /* the iWMMXt context must be 64 bit aligned */ kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); kframe->magic0 = IWMMXT_MAGIC0; kframe->magic1 = IWMMXT_MAGIC1; kframe->magic = IWMMXT_MAGIC; kframe->size = IWMMXT_STORAGE_SIZE; iwmmxt_task_copy(current_thread_info(), &kframe->storage); return __copy_to_user(frame, kframe, sizeof(*frame)); } Loading @@ -167,8 +156,8 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); if (__copy_from_user(kframe, frame, sizeof(*frame))) return -1; if (kframe->magic0 != IWMMXT_MAGIC0 || kframe->magic1 != IWMMXT_MAGIC1) if (kframe->magic != IWMMXT_MAGIC || kframe->size != IWMMXT_STORAGE_SIZE) return -1; iwmmxt_task_restore(current_thread_info(), &kframe->storage); return 0; Loading @@ -176,71 +165,62 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) #endif /* * Auxiliary signal frame. This saves stuff like FP state. * The layout of this structure is not part of the user ABI. */ struct aux_sigframe { #ifdef CONFIG_IWMMXT struct iwmmxt_sigframe iwmmxt; #endif #ifdef CONFIG_VFP union vfp_state vfp; #endif }; /* * Do a signal return; undo the signal stack. These are aligned to 64-bit. */ struct sigframe { struct sigcontext sc; unsigned long extramask[_NSIG_WORDS-1]; struct ucontext uc; unsigned long retcode[2]; struct aux_sigframe aux __attribute__((aligned(8))); }; struct rt_sigframe { struct siginfo __user *pinfo; void __user *puc; struct siginfo info; struct ucontext uc; unsigned long retcode[2]; struct aux_sigframe aux __attribute__((aligned(8))); struct sigframe sig; }; static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, struct aux_sigframe __user *aux) static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) { int err = 0; struct aux_sigframe __user *aux; sigset_t set; int err; err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); if (err == 0) { sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } __get_user_error(regs->ARM_r0, &sc->arm_r0, err); __get_user_error(regs->ARM_r1, &sc->arm_r1, err); __get_user_error(regs->ARM_r2, &sc->arm_r2, err); __get_user_error(regs->ARM_r3, &sc->arm_r3, err); __get_user_error(regs->ARM_r4, &sc->arm_r4, err); __get_user_error(regs->ARM_r5, &sc->arm_r5, err); __get_user_error(regs->ARM_r6, &sc->arm_r6, err); __get_user_error(regs->ARM_r7, &sc->arm_r7, err); __get_user_error(regs->ARM_r8, &sc->arm_r8, err); __get_user_error(regs->ARM_r9, &sc->arm_r9, err); __get_user_error(regs->ARM_r10, &sc->arm_r10, err); __get_user_error(regs->ARM_fp, &sc->arm_fp, err); __get_user_error(regs->ARM_ip, &sc->arm_ip, err); __get_user_error(regs->ARM_sp, &sc->arm_sp, err); __get_user_error(regs->ARM_lr, &sc->arm_lr, err); __get_user_error(regs->ARM_pc, &sc->arm_pc, err); __get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); __get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); __get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); __get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); __get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); __get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); __get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); __get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); __get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); __get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); __get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); __get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); __get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); __get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); __get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); __get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); __get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); err |= !valid_user_regs(regs); aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; #ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) err |= restore_iwmmxt_context(&aux->iwmmxt); #endif #ifdef CONFIG_VFP // if (err == 0) // err |= vfp_restore_state(&aux->vfp); // err |= vfp_restore_state(&sf->aux.vfp); #endif return err; Loading @@ -249,7 +229,6 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, asmlinkage int sys_sigreturn(struct pt_regs *regs) { struct sigframe __user *frame; sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; Loading @@ -266,19 +245,8 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask)))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->sc, &frame->aux)) if (restore_sigframe(regs, frame)) goto badframe; /* Send SIGTRAP if we're single-stepping */ Loading @@ -297,7 +265,6 @@ badframe: asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe __user *frame; sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; Loading @@ -314,19 +281,11 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux)) if (restore_sigframe(regs, &frame->sig)) goto badframe; if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) goto badframe; /* Send SIGTRAP if we're single-stepping */ Loading @@ -343,42 +302,46 @@ badframe: } static int setup_sigcontext(struct sigcontext __user *sc, struct aux_sigframe __user *aux, struct pt_regs *regs, unsigned long mask) setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { struct aux_sigframe __user *aux; int err = 0; __put_user_error(regs->ARM_r0, &sc->arm_r0, err); __put_user_error(regs->ARM_r1, &sc->arm_r1, err); __put_user_error(regs->ARM_r2, &sc->arm_r2, err); __put_user_error(regs->ARM_r3, &sc->arm_r3, err); __put_user_error(regs->ARM_r4, &sc->arm_r4, err); __put_user_error(regs->ARM_r5, &sc->arm_r5, err); __put_user_error(regs->ARM_r6, &sc->arm_r6, err); __put_user_error(regs->ARM_r7, &sc->arm_r7, err); __put_user_error(regs->ARM_r8, &sc->arm_r8, err); __put_user_error(regs->ARM_r9, &sc->arm_r9, err); __put_user_error(regs->ARM_r10, &sc->arm_r10, err); __put_user_error(regs->ARM_fp, &sc->arm_fp, err); __put_user_error(regs->ARM_ip, &sc->arm_ip, err); __put_user_error(regs->ARM_sp, &sc->arm_sp, err); __put_user_error(regs->ARM_lr, &sc->arm_lr, err); __put_user_error(regs->ARM_pc, &sc->arm_pc, err); __put_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); __put_user_error(current->thread.trap_no, &sc->trap_no, err); __put_user_error(current->thread.error_code, &sc->error_code, err); __put_user_error(current->thread.address, &sc->fault_address, err); __put_user_error(mask, &sc->oldmask, err); __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); __put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); __put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); __put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); __put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); __put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); __put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); __put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); __put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); __put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); __put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); __put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); __put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); __put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); __put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); __put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); __put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err); __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err); __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err); __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; #ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) err |= preserve_iwmmxt_context(&aux->iwmmxt); #endif #ifdef CONFIG_VFP // if (err == 0) // err |= vfp_save_state(&aux->vfp); // err |= vfp_save_state(&sf->aux.vfp); #endif __put_user_error(0, &aux->end_magic, err); return err; } Loading Loading @@ -487,13 +450,12 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg if (!frame) return 1; err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]); if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } /* * Set uc.uc_flags to a value which sc.trap_no would never have. */ __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err); err |= setup_sigframe(frame, regs, set); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); Loading @@ -511,25 +473,20 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, if (!frame) return 1; __put_user_error(&frame->info, &frame->pinfo, err); __put_user_error(&frame->uc, &frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); __put_user_error(0, &frame->uc.uc_flags, err); __put_user_error(NULL, &frame->uc.uc_link, err); __put_user_error(0, &frame->sig.uc.uc_flags, err); __put_user_error(NULL, &frame->sig.uc.uc_link, err); memset(&stack, 0, sizeof(stack)); stack.ss_sp = (void __user *)current->sas_ss_sp; stack.ss_flags = sas_ss_flags(regs->ARM_sp); stack.ss_size = current->sas_ss_size; err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack)); err |= setup_sigframe(&frame->sig, regs, set); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); err = setup_return(regs, ka, frame->sig.retcode, frame, usig); if (err == 0) { /* Loading @@ -538,7 +495,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06 */ regs->ARM_r1 = (unsigned long)&frame->info; regs->ARM_r2 = (unsigned long)&frame->uc; regs->ARM_r2 = (unsigned long)&frame->sig.uc; } return err; Loading
arch/arm/mach-ep93xx/Makefile +1 −1 Original line number Diff line number Diff line # # Makefile for the linux kernel. # obj-y := core.o obj-y := core.o clock.o obj-m := obj-n := obj- := Loading
arch/arm/mach-ep93xx/clock.c 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * arch/arm/mach-ep93xx/clock.c * Clock control for Cirrus EP93xx chips. * * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. */ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/string.h> #include <asm/div64.h> #include <asm/hardware.h> #include <asm/io.h> struct clk { char *name; unsigned long rate; int users; u32 enable_reg; u32 enable_mask; }; static struct clk clk_pll1 = { .name = "pll1", }; static struct clk clk_f = { .name = "fclk", }; static struct clk clk_h = { .name = "hclk", }; static struct clk clk_p = { .name = "pclk", }; static struct clk clk_pll2 = { .name = "pll2", }; static struct clk clk_usb_host = { .name = "usb_host", .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, }; static struct clk *clocks[] = { &clk_pll1, &clk_f, &clk_h, &clk_p, &clk_pll2, &clk_usb_host, }; struct clk *clk_get(struct device *dev, const char *id) { int i; for (i = 0; i < ARRAY_SIZE(clocks); i++) { if (!strcmp(clocks[i]->name, id)) return clocks[i]; } return ERR_PTR(-ENOENT); } int clk_enable(struct clk *clk) { if (!clk->users++ && clk->enable_reg) { u32 value; value = __raw_readl(clk->enable_reg); __raw_writel(value | clk->enable_mask, clk->enable_reg); } return 0; } void clk_disable(struct clk *clk) { if (!--clk->users && clk->enable_reg) { u32 value; value = __raw_readl(clk->enable_reg); __raw_writel(value & ~clk->enable_mask, clk->enable_reg); } } unsigned long clk_get_rate(struct clk *clk) { return clk->rate; } void clk_put(struct clk *clk) { } static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; static char pclk_divisors[] = { 1, 2, 4, 8 }; /* * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS */ static unsigned long calc_pll_rate(u32 config_word) { unsigned long long rate; int i; rate = 14745600; rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */ rate >>= 1; return (unsigned long)rate; } void ep93xx_clock_init(void) { u32 value; value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); if (!(value & 0x00800000)) { /* PLL1 bypassed? */ clk_pll1.rate = 14745600; } else { clk_pll1.rate = calc_pll_rate(value); } clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7]; clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7]; clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3]; value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); if (!(value & 0x00080000)) { /* PLL2 bypassed? */ clk_pll2.rate = 14745600; } else if (value & 0x00040000) { /* PLL2 enabled? */ clk_pll2.rate = calc_pll_rate(value); } else { clk_pll2.rate = 0; } clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1); printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n", clk_pll1.rate / 1000000, clk_pll2.rate / 1000000); printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", clk_f.rate / 1000000, clk_h.rate / 1000000, clk_p.rate / 1000000); }