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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [ssb/] [pcmcia.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Sonics Silicon Backplane
3
 * PCMCIA-Hostbus related functions
4
 *
5
 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
6
 * Copyright 2007 Michael Buesch <mb@bu3sch.de>
7
 *
8
 * Licensed under the GNU/GPL. See COPYING for details.
9
 */
10
 
11
#include <linux/ssb/ssb.h>
12
#include <linux/delay.h>
13
#include <linux/io.h>
14
 
15
#include <pcmcia/cs_types.h>
16
#include <pcmcia/cs.h>
17
#include <pcmcia/cistpl.h>
18
#include <pcmcia/ciscode.h>
19
#include <pcmcia/ds.h>
20
#include <pcmcia/cisreg.h>
21
 
22
#include "ssb_private.h"
23
 
24
 
25
/* Define the following to 1 to enable a printk on each coreswitch. */
26
#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG              0
27
 
28
 
29
int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
30
                              u8 coreidx)
31
{
32
        struct pcmcia_device *pdev = bus->host_pcmcia;
33
        int err;
34
        int attempts = 0;
35
        u32 cur_core;
36
        conf_reg_t reg;
37
        u32 addr;
38
        u32 read_addr;
39
 
40
        addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
41
        while (1) {
42
                reg.Action = CS_WRITE;
43
                reg.Offset = 0x2E;
44
                reg.Value = (addr & 0x0000F000) >> 12;
45
                err = pcmcia_access_configuration_register(pdev, &reg);
46
                if (err != CS_SUCCESS)
47
                        goto error;
48
                reg.Offset = 0x30;
49
                reg.Value = (addr & 0x00FF0000) >> 16;
50
                err = pcmcia_access_configuration_register(pdev, &reg);
51
                if (err != CS_SUCCESS)
52
                        goto error;
53
                reg.Offset = 0x32;
54
                reg.Value = (addr & 0xFF000000) >> 24;
55
                err = pcmcia_access_configuration_register(pdev, &reg);
56
                if (err != CS_SUCCESS)
57
                        goto error;
58
 
59
                read_addr = 0;
60
 
61
                reg.Action = CS_READ;
62
                reg.Offset = 0x2E;
63
                err = pcmcia_access_configuration_register(pdev, &reg);
64
                if (err != CS_SUCCESS)
65
                        goto error;
66
                read_addr |= ((u32)(reg.Value & 0x0F)) << 12;
67
                reg.Offset = 0x30;
68
                err = pcmcia_access_configuration_register(pdev, &reg);
69
                if (err != CS_SUCCESS)
70
                        goto error;
71
                read_addr |= ((u32)reg.Value) << 16;
72
                reg.Offset = 0x32;
73
                err = pcmcia_access_configuration_register(pdev, &reg);
74
                if (err != CS_SUCCESS)
75
                        goto error;
76
                read_addr |= ((u32)reg.Value) << 24;
77
 
78
                cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
79
                if (cur_core == coreidx)
80
                        break;
81
 
82
                if (attempts++ > SSB_BAR0_MAX_RETRIES)
83
                        goto error;
84
                udelay(10);
85
        }
86
 
87
        return 0;
88
error:
89
        ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
90
        return -ENODEV;
91
}
92
 
93
int ssb_pcmcia_switch_core(struct ssb_bus *bus,
94
                           struct ssb_device *dev)
95
{
96
        int err;
97
        unsigned long flags;
98
 
99
#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
100
        ssb_printk(KERN_INFO PFX
101
                   "Switching to %s core, index %d\n",
102
                   ssb_core_name(dev->id.coreid),
103
                   dev->core_index);
104
#endif
105
 
106
        spin_lock_irqsave(&bus->bar_lock, flags);
107
        err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
108
        if (!err)
109
                bus->mapped_device = dev;
110
        spin_unlock_irqrestore(&bus->bar_lock, flags);
111
 
112
        return err;
113
}
114
 
