OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [pcmcia/] [hd64465_ss.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * $Id: hd64465_ss.c,v 1.1.1.1 2004-04-15 02:28:53 phoenix Exp $
3
 *
4
 * Device driver for the PCMCIA controller module of the
5
 * Hitachi HD64465 handheld companion chip.
6
 *
7
 * Note that the HD64465 provides a very thin PCMCIA host bridge
8
 * layer, requiring a lot of the work of supporting cards to be
9
 * performed by the processor.  For example: mapping of card
10
 * interrupts to processor IRQs is done by IRQ demuxing software;
11
 * IO and memory mappings are fixed; setting voltages according
12
 * to card Voltage Select pins etc is done in software.
13
 *
14
 * Note also that this driver uses only the simple, fixed,
15
 * 16MB, 16-bit wide mappings to PCMCIA spaces defined by the
16
 * HD64465.  Larger mappings, smaller mappings, or mappings of
17
 * different width to the same socket, are all possible only by
18
 * involving the SH7750's MMU, which is considered unnecessary here.
19
 * The downside is that it may be possible for some drivers to
20
 * break because they need or expect 8-bit mappings.
21
 *
22
 * This driver currently supports only the following configuration:
23
 * SH7750 CPU, HD64465, TPS2206 voltage control chip.
24
 *
25
 * by Greg Banks <gbanks@pocketpenguins.com>
26
 * (c) 2000 PocketPenguins Inc
27
 *
28
 */
29
 
30
#include <linux/types.h>
31
#include <linux/module.h>
32
#include <linux/init.h>
33
#include <linux/string.h>
34
#include <linux/kernel.h>
35
#include <linux/ioport.h>
36
#include <linux/mm.h>
37
#include <linux/vmalloc.h>
38
#include <asm/errno.h>
39
#include <linux/irq.h>
40
 
41
#include <asm/io.h>
42
#include <asm/hd64465.h>
43
 
44
#include <pcmcia/version.h>
45
#include <pcmcia/cs_types.h>
46
#include <pcmcia/cs.h>
47
#include <pcmcia/ss.h>
48
#include <pcmcia/bulkmem.h>
49
#include <pcmcia/cistpl.h>
50
#include "cs_internal.h"
51
 
52
#define MODNAME "hd64465_ss"
53
 
54
/* #define HD64465_DEBUG 1 */
55
 
56
#ifndef HD64465_DEBUG
57
#define HD64465_DEBUG 0
58
#endif
59
 
60
#if HD64465_DEBUG
61
#define DPRINTK(args...)        printk(MODNAME ": " args)
62
#else
63
#define DPRINTK(args...)
64
#endif
65
 
66
extern int hd64465_io_debug;
67
 
68
 
69
/*============================================================*/
70
 
71
#define HS_IO_MAP_SIZE  (64*1024)
72
 
73
typedef struct hs_socket_t
74
{
75
    u_int               irq;
76
    u_long              mem_base;
77
    u_long              mem_length;
78
    void                (*handler)(void *info, u_int events);
79
    void                *handler_info;
80
    u_int               pending_events;
81
    u_int               ctrl_base;
82
    socket_state_t      state;
83
    pccard_io_map       io_maps[MAX_IO_WIN];
84
    pccard_mem_map      mem_maps[MAX_WIN];
85
    struct vm_struct    *io_vma;    /* allocated kernel vm for mapping IO space */
86
} hs_socket_t;
87
 
88
#define HS_MAX_SOCKETS 2
89
static hs_socket_t hs_sockets[HS_MAX_SOCKETS];
90
static spinlock_t hs_pending_event_lock = SPIN_LOCK_UNLOCKED;
91
 
92
/* Calculate socket number from ptr into hs_sockets[] */
93
#define hs_sockno(sp)   (sp - hs_sockets)
94
 
95
static socket_cap_t hs_socket_cap =
96
{
97
    SS_CAP_PCCARD           /* support 16 bit cards */
98
    |SS_CAP_STATIC_MAP      /* mappings are fixed in host memory */
99
    ,
100
    0xffde/*0xffff*/,       /* IRQs mapped in s/w so can do any, really */
101
    HD64465_PCC_WINDOW,     /* 16MB fixed window size */
102
    0,                       /* no PCI support */
103
    0,                       /* no CardBus support */
104
 
105
};
106
 
107
#define hs_in(sp, r)        inb((sp)->ctrl_base + (r))
108
#define hs_out(sp, v, r)    outb(v, (sp)->ctrl_base + (r))
109
 
110
 
111
/* translate a boolean value to a bit in a register */
112
#define bool_to_regbit(sp, r, bi, bo)           \
113
    do {                                        \
114
        unsigned short v = hs_in(sp, r);        \
115
        if (bo)                                 \
116
            v |= (bi);                          \
117
        else                                    \
118
            v &= ~(bi);                         \
119
        hs_out(sp, v, r);                       \
120
    } while(0)
121
 
122
/* register offsets from HD64465_REG_PCC[01]ISR */
123
#define ISR     0x0
124
#define GCR     0x2
125
#define CSCR    0x4
126
#define CSCIER  0x6
127
#define SCR     0x8
128
 
129
 
130
/* Mask and values for CSCIER register */
131
#define IER_MASK    0x80
132
#define IER_ON      0x3f        /* interrupts on */
133
#define IER_OFF     0x00        /* interrupts off */
134
 
135
/*============================================================*/
136
 
137
#if HD64465_DEBUG > 10
138
 
139
static void cis_hex_dump(const unsigned char *x, int len)
140
{
141
        int i;
142
 
143
        for (i=0 ; i<len ; i++)
144
        {
145
            if (!(i & 0xf))
146
                printk("\n%08x", (unsigned)(x + i));
147
            printk(" %02x", *(volatile unsigned short*)x);
148
            x += 2;
149
        }
150
        printk("\n");
151
}
152
 
153
#endif
154
/*============================================================*/
155
 
156
/*
157
 * This code helps create the illusion that the IREQ line from
158
 * the PC card is mapped to one of the CPU's IRQ lines by the
159
 * host bridge hardware (which is how every host bridge *except*
160
 * the HD64465 works).  In particular, it supports enabling
161
 * and disabling the IREQ line by code which knows nothing
162
 * about the host bridge (e.g. device drivers, IDE code) using
163
 * the request_irq(), free_irq(), probe_irq_on() and probe_irq_off()
164
 * functions.  Also, it supports sharing the mapped IRQ with
165
 * real hardware IRQs from the -IRL0-3 lines.
166
 */
167
 
168
#define HS_NUM_MAPPED_IRQS  16  /* Limitation of the PCMCIA code */
169
static struct
170
{
171
    /* index is mapped irq number */
172
    hs_socket_t *sock;
173
    hw_irq_controller *old_handler;
174
} hs_mapped_irq[HS_NUM_MAPPED_IRQS];
175
 
176
static void hs_socket_enable_ireq(hs_socket_t *sp)
177
{
178
        unsigned short cscier;
179
 
180
        DPRINTK("hs_socket_enable_ireq(sock=%d)\n", hs_sockno(sp));
181
 
182
        cscier = hs_in(sp, CSCIER);
183
        cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK;
184
        cscier |= HD64465_PCCCSCIER_PIREQE_LEVEL;
185
        hs_out(sp, cscier, CSCIER);
186
}
187
 
188
static void hs_socket_disable_ireq(hs_socket_t *sp)
189
{
190
        unsigned short cscier;
191
 
192
        DPRINTK("hs_socket_disable_ireq(sock=%d)\n", hs_sockno(sp));
193
 
194
        cscier = hs_in(sp, CSCIER);
195
        cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK;
196
        hs_out(sp, cscier, CSCIER);
197
}
198
 
199
static unsigned int hs_startup_irq(unsigned int irq)
200
{
201
        hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
202
        hs_mapped_irq[irq].old_handler->startup(irq);
203
        return 0;
204
}
205
 
206
static void hs_shutdown_irq(unsigned int irq)
207
{
208
        hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
209
        hs_mapped_irq[irq].old_handler->shutdown(irq);
210
}
211
 
212
static void hs_enable_irq(unsigned int irq)
213
{
214
        hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
215
        hs_mapped_irq[irq].old_handler->enable(irq);
216
}
217
 
218
static void hs_disable_irq(unsigned int irq)
219
{
220
        hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
221
        hs_mapped_irq[irq].old_handler->disable(irq);
222
}
223
 
224
extern struct hw_interrupt_type no_irq_type;
225
 
226
static void hs_mask_and_ack_irq(unsigned int irq)
227
{
228
        hs_socket_disable_ireq(hs_mapped_irq[irq].sock);
229
        /* ack_none() spuriously complains about an unexpected IRQ */
230
        if (hs_mapped_irq[irq].old_handler != &no_irq_type)
231
            hs_mapped_irq[irq].old_handler->ack(irq);
232
}
233
 
234
static void hs_end_irq(unsigned int irq)
235
{
236
        hs_socket_enable_ireq(hs_mapped_irq[irq].sock);
237
        hs_mapped_irq[irq].old_handler->end(irq);
238
}
239
 
240
 
241
static struct hw_interrupt_type hd64465_ss_irq_type = {
242
        typename:       "PCMCIA-IRQ",
243
        startup:        hs_startup_irq,
244
        shutdown:       hs_shutdown_irq,
245
        enable:         hs_enable_irq,
246
        disable:        hs_disable_irq,
247
        ack:            hs_mask_and_ack_irq,
248
        end:            hs_end_irq
249
};
250
 
251
/*
252
 * This function should only ever be called with interrupts disabled.
253
 */
254
static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
255
{
256
        DPRINTK("hs_map_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq);
257
 
258
        if (irq >= HS_NUM_MAPPED_IRQS)
259
            return;
260
 
261
        hs_mapped_irq[irq].sock = sp;
262
        /* insert ourselves as the irq controller */
263
        hs_mapped_irq[irq].old_handler = irq_desc[irq].handler;
264
        irq_desc[irq].handler = &hd64465_ss_irq_type;
265
}
266
 
267
 
268
/*
269
 * This function should only ever be called with interrupts disabled.
270
 */
271
static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq)
272
{
273
        DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq);
274
 
275
        if (irq >= HS_NUM_MAPPED_IRQS)
276
            return;
277
 
278
        /* restore the original irq controller */
279
        irq_desc[irq].handler = hs_mapped_irq[irq].old_handler;
280
}
281
 
