elan-mmcr.c revision 103168
1101225Sphk/* 2101225Sphk * ---------------------------------------------------------------------------- 3101225Sphk * "THE BEER-WARE LICENSE" (Revision 42): 4101225Sphk * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 5101225Sphk * can do whatever you want with this stuff. If we meet some day, and you think 6101225Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7101225Sphk * ---------------------------------------------------------------------------- 8101225Sphk * 9101225Sphk * $FreeBSD: head/sys/i386/i386/elan-mmcr.c 103168 2002-09-10 05:06:48Z sam $ 10101225Sphk * 11102934Sphk * The AMD Elan sc520 is a system-on-chip gadget which is used in embedded 12102934Sphk * kind of things, see www.soekris.com for instance, and it has a few quirks 13102934Sphk * we need to deal with. 14102934Sphk * Unfortunately we cannot identify the gadget by CPUID output because it 15102934Sphk * depends on strapping options and only the stepping field may be useful 16102934Sphk * and those are undocumented from AMDs side. 17102934Sphk * 18102934Sphk * So instead we recognize the on-chip host-PCI bridge and call back from 19102934Sphk * sys/i386/pci/pci_bus.c to here if we find it. 20101225Sphk */ 21102934Sphk 22101225Sphk#include <sys/param.h> 23101225Sphk#include <sys/systm.h> 24101225Sphk#include <sys/kernel.h> 25101225Sphk#include <sys/conf.h> 26102934Sphk#include <sys/sysctl.h> 27102934Sphk#include <sys/timetc.h> 28102934Sphk#include <sys/proc.h> 29101225Sphk 30101225Sphk#include <machine/md_var.h> 31101225Sphk 32102934Sphk#include <vm/vm.h> 33102934Sphk#include <vm/pmap.h> 34102934Sphk 35102934Sphkuint16_t *elan_mmcr; 36102934Sphk 37102935Sphk 38102935Sphkstatic unsigned 39102935Sphkelan_get_timecount(struct timecounter *tc) 40102935Sphk{ 41102935Sphk return (elan_mmcr[0xc84 / 2]); 42102935Sphk} 43102935Sphk 44102935Sphkstatic struct timecounter elan_timecounter = { 45102935Sphk elan_get_timecount, 46102935Sphk 0, 47102935Sphk 0xffff, 48102935Sphk 33333333 / 4, 49102935Sphk "ELAN" 50102935Sphk}; 51102935Sphk 52102934Sphkvoid 53102934Sphkinit_AMD_Elan_sc520(void) 54102934Sphk{ 55102934Sphk u_int new; 56102934Sphk int i; 57102934Sphk 58103168Ssam if (bootverbose) 59103168Ssam printf("Doing h0h0magic for AMD Elan sc520\n"); 60102934Sphk elan_mmcr = pmap_mapdev(0xfffef000, 0x1000); 61102934Sphk 62102934Sphk /*- 63102934Sphk * The i8254 is driven with a nonstandard frequency which is 64102934Sphk * derived thusly: 65102934Sphk * f = 32768 * 45 * 25 / 31 = 1189161.29... 66102934Sphk * We use the sysctl to get the timecounter etc into whack. 67102934Sphk */ 68102934Sphk 69102934Sphk new = 1189161; 70102934Sphk i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq", 71102934Sphk NULL, 0, 72102934Sphk &new, sizeof new, 73102934Sphk NULL); 74103168Ssam if (bootverbose) 75103168Ssam printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i); 76102935Sphk 77102935Sphk /* Start GP timer #2 and use it as timecounter, hz permitting */ 78102935Sphk elan_mmcr[0xc82 / 2] = 0xc001; 79102935Sphk tc_init(&elan_timecounter); 80102934Sphk} 81102934Sphk 82102934Sphk 83101225Sphk/* 84101225Sphk * Device driver initialization stuff 85101225Sphk */ 86101225Sphk 87101225Sphkstatic d_open_t elan_open; 88101225Sphkstatic d_close_t elan_close; 89101225Sphkstatic d_ioctl_t elan_ioctl; 90101225Sphkstatic d_mmap_t elan_mmap; 91101225Sphk 92101225Sphk#define CDEV_MAJOR 100 /* Share with xrpu */ 93101225Sphkstatic struct cdevsw elan_cdevsw = { 94101225Sphk /* open */ elan_open, 95101225Sphk /* close */ elan_close, 96101225Sphk /* read */ noread, 97101225Sphk /* write */ nowrite, 98101225Sphk /* ioctl */ elan_ioctl, 99101225Sphk /* poll */ nopoll, 100101225Sphk /* mmap */ elan_mmap, 101101225Sphk /* strategy */ nostrategy, 102101225Sphk /* name */ "elan", 103101225Sphk /* maj */ CDEV_MAJOR, 104101225Sphk /* dump */ nodump, 105101225Sphk /* psize */ nopsize, 106101225Sphk /* flags */ 0, 107101225Sphk}; 108101225Sphk 109101225Sphkstatic int 110101225Sphkelan_open(dev_t dev, int flag, int mode, struct thread *td) 111101225Sphk{ 112101225Sphk return (0); 113101225Sphk} 114101225Sphk 115101225Sphkstatic int 116101225Sphkelan_close(dev_t dev, int flag, int mode, struct thread *td) 117101225Sphk{ 118101225Sphk return (0); 119101225Sphk} 120101225Sphk 121101225Sphkstatic int 122101225Sphkelan_mmap(dev_t dev, vm_offset_t offset, int nprot) 123101225Sphk{ 124101225Sphk if (offset >= 0x1000) 125101225Sphk return (-1); 126101225Sphk return (i386_btop(0xfffef000)); 127101225Sphk} 128101225Sphk 129101225Sphkstatic int 130101225Sphkelan_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr) 131101225Sphk{ 132101225Sphk return(ENOENT); 133101225Sphk} 134101225Sphk 135101225Sphkstatic void 136101225Sphkelan_drvinit(void) 137101225Sphk{ 138101225Sphk 139101225Sphk if (elan_mmcr == NULL) 140101225Sphk return; 141103168Ssam printf("Elan-mmcr driver: MMCR at %p\n", elan_mmcr); 142101225Sphk make_dev(&elan_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "elan-mmcr"); 143101225Sphk return; 144101225Sphk} 145101225Sphk 146101229SphkSYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE+CDEV_MAJOR,elan_drvinit,NULL); 147