115
int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
116
{
117
        int attempts = 0;
118
        unsigned long flags;
119
        conf_reg_t reg;
120
        int res, err = 0;
121
 
122
        SSB_WARN_ON((seg != 0) && (seg != 1));
123
        reg.Offset = 0x34;
124
        reg.Function = 0;
125
        spin_lock_irqsave(&bus->bar_lock, flags);
126
        while (1) {
127
                reg.Action = CS_WRITE;
128
                reg.Value = seg;
129
                res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
130
                if (unlikely(res != CS_SUCCESS))
131
                        goto error;
132
                reg.Value = 0xFF;
133
                reg.Action = CS_READ;
134
                res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
135
                if (unlikely(res != CS_SUCCESS))
136
                        goto error;
137
 
138
                if (reg.Value == seg)
139
                        break;
140
 
141
                if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
142
                        goto error;
143
                udelay(10);
144
        }
145
        bus->mapped_pcmcia_seg = seg;
146
out_unlock:
147
        spin_unlock_irqrestore(&bus->bar_lock, flags);
148
        return err;
149
error:
150
        ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
151
        err = -ENODEV;
152
        goto out_unlock;
153
}
154
 
155
static int select_core_and_segment(struct ssb_device *dev,
156
                                   u16 *offset)
157
{
158
        struct ssb_bus *bus = dev->bus;
159
        int err;
160
        u8 need_segment;
161
 
162
        if (*offset >= 0x800) {
163
                *offset -= 0x800;
164
                need_segment = 1;
165
        } else
166
                need_segment = 0;
167
 
168
        if (unlikely(dev != bus->mapped_device)) {
169
                err = ssb_pcmcia_switch_core(bus, dev);
170
                if (unlikely(err))
171
                        return err;
172
        }
173
        if (unlikely(need_segment != bus->mapped_pcmcia_seg)) {
174
                err = ssb_pcmcia_switch_segment(bus, need_segment);
175
                if (unlikely(err))
176
                        return err;
177
        }
178
 
179
        return 0;
180
}
181
 
182
static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
183
{
184
        struct ssb_bus *bus = dev->bus;
185
 
186
        if (unlikely(select_core_and_segment(dev, &offset)))
187
                return 0xFFFF;
188
 
189
        return readw(bus->mmio + offset);
190
}
191
 
192
static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
193
{
194
        struct ssb_bus *bus = dev->bus;
195
        u32 lo, hi;
196
 
197
        if (unlikely(select_core_and_segment(dev, &offset)))
198
                return 0xFFFFFFFF;
199
        lo = readw(bus->mmio + offset);
200
        hi = readw(bus->mmio + offset + 2);
201
 
202
        return (lo | (hi << 16));
203
}
204
 
205
static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
206
{
207
        struct ssb_bus *bus = dev->bus;
208
 
209
        if (unlikely(select_core_and_segment(dev, &offset)))
210
                return;
211
        writew(value, bus->mmio + offset);
212
}
213
 
214
static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
215
{
216
        struct ssb_bus *bus = dev->bus;
217
 
218
        if (unlikely(select_core_and_segment(dev, &offset)))
219
                return;
220
        writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3);
221
        writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2);
222
        writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1);
223
        writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0);
224
}
225
 
226
/* Not "static", as it's used in main.c */
227
const struct ssb_bus_ops ssb_pcmcia_ops = {
228
        .read16         = ssb_pcmcia_read16,
229
        .read32         = ssb_pcmcia_read32,
230
        .write16        = ssb_pcmcia_write16,
231
        .write32        = ssb_pcmcia_write32,
232
};
233
 
234
int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
235
                              struct ssb_init_invariants *iv)
236
{
237
        //TODO
238
        return 0;
239
}
240
 
241
int ssb_pcmcia_init(struct ssb_bus *bus)
242
{
243
        conf_reg_t reg;
244
        int err;
245
 
246
        if (bus->bustype != SSB_BUSTYPE_PCMCIA)
247
                return 0;
248
 
249
        /* Switch segment to a known state and sync
250
         * bus->mapped_pcmcia_seg with hardware state. */
251
        ssb_pcmcia_switch_segment(bus, 0);
252
 
253
        /* Init IRQ routing */
254
        reg.Action = CS_READ;
255
        reg.Function = 0;
256
        if (bus->chip_id == 0x4306)
257
                reg.Offset = 0x00;
258
        else
259
                reg.Offset = 0x80;
260
        err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
261
        if (err != CS_SUCCESS)
262
                goto error;
263
        reg.Action = CS_WRITE;
264
        reg.Value |= 0x04 | 0x01;
265
        err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
266
        if (err != CS_SUCCESS)
267
                goto error;
268
 
269
        return 0;
270
error:
271
        return -ENODEV;
272
}

powered by: WebSVN 2.1.0

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