282
/*============================================================*/
283
 
284
 
285
/*
286
 * Set Vpp and Vcc (in tenths of a Volt).  Does not
287
 * support the hi-Z state.
288
 *
289
 * Note, this assumes the board uses a TPS2206 chip to control
290
 * the Vcc and Vpp voltages to the hs_sockets.  If your board
291
 * uses the MIC2563 (also supported by the HD64465) then you
292
 * will have to modify this function.
293
 */
294
                                         /* 0V   3.3V  5.5V */
295
static const u_char hs_tps2206_avcc[3] = { 0x00, 0x04, 0x08 };
296
static const u_char hs_tps2206_bvcc[3] = { 0x00, 0x80, 0x40 };
297
 
298
static int hs_set_voltages(hs_socket_t *sp, int Vcc, int Vpp)
299
{
300
        u_int psr;
301
        u_int vcci = 0;
302
        u_int sock = hs_sockno(sp);
303
 
304
        DPRINTK("hs_set_voltage(%d, %d, %d)\n", sock, Vcc, Vpp);
305
 
306
        switch (Vcc)
307
        {
308
        case 0:  vcci = 0; break;
309
        case 33: vcci = 1; break;
310
        case 50: vcci = 2; break;
311
        default: return 0;
312
        }
313
 
314
        /* Note: Vpp = 120 not supported -- Greg Banks */
315
        if (Vpp != 0 && Vpp != Vcc)
316
            return 0;
317
 
318
        /* The PSR register holds 8 of the 9 bits which control
319
         * the TPS2206 via its serial interface.
320
         */
321
        psr = inw(HD64465_REG_PCCPSR);
322
        switch (sock)
323
        {
324
        case 0:
325
            psr &= 0x0f;
326
            psr |= hs_tps2206_avcc[vcci];
327
            psr |= (Vpp == 0 ? 0x00 : 0x02);
328
            break;
329
        case 1:
330
            psr &= 0xf0;
331
            psr |= hs_tps2206_bvcc[vcci];
332
            psr |= (Vpp == 0 ? 0x00 : 0x20);
333
            break;
334
        };
335
        outw(psr, HD64465_REG_PCCPSR);
336
 
337
        return 1;
338
}
339
 
