/* sa1100_pcmcia_update_mecr() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due * to a core clock frequency change) is needed, this routine establishes * new BS_xx values consistent with the clock speed `clock'. */ static void sa1100_pcmcia_update_mecr(unsigned int clock){ unsigned int sock; unsigned long mecr = MECR; for(sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock){ MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_io, clock)); MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_attr, clock)); MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_mem, clock)); } MECR = mecr; }
/* sa1100_pcmcia_set_mem_map() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the set_mem_map() operation for the in-kernel PCMCIA * service (formerly SS_SetMemMap in Card Services). We configure * the map speed as requested, but override the address ranges * supplied by Card Services. * * Returns: 0 on success, -1 on error */ static int sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); unsigned long start; DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n", map->map, map->speed, map->sys_start, map->sys_stop, map->card_start); DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", (map->flags==0)?"<NONE>":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", (map->flags&MAP_0WS)?"0WS ":"", (map->flags&MAP_WRPROT)?"WRPROT ":"", (map->flags&MAP_ATTRIB)?"ATTRIB ":"", (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); if (map->map >= MAX_WIN){ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; } if (map->flags & MAP_ACTIVE) { unsigned int clock, speed = map->speed; unsigned long mecr; /* * When clients issue RequestMap, the access speed is not always * properly configured. Choose some sensible defaults. */ if (speed == 0) { if (skt->cs_state.Vcc == 33) speed = SA1100_PCMCIA_3V_MEM_ACCESS; else speed = SA1100_PCMCIA_5V_MEM_ACCESS; } clock = cpufreq_get(0); /* Fixme: MECR is not pre-empt safe. */ mecr = MECR; if (map->flags & MAP_ATTRIB) { MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); skt->speed_attr = speed; } else { MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); skt->speed_mem = speed; } DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), sock, MECR_BSIO_GET(mecr, sock)); MECR = mecr; } start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem; if (map->sys_stop == 0) map->sys_stop = PAGE_SIZE-1; map->sys_stop -= map->sys_start; map->sys_stop += start; map->sys_start = start; skt->mem_map[map->map] = *map; return 0; } /* sa1100_pcmcia_set_mem_map() */
/* sa1100_pcmcia_driver_init() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * * This routine performs a basic sanity check to ensure that this * kernel has been built with the appropriate board-specific low-level * PCMCIA support, performs low-level PCMCIA initialization, registers * this socket driver with Card Services, and then spawns the daemon * thread which is the real workhorse of the socket driver. * * Returns: 0 on success, -1 on error */ static int __init sa1100_pcmcia_driver_init(void) { servinfo_t info; struct pcmcia_init pcmcia_init; struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; unsigned int i, clock; unsigned long mecr; int ret; printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE); CardServices(GetCardServicesInfo, &info); if (info.Revision != CS_RELEASE_CODE) { printk(KERN_ERR "Card Services release codes do not match\n"); return -EINVAL; } ret = sa1100_pcmcia_machine_init(); if (ret) return ret; pcmcia_init.handler = sa1100_pcmcia_interrupt; ret = pcmcia_low_level->init(&pcmcia_init); if (ret < 0) { printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret); return ret == -1 ? -EIO : ret; } sa1100_pcmcia_socket_count = ret; state_array.size = sa1100_pcmcia_socket_count; state_array.state = state; memset(state, 0, sizeof(state)); if (pcmcia_low_level->socket_state(&state_array) < 0) { pcmcia_low_level->shutdown(); printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); return -EIO; } /* * We initialize the MECR to default values here, because we are * not guaranteed to see a SetIOMap operation at runtime. */ mecr = MECR; clock = cpufreq_get(0); for (i = 0; i < sa1100_pcmcia_socket_count; i++) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); struct pcmcia_irq_info irq_info; if (!request_mem_region(_PCMCIA(i), PCMCIASp, "PCMCIA")) { ret = -EBUSY; goto out_err; } irq_info.sock = i; irq_info.irq = -1; ret = pcmcia_low_level->get_irq_info(&irq_info); if (ret < 0) printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret); skt->irq = irq_info.irq; skt->k_state = state[i]; skt->speed_io = SA1100_PCMCIA_IO_ACCESS; skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS; skt->speed_mem = SA1100_PCMCIA_5V_MEM_ACCESS; skt->phys_attr = _PCMCIAAttr(i); skt->phys_mem = _PCMCIAMem(i); skt->virt_io = ioremap(_PCMCIAIO(i), 0x10000); if (skt->virt_io == NULL) { ret = -ENOMEM; goto out_err; } MECR_FAST_SET(mecr, i, 0); MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_io, clock)); MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_attr, clock)); MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_mem, clock)); } MECR = mecr; #ifdef CONFIG_CPU_FREQ ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block); if (ret < 0) { printk(KERN_ERR "Unable to register CPU frequency change notifier (%d)\n", ret); goto out_err; } #endif /* Only advertise as many sockets as we can detect */ ret = register_ss_entry(sa1100_pcmcia_socket_count, &sa1100_pcmcia_operations); if (ret < 0) { printk(KERN_ERR "Unable to register sockets\n"); goto out_err; } /* * Start the event poll timer. It will reschedule by itself afterwards. */ sa1100_pcmcia_poll_event(0); return 0; out_err: for (i = 0; i < sa1100_pcmcia_socket_count; i++) { iounmap(sa1100_pcmcia_socket[i].virt_io); release_mem_region(_PCMCIA(i), PCMCIASp); } pcmcia_low_level->shutdown(); return ret; } /* sa1100_pcmcia_driver_init() */
/* sa1100_pcmcia_set_mem_map() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the set_mem_map() operation for the in-kernel PCMCIA * service (formerly SS_SetMemMap in Card Services). We configure * the map speed as requested, but override the address ranges * supplied by Card Services. * * Returns: 0 on success, -1 on error */ static int sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map){ unsigned int clock, speed; unsigned long mecr, start; DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); DEBUG(4, "\tmap %u speed %u\n\tsys_start %#lx\n" "\tsys_stop %#lx\n\tcard_start %#x\n" "\tflags: %s%s%s%s%s%s%s%s\n", map->map, map->speed, map->sys_start, map->sys_stop, map->card_start, (map->flags==0)?"<NONE>":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", (map->flags&MAP_0WS)?"0WS ":"", (map->flags&MAP_WRPROT)?"WRPROT ":"", (map->flags&MAP_ATTRIB)?"ATTRIB ":"", (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); if(map->map>=MAX_WIN){ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; } if(map->flags&MAP_ACTIVE){ /* When clients issue RequestMap, the access speed is not always * properly configured: */ if(map->speed > 0) speed = map->speed; else switch(sa1100_pcmcia_socket[sock].cs_state.Vcc){ case 33: speed = SA1100_PCMCIA_3V_MEM_ACCESS; break; default: speed = SA1100_PCMCIA_5V_MEM_ACCESS; } clock = cpufreq_get(0); mecr=MECR; if(map->flags&MAP_ATTRIB){ MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); sa1100_pcmcia_socket[sock].speed_attr=speed; } else { MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); sa1100_pcmcia_socket[sock].speed_mem=speed; } DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), sock, MECR_BSIO_GET(mecr, sock)); MECR=mecr; } start=map->sys_start; if(map->sys_stop==0) map->sys_stop=PAGE_SIZE-1; map->sys_start=(map->flags & MAP_ATTRIB)?\ sa1100_pcmcia_socket[sock].phys_attr:\ sa1100_pcmcia_socket[sock].phys_mem; map->sys_stop=map->sys_start+(map->sys_stop-start); sa1100_pcmcia_socket[sock].mem_map[map->map]=*map; return 0; } /* sa1100_pcmcia_set_mem_map() */
/* sa1100_pcmcia_driver_init() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * * This routine performs a basic sanity check to ensure that this * kernel has been built with the appropriate board-specific low-level * PCMCIA support, performs low-level PCMCIA initialization, registers * this socket driver with Card Services, and then spawns the daemon * thread which is the real workhorse of the socket driver. * * Please see linux/Documentation/arm/SA1100/PCMCIA for more information * on the low-level kernel interface. * * Returns: 0 on success, -1 on error */ static int __init sa1100_pcmcia_driver_init(void){ servinfo_t info; struct pcmcia_init pcmcia_init; struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; unsigned int i, clock; unsigned long mecr; printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE); CardServices(GetCardServicesInfo, &info); if(info.Revision!=CS_RELEASE_CODE){ printk(KERN_ERR "Card Services release codes do not match\n"); return -1; } if(machine_is_assabet()){ #ifdef CONFIG_SA1100_ASSABET if(machine_has_neponset()){ #ifdef CONFIG_ASSABET_NEPONSET pcmcia_low_level=&neponset_pcmcia_ops; #else printk(KERN_ERR "Card Services disabled: missing Neponset support\n"); return -1; #endif }else{ pcmcia_low_level=&assabet_pcmcia_ops; } #endif } else if (machine_is_freebird()) { #ifdef CONFIG_SA1100_FREEBIRD pcmcia_low_level = &freebird_pcmcia_ops; #endif } else if (machine_is_h3xxx()) { #ifdef CONFIG_SA1100_H3XXX pcmcia_low_level = &h3600_pcmcia_ops; #endif } else if (machine_is_cerf()) { #ifdef CONFIG_SA1100_CERF pcmcia_low_level = &cerf_pcmcia_ops; #endif } else if (machine_is_graphicsclient()) { #ifdef CONFIG_SA1100_GRAPHICSCLIENT pcmcia_low_level = &gcplus_pcmcia_ops; #endif } else if (machine_is_xp860()) { #ifdef CONFIG_SA1100_XP860 pcmcia_low_level = &xp860_pcmcia_ops; #endif } else if (machine_is_yopy()) { #ifdef CONFIG_SA1100_YOPY pcmcia_low_level = &yopy_pcmcia_ops; #endif } else if (machine_is_shannon()) { #ifdef CONFIG_SA1100_SHANNON pcmcia_low_level = &shannon_pcmcia_ops; #endif } else if (machine_is_pangolin()) { #ifdef CONFIG_SA1100_PANGOLIN pcmcia_low_level = &pangolin_pcmcia_ops; #endif } else if (machine_is_jornada720()) { #ifdef CONFIG_SA1100_JORNADA720 pcmcia_low_level = &jornada720_pcmcia_ops; #endif } else if(machine_is_pfs168()){ #ifdef CONFIG_SA1100_PFS168 pcmcia_low_level=&pfs168_pcmcia_ops; #endif } else if(machine_is_flexanet()){ #ifdef CONFIG_SA1100_FLEXANET pcmcia_low_level=&flexanet_pcmcia_ops; #endif } else if(machine_is_simpad()){ #ifdef CONFIG_SA1100_SIMPAD pcmcia_low_level=&simpad_pcmcia_ops; #endif } else if(machine_is_graphicsmaster()) { #ifdef CONFIG_SA1100_GRAPHICSMASTER pcmcia_low_level=&graphicsmaster_pcmcia_ops; #endif } else if(machine_is_adsbitsy()) { #ifdef CONFIG_SA1100_ADSBITSY pcmcia_low_level=&adsbitsy_pcmcia_ops; #endif } else if(machine_is_stork()) { #ifdef CONFIG_SA1100_STORK pcmcia_low_level=&stork_pcmcia_ops; #endif } if (!pcmcia_low_level) { printk(KERN_ERR "This hardware is not supported by the SA1100 Card Service driver\n"); return -ENODEV; } pcmcia_init.handler=sa1100_pcmcia_interrupt; if((sa1100_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){ printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n"); return -EIO; } state_array.size=sa1100_pcmcia_socket_count; state_array.state=state; if(pcmcia_low_level->socket_state(&state_array)<0){ printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); return -EIO; } /* We initialize the MECR to default values here, because we are * not guaranteed to see a SetIOMap operation at runtime. */ mecr=0; clock = cpufreq_get(0); for(i=0; i<sa1100_pcmcia_socket_count; ++i){ sa1100_pcmcia_socket[i].k_state=state[i]; /* This is an interim fix. Apparently, SetSocket is no longer * called to initialize each socket (prior to the first detect * event). For now, we'll just manually set up the mask. */ sa1100_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT; sa1100_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE; sa1100_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i); sa1100_pcmcia_socket[i].phys_mem=_PCMCIAMem(i); MECR_FAST_SET(mecr, i, 0); MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_IO_ACCESS, clock)); MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock)); MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(SA1100_PCMCIA_5V_MEM_ACCESS, clock)); sa1100_pcmcia_socket[i].speed_io=SA1100_PCMCIA_IO_ACCESS; sa1100_pcmcia_socket[i].speed_attr=SA1100_PCMCIA_5V_MEM_ACCESS; sa1100_pcmcia_socket[i].speed_mem=SA1100_PCMCIA_5V_MEM_ACCESS; } MECR=mecr; #ifdef CONFIG_CPU_FREQ if(cpufreq_register_notifier(&sa1100_pcmcia_notifier_block) < 0){ printk(KERN_ERR "Unable to register CPU frequency change notifier\n"); return -ENXIO; } #endif /* Only advertise as many sockets as we can detect: */ if(register_ss_entry(sa1100_pcmcia_socket_count, &sa1100_pcmcia_operations)<0){ printk(KERN_ERR "Unable to register socket service routine\n"); return -ENXIO; } /* Start the event poll timer. It will reschedule by itself afterwards. */ sa1100_pcmcia_poll_event(0); DEBUG(1, "sa1100: initialization complete\n"); return 0; } /* sa1100_pcmcia_driver_init() */