| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * ---------------------------------------------------------------------------- | |
| 3 | * "THE BEER-WARE LICENSE" (Revision 42): | |
| 4 | * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you | |
| 5 | * can do whatever you want with this stuff. If we meet some day, and you think | |
| 6 | * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp | |
| 7 | * ---------------------------------------------------------------------------- | |
| 8 | * | |
| 9 | * $FreeBSD: src/sys/i386/i386/elan-mmcr.c,v 1.6.2.1 2002/09/17 22:39:53 sam Exp $ | |
| 27dd53e3 | 10 | * $DragonFly: src/sys/platform/pc32/i386/elan-mmcr.c,v 1.10 2007/12/29 13:40:28 swildner Exp $ |
| 984263bc MD |
11 | * The AMD Elan sc520 is a system-on-chip gadget which is used in embedded |
| 12 | * kind of things, see www.soekris.com for instance, and it has a few quirks | |
| 13 | * we need to deal with. | |
| 14 | * Unfortunately we cannot identify the gadget by CPUID output because it | |
| 15 | * depends on strapping options and only the stepping field may be useful | |
| 16 | * and those are undocumented from AMDs side. | |
| 17 | * | |
| 18 | * So instead we recognize the on-chip host-PCI bridge and call back from | |
| 19 | * sys/i386/pci/pci_bus.c to here if we find it. | |
| 20 | */ | |
| 21 | ||
| 22 | #include <sys/param.h> | |
| 23 | #include <sys/systm.h> | |
| 24 | #include <sys/kernel.h> | |
| 25 | #include <sys/conf.h> | |
| fef8985e | 26 | #include <sys/device.h> |
| 984263bc MD |
27 | #include <sys/proc.h> |
| 28 | #include <sys/sysctl.h> | |
| 29 | #include <sys/time.h> | |
| 30 | ||
| 31 | #include <machine/md_var.h> | |
| 32 | ||
| 33 | #include <vm/vm.h> | |
| 34 | #include <vm/pmap.h> | |
| 35 | ||
| 36 | uint16_t *elan_mmcr; | |
| 37 | ||
| 88c4d2f6 | 38 | #if 0 |
| 984263bc MD |
39 | |
| 40 | static unsigned | |
| 41 | elan_get_timecount(struct timecounter *tc) | |
| 42 | { | |
| 43 | return (elan_mmcr[0xc84 / 2]); | |
| 44 | } | |
| 45 | ||
| 46 | static struct timecounter elan_timecounter = { | |
| 47 | elan_get_timecount, | |
| 48 | 0, | |
| 49 | 0xffff, | |
| 50 | 33333333 / 4, | |
| 51 | "ELAN" | |
| 52 | }; | |
| 53 | ||
| 88c4d2f6 MD |
54 | #endif |
| 55 | ||
| 984263bc MD |
56 | void |
| 57 | init_AMD_Elan_sc520(void) | |
| 58 | { | |
| 59 | u_int new; | |
| 60 | int i; | |
| 61 | ||
| 62 | if (bootverbose) | |
| 26be20a0 | 63 | kprintf("Doing h0h0magic for AMD Elan sc520\n"); |
| 984263bc MD |
64 | elan_mmcr = pmap_mapdev(0xfffef000, 0x1000); |
| 65 | ||
| 66 | /*- | |
| 67 | * The i8254 is driven with a nonstandard frequency which is | |
| 68 | * derived thusly: | |
| 69 | * f = 32768 * 45 * 25 / 31 = 1189161.29... | |
| 70 | * We use the sysctl to get the timecounter etc into whack. | |
| 71 | */ | |
| 72 | ||
| 73 | new = 1189161; | |
| 7b95be2a | 74 | i = kernel_sysctlbyname("machdep.i8254_freq", |
| 984263bc MD |
75 | NULL, 0, |
| 76 | &new, sizeof new, | |
| 77 | NULL); | |
| 78 | if (bootverbose) | |
| 26be20a0 | 79 | kprintf("sysctl machdep.i8254_freq=%d returns %d\n", new, i); |
| 984263bc | 80 | |
| 88c4d2f6 | 81 | #if 0 |
| 984263bc MD |
82 | /* Start GP timer #2 and use it as timecounter, hz permitting */ |
| 83 | elan_mmcr[0xc82 / 2] = 0xc001; | |
| 84 | init_timecounter(&elan_timecounter); | |
| 88c4d2f6 | 85 | #endif |
| 984263bc MD |
86 | } |
| 87 | ||
| 88 | ||
| 89 | /* | |
| 90 | * Device driver initialization stuff | |
| 91 | */ | |
| 92 | ||
| 93 | static d_open_t elan_open; | |
| 94 | static d_close_t elan_close; | |
| 95 | static d_ioctl_t elan_ioctl; | |
| 96 | static d_mmap_t elan_mmap; | |
| 97 | ||
| 27dd53e3 | 98 | #define CDEV_MAJOR 100 |
| fef8985e MD |
99 | static struct dev_ops elan_ops = { |
| 100 | { "elan", CDEV_MAJOR, 0 }, | |
| 101 | .d_open = elan_open, | |
| 102 | .d_close = elan_close, | |
| 103 | .d_ioctl = elan_ioctl, | |
| 104 | .d_mmap = elan_mmap, | |
| 984263bc MD |
105 | }; |
| 106 | ||
| 107 | static int | |
| fef8985e | 108 | elan_open(struct dev_open_args *ap) |
| 984263bc MD |
109 | { |
| 110 | return (0); | |
| 111 | } | |
| 112 | ||
| 113 | static int | |
| fef8985e | 114 | elan_close(struct dev_close_args *ap) |
| 984263bc MD |
115 | { |
| 116 | return (0); | |
| 117 | } | |
| 118 | ||
| 119 | static int | |
| fef8985e | 120 | elan_mmap(struct dev_mmap_args *ap) |
| 984263bc | 121 | { |
| fef8985e MD |
122 | if (ap->a_offset >= 0x1000) |
| 123 | return (EINVAL); | |
| 124 | ap->a_result = i386_btop(0xfffef000); | |
| 125 | return(0); | |
| 984263bc MD |
126 | } |
| 127 | ||
| 128 | static int | |
| fef8985e | 129 | elan_ioctl(struct dev_ioctl_args *ap) |
| 984263bc MD |
130 | { |
| 131 | return(ENOENT); | |
| 132 | } | |
| 133 | ||
| 134 | static void | |
| 135 | elan_drvinit(void) | |
| 136 | { | |
| 137 | ||
| 138 | if (elan_mmcr == NULL) | |
| 139 | return; | |
| 26be20a0 | 140 | kprintf("Elan-mmcr driver: MMCR at %p\n", elan_mmcr); |
| fef8985e | 141 | make_dev(&elan_ops, 0, UID_ROOT, GID_WHEEL, 0600, "elan-mmcr"); |
| 984263bc MD |
142 | } |
| 143 | ||
| 144 | SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE+CDEV_MAJOR,elan_drvinit,NULL); |