340
 
341
/*============================================================*/
342
 
343
/*
344
 * Drive the RESET line to the card.
345
 */
346
static void hs_reset_socket(hs_socket_t *sp, int on)
347
{
348
        unsigned short v;
349
 
350
        v = hs_in(sp, GCR);
351
        if (on)
352
            v |= HD64465_PCCGCR_PCCR;
353
        else
354
            v &= ~HD64465_PCCGCR_PCCR;
355
        hs_out(sp, v, GCR);
356
}
357
 
358
/*============================================================*/
359
 
360
static int hs_init(unsigned int sock)
361
{
362
        hs_socket_t *sp = &hs_sockets[sock];
363
 
364
        DPRINTK("hs_init(%d)\n", sock);
365
 
366
        sp->pending_events = 0;
367
        sp->state.Vcc = 0;
368
        sp->state.Vpp = 0;
369
        hs_set_voltages(sp, 0, 0);
370
 
371
        return 0;
372
}
373
 
374
/*============================================================*/
375
 
376
static int hs_suspend(unsigned int sock)
377
{
378
        DPRINTK("hs_suspend(%d)\n", sock);
379
 
380
        /* TODO */
381
 
382
        return 0;
383
}
384
 
385
/*============================================================*/
386
 
387
static int hs_register_callback(unsigned int sock,
388
            void (*handler)(void *, unsigned int), void * info)
389
{
390
        hs_socket_t *sp = &hs_sockets[sock];
391
 
392
        DPRINTK("hs_register_callback(%d)\n", sock);
393
        sp->handler = handler;
394
        sp->handler_info = info;
395
        if (handler == 0) {
396
            MOD_DEC_USE_COUNT;
397
        } else {
398
            MOD_INC_USE_COUNT;
399
        }
400
        return 0;
401
}
402
 
403
/*============================================================*/
404
 
405
static int hs_inquire_socket(unsigned int sock, socket_cap_t *cap)
406
{
407
        DPRINTK("hs_inquire_socket(%d)\n", sock);
408
 
409
        *cap = hs_socket_cap;
410
        return 0;
411
}
412
 
413
/*============================================================*/
414
 
415
static int hs_get_status(unsigned int sock, u_int *value)
416
{
417
        hs_socket_t *sp = &hs_sockets[sock];
418
        unsigned int isr;
419
        u_int status = 0;
420
 
421
 
422
        isr = hs_in(sp, ISR);
423
 
424
        /* Card is seated and powered when *both* CD pins are low */
425
        if ((isr & HD64465_PCCISR_PCD_MASK) == 0)
426
        {
427
            status |= SS_DETECT;    /* card present */
428
 
429
            switch (isr & HD64465_PCCISR_PBVD_MASK)
430
            {
431
            case HD64465_PCCISR_PBVD_BATGOOD:
432
                break;
433
            case HD64465_PCCISR_PBVD_BATWARN:
434
                status |= SS_BATWARN;
435
                break;
436
            default:
437
                status |= SS_BATDEAD;
438
                break;
439
            }
440
 
441
            if (isr & HD64465_PCCISR_PREADY)
442
                status |= SS_READY;
443
 
444
            if (isr & HD64465_PCCISR_PMWP)
445
                status |= SS_WRPROT;
446
 
447
            /* Voltage Select pins interpreted as per Table 4-5 of the std.
448
             * Assuming we have the TPS2206, the socket is a "Low Voltage
449
             * key, 3.3V and 5V available, no X.XV available".
450
             */
451
            switch (isr & (HD64465_PCCISR_PVS2|HD64465_PCCISR_PVS1))
452
            {
453
            case HD64465_PCCISR_PVS1:
454
                printk(KERN_NOTICE MODNAME ": cannot handle X.XV card, ignored\n");
455
                status = 0;
456
                break;
457
            case 0:
458
            case HD64465_PCCISR_PVS2:
459
                /* 3.3V */
460
                status |= SS_3VCARD;
461
                break;
462
            case HD64465_PCCISR_PVS2|HD64465_PCCISR_PVS1:
463
                /* 5V */
464
                break;
465
            }
466
 
467
            /* TODO: SS_POWERON */
468
            /* TODO: SS_STSCHG */
469
        }
470
 
471
        DPRINTK("hs_get_status(%d) = %x\n", sock, status);
472
 
473
        *value = status;
474
        return 0;
475
}
476
 
477
/*============================================================*/
478
 
479
static int hs_get_socket(unsigned int sock, socket_state_t *state)
480
{
481
        hs_socket_t *sp = &hs_sockets[sock];
482
 
483
        DPRINTK("hs_get_socket(%d)\n", sock);
484
 
485
        *state = sp->state;
486
        return 0;
487
}
488
 
489
/*============================================================*/
490
 
491
static int hs_set_socket(unsigned int sock, socket_state_t *state)
492
{
493
        hs_socket_t *sp = &hs_sockets[sock];
494
        u_long flags;
495
        u_int changed;
496
        unsigned short cscier;
497
 
498
        DPRINTK("hs_set_socket(sock=%d, flags=%x, csc_mask=%x, Vcc=%d, Vpp=%d, io_irq=%d)\n",
499
            sock, state->flags, state->csc_mask, state->Vcc, state->Vpp, state->io_irq);
500
 
501
        save_and_cli(flags);    /* Don't want interrupts happening here */
502
 
503
        if (state->Vpp != sp->state.Vpp ||
504
            state->Vcc != sp->state.Vcc) {
505
            if (!hs_set_voltages(sp, state->Vcc, state->Vpp)) {
506
                restore_flags(flags);
507
                return -EINVAL;
508
            }
509
        }
510
 
511
/*      hd64465_io_debug = 1; */
512
        /*
513
         * Handle changes in the Card Status Change mask,
514
         * by propagating to the CSCR register
515
         */
516
        changed = sp->state.csc_mask ^ state->csc_mask;
517
        cscier = hs_in(sp, CSCIER);
518
 
519
        if (changed & SS_DETECT) {
520
            if (state->csc_mask & SS_DETECT)
521
                cscier |= HD64465_PCCCSCIER_PCDE;
522
            else
523
                cscier &= ~HD64465_PCCCSCIER_PCDE;
524
        }
525
 
526
        if (changed & SS_READY) {
527
            if (state->csc_mask & SS_READY)
528
                cscier |= HD64465_PCCCSCIER_PRE;
529
            else
530
                cscier &= ~HD64465_PCCCSCIER_PRE;
531
        }
532
 
533
        if (changed & SS_BATDEAD) {
534
            if (state->csc_mask & SS_BATDEAD)
535
                cscier |= HD64465_PCCCSCIER_PBDE;
536
            else
537
                cscier &= ~HD64465_PCCCSCIER_PBDE;
538
        }
539
 
540
        if (changed & SS_BATWARN) {
541
            if (state->csc_mask & SS_BATWARN)
542
                cscier |= HD64465_PCCCSCIER_PBWE;
543
            else
544
                cscier &= ~HD64465_PCCCSCIER_PBWE;
545
        }
546
 
547
        if (changed & SS_STSCHG) {
548
            if (state->csc_mask & SS_STSCHG)
549
                cscier |= HD64465_PCCCSCIER_PSCE;
550
            else
551
                cscier &= ~HD64465_PCCCSCIER_PSCE;
552
        }
553
 
554
        hs_out(sp, cscier, CSCIER);
555
 
556
        if (sp->state.io_irq && !state->io_irq)
557
            hs_unmap_irq(sp, sp->state.io_irq);
558
        else if (!sp->state.io_irq && state->io_irq)
559
            hs_map_irq(sp, state->io_irq);
560
 
561
 
562
        /*
563
         * Handle changes in the flags field,
564
         * by propagating to config registers.
565
         */
566
        changed = sp->state.flags ^ state->flags;
567
 
568
        if (changed & SS_IOCARD) {
569
            DPRINTK("card type: %s\n",
570
                    (state->flags & SS_IOCARD ? "i/o" : "memory" ));
571
            bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCT,
572
                state->flags & SS_IOCARD);
573
        }
574
 
575
        if (changed & SS_RESET) {
576
            DPRINTK("%s reset card\n",
577
                (state->flags & SS_RESET ? "start" : "stop"));
578
            bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCR,
579
                state->flags & SS_RESET);
580
        }
581
 
582
        if (changed & SS_OUTPUT_ENA) {
583
            DPRINTK("%sabling card output\n",
584
                (state->flags & SS_OUTPUT_ENA ? "en" : "dis"));
585
            bool_to_regbit(sp, GCR, HD64465_PCCGCR_PDRV,
586
                state->flags & SS_OUTPUT_ENA);
587
        }
588
 
589
        /* TODO: SS_SPKR_ENA */
590
 
591
/*      hd64465_io_debug = 0; */
592
        sp->state = *state;
593
 
594
        restore_flags(flags);
595
 
596
#if HD64465_DEBUG > 10
597
        if (state->flags & SS_OUTPUT_ENA)
598
            cis_hex_dump((const unsigned char*)sp->mem_base, 0x100);
599
#endif
600
        return 0;
601
}
602
 
603
/*============================================================*/
604
 
605
static int hs_get_io_map(unsigned int sock, struct pccard_io_map *io)
606
{
607
        hs_socket_t *sp = &hs_sockets[sock];
608
        int map = io->map;
609
 
610
        DPRINTK("hs_get_io_map(%d, %d)\n", sock, map);
611
        if (map >= MAX_IO_WIN)
612
            return -EINVAL;
613
 
614
        *io = sp->io_maps[map];
615
        return 0;
616
}
617
 
618
/*============================================================*/
619
 
620
static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io)
621
{
622
        hs_socket_t *sp = &hs_sockets[sock];
623
        int map = io->map;
624
        struct pccard_io_map *sio;
625
        pgprot_t prot;
626
 
627
        DPRINTK("hs_set_io_map(sock=%d, map=%d, flags=0x%x, speed=%dns, start=0x%04x, stop=0x%04x)\n",
628
            sock, map, io->flags, io->speed, io->start, io->stop);
629
        if (map >= MAX_IO_WIN)
630
            return -EINVAL;
631
        sio = &sp->io_maps[map];
632
 
633
        /* check for null changes */
634
        if (io->flags == sio->flags &&
635
            io->start == sio->start &&
636
            io->stop == sio->stop)
637
            return 0;
638
 
639
        if (io->flags & MAP_AUTOSZ)
640
            prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IODYN);
641
        else if (io->flags & MAP_16BIT)
642
            prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO16);
643
        else
644
            prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO8);
645
 
646
        /* TODO: handle MAP_USE_WAIT */
647
        if (io->flags & MAP_USE_WAIT)
648
            printk(KERN_INFO MODNAME ": MAP_USE_WAIT unimplemented\n");
649
        /* TODO: handle MAP_PREFETCH */
650
        if (io->flags & MAP_PREFETCH)
651
            printk(KERN_INFO MODNAME ": MAP_PREFETCH unimplemented\n");
652
        /* TODO: handle MAP_WRPROT */
653
        if (io->flags & MAP_WRPROT)
654
            printk(KERN_INFO MODNAME ": MAP_WRPROT unimplemented\n");
655
        /* TODO: handle MAP_0WS */
656
        if (io->flags & MAP_0WS)
657
            printk(KERN_INFO MODNAME ": MAP_0WS unimplemented\n");
658
 
659
        if (io->flags & MAP_ACTIVE) {
660
            unsigned long pstart, psize, paddrbase, vaddrbase;
661
 
662
            paddrbase = virt_to_phys((void*)(sp->mem_base + 2 * HD64465_PCC_WINDOW));
663
            vaddrbase = (unsigned long)sp->io_vma->addr;
664
            pstart = io->start & PAGE_MASK;
665
            psize = ((io->stop + PAGE_SIZE) & PAGE_MASK) - pstart;
666
 
667
            /*
668
             * Change PTEs in only that portion of the mapping requested
669
             * by the caller.  This means that most of the time, most of
670
             * the PTEs in the io_vma will be unmapped and only the bottom
671
             * page will be mapped.  But the code allows for weird cards
672
             * that might want IO ports > 4K.
673
             */
674
            DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)\n",
675
                vaddrbase + pstart, paddrbase + pstart, psize);
676
            remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot);
677
 
678
            /*
679
             * Change the mapping used by inb() outb() etc
680
             */
681
            hd64465_port_map(
682
                io->start,
683
                io->stop - io->start + 1,
684
                vaddrbase + io->start,0);
685
        } else {
686
            hd64465_port_unmap(
687
                sio->start,
688
                sio->stop - sio->start + 1);
689
            /* TODO: remap_page_range() to mark pages not present ? */
690
        }
691
 
692
        *sio = *io;
693
        return 0;
694
}
695
 
696
/*============================================================*/
697
 
698
static int hs_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
699
{
700
        hs_socket_t *sp = &hs_sockets[sock];
701
        int map = mem->map;
702
 
703
        DPRINTK("hs_get_mem_map(%d, %d)\n", sock, map);
704
        if (map >= MAX_WIN)
705
            return -EINVAL;
706
 
707
        *mem = sp->mem_maps[map];
708
        return 0;
709
}
710
 
711
/*============================================================*/
712
 
713
static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
714
{
715
        hs_socket_t *sp = &hs_sockets[sock];
716
        struct pccard_mem_map *smem;
717
        int map = mem->map;
718
        unsigned long paddr, size;
719
 
720
#if 0
721
        DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, sys_start=0x%08lx, sys_end=0x%08lx, card_start=0x%08x)\n",
722
            sock, map, mem->flags, mem->sys_start, mem->sys_stop, mem->card_start);
723
#endif
724
 
725
        if (map >= MAX_WIN)
726
            return -EINVAL;
727
        smem = &sp->mem_maps[map];
728
 
729
        size = mem->sys_stop - mem->sys_start + 1;
730
 
731
        paddr = sp->mem_base;               /* base of Attribute mapping */
732
        if (!(mem->flags & MAP_ATTRIB))
733
            paddr += HD64465_PCC_WINDOW;    /* base of Common mapping */
734
        paddr += mem->card_start;
735
 
736
        /* Because we specified SS_CAP_STATIC_MAP, we are obliged
737
         * at this time to report the system address corresponding
738
         * to the card address requested.  This is how Socket Services
739
         * queries our fixed mapping.  I wish this fact had been
740
         * documented - Greg Banks.
741
         */
742
        mem->sys_start = paddr;
743
        mem->sys_stop = paddr + size - 1;
744
 
745
        *smem = *mem;
746
 
747
        return 0;
748
}
749
 
750
/* TODO: do we need to use the MMU to access Common memory ??? */
751
 
752
/*============================================================*/
753
 
754
static void hs_proc_setup(unsigned int sock, struct proc_dir_entry *base)
755
{
756
        DPRINTK("hs_proc_setup(%d)\n", sock);
757
}
758
 
759
/*============================================================*/
760
 
761
/*
762
 * This function is registered with the HD64465 glue code to do a
763
 * secondary demux step on the PCMCIA interrupts.  It handles
764
 * mapping the IREQ request from the card to a standard Linux
765
 * IRQ, as requested by SocketServices.
766
 */
767
static int hs_irq_demux(int irq, void *dev)
768
{
769
        hs_socket_t *sp = (hs_socket_t *)dev;
770
        u_int cscr;
771
 
772
        DPRINTK("hs_irq_demux(irq=%d)\n", irq);
773
 
774
        if (sp->state.io_irq &&
775
            (cscr = hs_in(sp, CSCR)) & HD64465_PCCCSCR_PIREQ) {
776
            cscr &= ~HD64465_PCCCSCR_PIREQ;
777
            hs_out(sp, cscr, CSCR);
778
            return sp->state.io_irq;
779
        }
780
 
781
        return irq;
782
}
783
 
784
/*============================================================*/
785
 
786
/*
787
 * Interrupt handling routine.
788
 *
789
 * This uses the schedule_task() technique to cause reportable events
790
 * such as card insertion and removal to be handled in keventd's
791
 * process context.
792
 */
793
 
794
 
795
static void hs_events_bh(void *dummy)
796
{
797
        hs_socket_t *sp;
798
        u_int events;
799
        int i;
800
 
801
        for (i=0; i<HS_MAX_SOCKETS; i++) {
802
            sp = &hs_sockets[i];
803
 
804
            spin_lock_irq(&hs_pending_event_lock);
805
            events = sp->pending_events;
806
            sp->pending_events = 0;
807
            spin_unlock_irq(&hs_pending_event_lock);
808
 
809
            if (sp->handler)
810
                sp->handler(sp->handler_info, events);
811
        }
812
}
813
 
814
static struct tq_struct hs_events_task = {
815
        routine:        hs_events_bh
816
};
817
 
818
static void hs_interrupt(int irq, void *dev, struct pt_regs *regs)
819
{
820
        hs_socket_t *sp = (hs_socket_t *)dev;
821
        u_int events = 0;
822
        u_int cscr;
823
 
824
 
825
        cscr = hs_in(sp, CSCR);
826
 
827
        DPRINTK("hs_interrupt, cscr=%04x\n", cscr);
828
 
829
        /* check for bus-related changes to be reported to Socket Services */
830
        if (cscr & HD64465_PCCCSCR_PCDC) {
831
            /* double-check for a 16-bit card, as we don't support CardBus */
832
            if ((hs_in(sp, ISR) & HD64465_PCCISR_PCD_MASK) != 0) {
833
                printk(KERN_NOTICE MODNAME
834
                    ": socket %d, card not a supported card type or not inserted correctly\n",
835
                    hs_sockno(sp));
836
                /* Don't do the rest unless a card is present */
837
                cscr &= ~(HD64465_PCCCSCR_PCDC|
838
                          HD64465_PCCCSCR_PRC|
839
                          HD64465_PCCCSCR_PBW|
840
                          HD64465_PCCCSCR_PBD|
841
                          HD64465_PCCCSCR_PSC);
842
            } else {
843
                cscr &= ~HD64465_PCCCSCR_PCDC;
844
                events |= SS_DETECT;            /* card insertion or removal */
845
            }
846
        }
847
        if (cscr & HD64465_PCCCSCR_PRC) {
848
            cscr &= ~HD64465_PCCCSCR_PRC;
849
            events |= SS_READY;         /* ready signal changed */
850
        }
851
        if (cscr & HD64465_PCCCSCR_PBW) {
852
            cscr &= ~HD64465_PCCCSCR_PSC;
853
            events |= SS_BATWARN;       /* battery warning */
854
        }
855
        if (cscr & HD64465_PCCCSCR_PBD) {
856
            cscr &= ~HD64465_PCCCSCR_PSC;
857
            events |= SS_BATDEAD;       /* battery dead */
858
        }
859
        if (cscr & HD64465_PCCCSCR_PSC) {
860
            cscr &= ~HD64465_PCCCSCR_PSC;
861
            events |= SS_STSCHG;        /* STSCHG (status changed) signal */
862
        }
863
 
864
        if (cscr & HD64465_PCCCSCR_PIREQ) {
865
            cscr &= ~HD64465_PCCCSCR_PIREQ;
866
 
867
            /* This should have been dealt with during irq demux */
868
            printk(KERN_NOTICE MODNAME ": unexpected IREQ from card\n");
869
        }
870
 
871
        hs_out(sp, cscr, CSCR);
872
 
873
        if (events) {
874
            /*
875
             * Arrange for events to be reported to the registered
876
             * event handler function (from CardServices) in a process
877
             * context (keventd) "soon".
878
             */
879
            spin_lock(&hs_pending_event_lock);
880
            sp->pending_events |= events;
881
            spin_unlock(&hs_pending_event_lock);
882
 
883
            schedule_task(&hs_events_task);
884
        }
885
}
886
 
887
/*============================================================*/
888
 
889
static struct pccard_operations hs_operations = {
890
        hs_init,
891
        hs_suspend,
892
        hs_register_callback,
893
        hs_inquire_socket,
894
        hs_get_status,
895
        hs_get_socket,
896
        hs_set_socket,
897
        hs_get_io_map,
898
        hs_set_io_map,
899
        hs_get_mem_map,
900
        hs_set_mem_map,
901
        hs_proc_setup
902
};
903
 
904
static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
905
            unsigned int ctrl_base)
906
{
907
        unsigned short v;
908
        int i, err;
909
 
910
        memset(sp, 0, sizeof(*sp));
911
        sp->irq = irq;
912
        sp->mem_base = mem_base;
913
        sp->mem_length = 4*HD64465_PCC_WINDOW;  /* 16MB */
914
        sp->ctrl_base = ctrl_base;
915
 
916
        for (i=0 ; i<MAX_IO_WIN ; i++)
917
            sp->io_maps[i].map = i;
918
        for (i=0 ; i<MAX_WIN ; i++)
919
            sp->mem_maps[i].map = i;
920
 
921
        if ((sp->io_vma = get_vm_area(HS_IO_MAP_SIZE, VM_IOREMAP)) == 0)
922
            return -ENOMEM;
923
 
924
        hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp);
925
 
926
        if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0)
927
            return err;
928
        if (request_mem_region(sp->mem_base, sp->mem_length, MODNAME) == 0) {
929
            sp->mem_base = 0;
930
            return -ENOMEM;
931
        }
932
 
933
 
934
        /* According to section 3.2 of the PCMCIA standard, low-voltage
935
         * capable cards must implement cold insertion, i.e. Vpp and
936
         * Vcc set to 0 before card is inserted.
937
         */
938
        /*hs_set_voltages(sp, 0, 0);*/
939
 
940
        /* hi-Z the outputs to the card and set 16MB map mode */
941
        v = hs_in(sp, GCR);
942
        v &= ~HD64465_PCCGCR_PCCT;      /* memory-only card */
943
        hs_out(sp, v, GCR);
944
 
945
        v = hs_in(sp, GCR);
946
        v |= HD64465_PCCGCR_PDRV;       /* enable outputs to card */
947
        hs_out(sp, v, GCR);
948
 
949
        v = hs_in(sp, GCR);
950
        v |= HD64465_PCCGCR_PMMOD;      /* 16MB mapping mode */
951
        hs_out(sp, v, GCR);
952
 
953
        v = hs_in(sp, GCR);
954
        /* lowest 16MB of Common */
955
        v &= ~(HD64465_PCCGCR_PPA25|HD64465_PCCGCR_PPA24);
956
        hs_out(sp, v, GCR);
957
 
958
        hs_reset_socket(sp, 1);
959
 
960
        return 0;
961
}
962
 
963
static void hs_exit_socket(hs_socket_t *sp)
964
{
965
        unsigned short cscier, gcr;
966
 
967
        /* turn off interrupts in hardware */
968
        cscier = hs_in(sp, CSCIER);
969
        cscier = (cscier & IER_MASK) | IER_OFF;
970
        hs_out(sp, cscier, CSCIER);
971
 
972
        /* hi-Z the outputs to the card */
973
        gcr = hs_in(sp, GCR);
974
        gcr &= HD64465_PCCGCR_PDRV;
975
        hs_out(sp, gcr, GCR);
976
 
977
        /* power the card down */
978
        hs_set_voltages(sp, 0, 0);
979
 
980
        if (sp->mem_base != 0)
981
            release_mem_region(sp->mem_base, sp->mem_length);
982
        if (sp->irq != 0) {
983
            free_irq(sp->irq, hs_interrupt);
984
            hd64465_unregister_irq_demux(sp->irq);
985
        }
986
        if (sp->io_vma != 0)
987
            vfree(sp->io_vma->addr);
988
}
989
 
990
 
991
static int __init init_hs(void)
992
{
993
        servinfo_t serv;
994
        int i;
995
        unsigned short v;
996
 
997
        /*
998
         * Check API version
999
         */
1000
        pcmcia_get_card_services_info(&serv);
1001
        if (serv.Revision != CS_RELEASE_CODE) {
1002
            printk(KERN_NOTICE MODNAME ": Card Services release does not match!\n");
1003
            return -ENODEV;
1004
        }
1005
 
1006
/*      hd64465_io_debug = 1; */
1007
 
1008
        /* Wake both sockets out of STANDBY mode */
1009
        /* TODO: wait 15ms */
1010
        v = inw(HD64465_REG_SMSCR);
1011
        v &= ~(HD64465_SMSCR_PC0ST|HD64465_SMSCR_PC1ST);
1012
        outw(v, HD64465_REG_SMSCR);
1013
 
1014
        /* keep power controller out of shutdown mode */
1015
        v = inb(HD64465_REG_PCC0SCR);
1016
        v |= HD64465_PCCSCR_SHDN;
1017
        outb(v, HD64465_REG_PCC0SCR);
1018
 
1019
        /* use serial (TPS2206) power controller */
1020
        v = inb(HD64465_REG_PCC0CSCR);
1021
        v |= HD64465_PCCCSCR_PSWSEL;
1022
        outb(v, HD64465_REG_PCC0CSCR);
1023
 
1024
        hs_set_voltages(&hs_sockets[0], 0, 0);
1025
        hs_set_voltages(&hs_sockets[1], 0, 0);
1026
 
1027
        /*
1028
         * Setup hs_sockets[] structures and request system resources.
1029
         * TODO: on memory allocation failure, power down the socket
1030
         *       before quitting.
1031
         */
1032
        i = hs_init_socket(&hs_sockets[0],
1033
            HD64465_IRQ_PCMCIA0,
1034
            HD64465_PCC0_BASE,
1035
            HD64465_REG_PCC0ISR);
1036
        if (i < 0)
1037
            return i;
1038
        i = hs_init_socket(&hs_sockets[1],
1039
            HD64465_IRQ_PCMCIA1,
1040
            HD64465_PCC1_BASE,
1041
            HD64465_REG_PCC1ISR);
1042
        if (i < 0)
1043
            return i;
1044
 
1045
/*      hd64465_io_debug = 0; */
1046
 
1047
 
1048
        if (register_ss_entry(HS_MAX_SOCKETS, &hs_operations) != 0) {
1049
            for (i=0 ; i<HS_MAX_SOCKETS ; i++)
1050
                hs_exit_socket(&hs_sockets[i]);
1051
            return -ENODEV;
1052
        }
1053
 
1054
        printk(KERN_INFO "HD64465 PCMCIA bridge:\n");
1055
        for (i=0 ; i<HS_MAX_SOCKETS ; i++) {
1056
            hs_socket_t *sp = &hs_sockets[i];
1057
 
1058
            printk(KERN_INFO "  socket %d at 0x%08lx irq %d io window %ldK@0x%08lx\n",
1059
                i, sp->mem_base, sp->irq,
1060
                sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr);
1061
        }
1062
 
1063
        return 0;
1064
}
1065
 
1066
static void __exit exit_hs(void)
1067
{
1068
        u_long flags;
1069
        int i;
1070
 
1071
        save_and_cli(flags);
1072
 
1073
        /*
1074
         * Release kernel resources
1075
         */
1076
        for (i=0 ; i<HS_MAX_SOCKETS ; i++)
1077
            hs_exit_socket(&hs_sockets[i]);
1078
        unregister_ss_entry(&hs_operations);
1079
 
1080
        restore_flags(flags);
1081
}
1082
 
1083
module_init(init_hs);
1084
module_exit(exit_hs);
1085
 
1086
/*============================================================*/
1087
/*END*/

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.