Subversion Repositories HelenOS

Rev

Rev 3502 | Rev 3549 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3502 Rev 3514
1
/*
1
/*
2
 * Copyright (c) 2008 Pavel Rimsky
2
 * Copyright (c) 2008 Pavel Rimsky
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup sparc64
29
/** @addtogroup sparc64
30
 * @{
30
 * @{
31
 */
31
 */
32
/**
32
/**
33
 * @file
33
 * @file
34
 * @brief   SGCN driver.
34
 * @brief   SGCN driver.
35
 */
35
 */
36
 
36
 
37
#include <arch/drivers/sgcn.h>
37
#include <arch/drivers/sgcn.h>
38
#include <genarch/ofw/ofw_tree.h>
38
#include <genarch/ofw/ofw_tree.h>
39
#include <debug.h>
39
#include <debug.h>
40
#include <func.h>
40
#include <func.h>
41
#include <print.h>
41
#include <print.h>
42
#include <mm/page.h>
42
#include <mm/page.h>
43
#include <console/chardev.h>
43
#include <console/chardev.h>
44
#include <console/console.h>
44
#include <console/console.h>
45
#include <synch/spinlock.h>
45
#include <synch/spinlock.h>
46
 
46
 
47
/*
47
/*
48
 * Physical address at which the SBBC starts. This value has been obtained
48
 * Physical address at which the SBBC starts. This value has been obtained
49
 * by inspecting (using Simics) memory accesses made by OBP. It is valid
49
 * by inspecting (using Simics) memory accesses made by OBP. It is valid
50
 * for the Simics-simulated Serengeti machine. The author of this code is
50
 * for the Simics-simulated Serengeti machine. The author of this code is
51
 * not sure whether this value is valid generally.
51
 * not sure whether this value is valid generally.
52
 */
52
 */
53
#define SBBC_START      0x63000000000
53
#define SBBC_START      0x63000000000
54
 
54
 
55
/* offset of SRAM within the SBBC memory */
55
/* offset of SRAM within the SBBC memory */
56
#define SBBC_SRAM_OFFSET    0x900000
56
#define SBBC_SRAM_OFFSET    0x900000
57
 
57
 
58
/* magic string contained at the beginning of SRAM */
58
/* magic string contained at the beginning of SRAM */
59
#define SRAM_TOC_MAGIC      "TOCSRAM"
59
#define SRAM_TOC_MAGIC      "TOCSRAM"
60
 
60
 
61
/*
61
/*
62
 * Key into the SRAM table of contents which identifies the entry
62
 * Key into the SRAM table of contents which identifies the entry
63
 * describing the OBP console buffer. It is worth mentioning
63
 * describing the OBP console buffer. It is worth mentioning
64
 * that the OBP console buffer is not the only console buffer
64
 * that the OBP console buffer is not the only console buffer
65
 * which can be used. It is, however, used because when the kernel
65
 * which can be used. It is, however, used because when the kernel
66
 * is running, the OBP buffer is not used by OBP any more but OBP
66
 * is running, the OBP buffer is not used by OBP any more but OBP
67
 * has already made neccessary arangements so that the output will
67
 * has already made neccessary arangements so that the output will
68
 * be read from the OBP buffer and input will go to the OBP buffer.
68
 * be read from the OBP buffer and input will go to the OBP buffer.
69
 * Therefore HelenOS needs to make no such arrangements any more.
69
 * Therefore HelenOS needs to make no such arrangements any more.
70
 */
70
 */
71
#define CONSOLE_KEY     "OBPCONS"
71
#define CONSOLE_KEY     "OBPCONS"
72
 
72
 
73
/* magic string contained at the beginning of the console buffer */
73
/* magic string contained at the beginning of the console buffer */
74
#define SGCN_BUFFER_MAGIC   "CON"
74
#define SGCN_BUFFER_MAGIC   "CON"
75
 
75
 
76
 
76
 
77
/*
77
/*
78
 * Returns a pointer to the object of a given type which is placed at the given
78
 * Returns a pointer to the object of a given type which is placed at the given
79
 * offset from the SRAM beginning.
79
 * offset from the SRAM beginning.
80
 */
80
 */
81
#define SRAM(type, offset)  ((type *) (sram_begin + (offset)))
81
#define SRAM(type, offset)  ((type *) (sram_begin + (offset)))
82
 
82
 
83
/* Returns a pointer to the SRAM table of contents. */
83
/* Returns a pointer to the SRAM table of contents. */
84
#define SRAM_TOC        (SRAM(iosram_toc_t, 0))
84
#define SRAM_TOC        (SRAM(iosram_toc_t, 0))
85
 
85
 
86
/*
86
/*
87
 * Returns a pointer to the object of a given type which is placed at the given
87
 * Returns a pointer to the object of a given type which is placed at the given
88
 * offset from the console buffer beginning.
88
 * offset from the console buffer beginning.
89
 */
89
 */
90
#define SGCN_BUFFER(type, offset) \
90
#define SGCN_BUFFER(type, offset) \
91
                ((type *) (sgcn_buffer_begin + (offset)))
91
                ((type *) (sgcn_buffer_begin + (offset)))
92
 
92
 
93
/* Returns a pointer to the console buffer header. */
93
/* Returns a pointer to the console buffer header. */
94
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
94
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
95
 
95
 
96
 
96
 
97
/* starting address of SRAM, will be set by the init_sram_begin function */
97
/* starting address of SRAM, will be set by the init_sram_begin function */
98
static uintptr_t sram_begin;
98
static uintptr_t sram_begin;
99
 
99
 
100
/*
100
/*
101
 * starting address of the SGCN buffer, will be set by the
101
 * starting address of the SGCN buffer, will be set by the
102
 * init_sgcn_buffer_begin function
102
 * init_sgcn_buffer_begin function
103
 */
103
 */
104
static uintptr_t sgcn_buffer_begin;
104
static uintptr_t sgcn_buffer_begin;
105
 
105
 
106
 
106
 
107
/*
107
/*
108
 * Ensures that writing to the buffer and consequent update of the write pointer
108
 * Ensures that writing to the buffer and consequent update of the write pointer
109
 * are together one atomic operation.
109
 * are together one atomic operation.
110
 */
110
 */
111
SPINLOCK_INITIALIZE(sgcn_output_lock);
111
SPINLOCK_INITIALIZE(sgcn_output_lock);
112
 
112
 
-
 
113
/*
-
 
114
 * Ensures that reading from the buffer and consequent update of the read
-
 
115
 * pointer are together one atomic operation.
-
 
116
 */
-
 
117
SPINLOCK_INITIALIZE(sgcn_input_lock);
113
 
118
 
114
static void sgcn_putchar(struct chardev * cd, const char c);
-
 
115
 
119
 
-
 
120
/* functions referenced from definitions of I/O operations structures */
-
 
121
static void sgcn_noop(chardev_t *);
-
 
122
static void sgcn_putchar(chardev_t *, const char);
-
 
123
static char sgcn_key_read(chardev_t *);
-
 
124
 
116
/** character device operations */
125
/** character device output operations */
117
static chardev_operations_t sgcn_ops = {
126
static chardev_operations_t sgcn_output_ops = {
118
    .suspend = NULL,
127
    .suspend = sgcn_noop,
119
    .resume = NULL,
128
    .resume = sgcn_noop,
120
    .write = sgcn_putchar,
129
    .write = sgcn_putchar,
121
    .read = NULL
130
    .read = NULL
122
};
131
};
123
 
132
 
-
 
133
/** character device input operations */
-
 
134
static chardev_operations_t sgcn_input_ops = {
-
 
135
    .suspend = sgcn_noop,
-
 
136
    .resume = sgcn_noop,
-
 
137
    .read = sgcn_key_read
-
 
138
};
-
 
139
 
-
 
140
 
124
/** SGCN character device */
141
/** SGCN character output device */
125
chardev_t sgcn_stdout;
142
chardev_t sgcn_stdout;
126
 
143
 
-
 
144
/** SGCN character input device */
-
 
145
chardev_t sgcn_input;
-
 
146
 
-
 
147
 
127
/**
148
/**
128
 * Initializes the starting address of SRAM.
149
 * Initializes the starting address of SRAM.
129
 *
150
 *
130
 * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
151
 * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
131
 * physical memory, where C is the value read from the "iosram-toc"
152
 * physical memory, where C is the value read from the "iosram-toc"
132
 * property of the "/chosen" OBP node. The sram_begin variable will
153
 * property of the "/chosen" OBP node. The sram_begin variable will
133
 * be set to the virtual address which maps to the SRAM physical
154
 * be set to the virtual address which maps to the SRAM physical
134
 * address.
155
 * address.
135
 */
156
 */
136
static void init_sram_begin(void)
157
static void init_sram_begin(void)
137
{
158
{
138
    ofw_tree_node_t *chosen;
159
    ofw_tree_node_t *chosen;
139
    ofw_tree_property_t *iosram_toc;
160
    ofw_tree_property_t *iosram_toc;
140
 
161
 
141
    chosen = ofw_tree_lookup("/chosen");
162
    chosen = ofw_tree_lookup("/chosen");
142
    if (!chosen)
163
    if (!chosen)
143
        panic("Can't find /chosen.\n");
164
        panic("Can't find /chosen.\n");
144
 
165
 
145
    iosram_toc = ofw_tree_getprop(chosen, "iosram-toc");
166
    iosram_toc = ofw_tree_getprop(chosen, "iosram-toc");
146
    if (!iosram_toc)
167
    if (!iosram_toc)
147
        panic("Can't find property \"iosram-toc\".\n");
168
        panic("Can't find property \"iosram-toc\".\n");
148
    if (!iosram_toc->value)
169
    if (!iosram_toc->value)
149
        panic("Can't find SRAM TOC.\n");
170
        panic("Can't find SRAM TOC.\n");
150
 
171
 
151
    sram_begin = hw_map(
172
    sram_begin = hw_map(
152
        SBBC_START + SBBC_SRAM_OFFSET
173
        SBBC_START + SBBC_SRAM_OFFSET
153
        + *((uint32_t *) iosram_toc->value),
174
        + *((uint32_t *) iosram_toc->value),
154
        128 * 1024);
175
        128 * 1024);
155
}
176
}
156
 
177
 
157
/**
178
/**
158
 * Initializes the starting address of the SGCN buffer.
179
 * Initializes the starting address of the SGCN buffer.
159
 *
180
 *
160
 * The offset of the SGCN buffer within SRAM is obtained from the
181
 * The offset of the SGCN buffer within SRAM is obtained from the
161
 * SRAM table of contents. The table of contents contains
182
 * SRAM table of contents. The table of contents contains
162
 * information about several buffers, among which there is an OBP
183
 * information about several buffers, among which there is an OBP
163
 * console buffer - this one will be used as the SGCN buffer.
184
 * console buffer - this one will be used as the SGCN buffer.
164
 */
185
 */
165
static void sgcn_buffer_begin_init(void)
186
static void sgcn_buffer_begin_init(void)
166
{
187
{
167
    init_sram_begin();
188
    init_sram_begin();
168
       
189
       
169
    ASSERT(strcmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
190
    ASSERT(strcmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
170
   
191
   
171
    /* lookup TOC entry with the correct key */
192
    /* lookup TOC entry with the correct key */
172
    uint32_t i;
193
    uint32_t i;
173
    for (i = 0; i < MAX_TOC_ENTRIES; i++) {
194
    for (i = 0; i < MAX_TOC_ENTRIES; i++) {
174
        if (strcmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
195
        if (strcmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
175
            break;
196
            break;
176
    }
197
    }
177
    ASSERT(i < MAX_TOC_ENTRIES);
198
    ASSERT(i < MAX_TOC_ENTRIES);
178
   
199
   
179
    sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
200
    sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
180
}
201
}
181
 
202
 
182
/**
203
/**
-
 
204
 * Default suspend/resume operation for the input device.
-
 
205
 */
-
 
206
static void sgcn_noop(chardev_t *d)
-
 
207
{
-
 
208
}
-
 
209
 
-
 
210
/**
183
 * Writes a single character to the SGCN (circular) output buffer
211
 * Writes a single character to the SGCN (circular) output buffer
184
 * and updates the output write pointer so that SGCN gets to know
212
 * and updates the output write pointer so that SGCN gets to know
185
 * that the character has been written.
213
 * that the character has been written.
186
 */
214
 */
187
static void sgcn_do_putchar(const char c)
215
static void sgcn_do_putchar(const char c)
188
{
216
{
189
    uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
217
    uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
190
    uint32_t end = SGCN_BUFFER_HEADER->out_end;
218
    uint32_t end = SGCN_BUFFER_HEADER->out_end;
191
    uint32_t size = end - begin;
219
    uint32_t size = end - begin;
192
   
220
   
193
    /* we need pointers to volatile variables */
221
    /* we need pointers to volatile variables */
194
    volatile char *buf_ptr = (volatile char *)
222
    volatile char *buf_ptr = (volatile char *)
195
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
223
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
196
    volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
224
    volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
197
    volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
225
    volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
198
 
226
 
199
    /*
227
    /*
200
     * Write the character and increment the write pointer modulo the
228
     * Write the character and increment the write pointer modulo the
201
     * output buffer size. Note that if we are to rewrite a character
229
     * output buffer size. Note that if we are to rewrite a character
202
     * which has not been read by the SGCN controller yet (i.e. the output
230
     * which has not been read by the SGCN controller yet (i.e. the output
203
     * buffer is full), we need to wait until the controller reads some more
231
     * buffer is full), we need to wait until the controller reads some more
204
     * characters. We wait actively, which means that all threads waiting
232
     * characters. We wait actively, which means that all threads waiting
205
     * for the lock are blocked. However, this situation is
233
     * for the lock are blocked. However, this situation is
206
     *   1) rare - the output buffer is big, so filling the whole
234
     *   1) rare - the output buffer is big, so filling the whole
207
     *             output buffer is improbable
235
     *             output buffer is improbable
208
     *   2) short-lasting - it will take the controller only a fraction
236
     *   2) short-lasting - it will take the controller only a fraction
209
     *             of millisecond to pick the unread characters up
237
     *             of millisecond to pick the unread characters up
210
     *   3) not serious - the blocked threads are those that print something
238
     *   3) not serious - the blocked threads are those that print something
211
     *             to user console, which is not a time-critical operation
239
     *             to user console, which is not a time-critical operation
212
     */
240
     */
213
    uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
241
    uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
214
    while (*out_rdptr_ptr == new_wrptr)
242
    while (*out_rdptr_ptr == new_wrptr)
215
        ;
243
        ;
216
    *buf_ptr = c;
244
    *buf_ptr = c;
217
    *out_wrptr_ptr = new_wrptr;
245
    *out_wrptr_ptr = new_wrptr;
218
}
246
}
219
 
247
 
220
/**
248
/**
221
 * SGCN output operation. Prints a single character to the SGCN. If the line
249
 * SGCN output operation. Prints a single character to the SGCN. If the line
222
 * feed character is written ('\n'), the carriage return character ('\r') is
250
 * feed character is written ('\n'), the carriage return character ('\r') is
223
 * written straight away.
251
 * written straight away.
224
 */
252
 */
225
static void sgcn_putchar(struct chardev * cd, const char c)
253
static void sgcn_putchar(struct chardev * cd, const char c)
226
{
254
{
227
    spinlock_lock(&sgcn_output_lock);
255
    spinlock_lock(&sgcn_output_lock);
228
   
256
   
229
    sgcn_do_putchar(c);
257
    sgcn_do_putchar(c);
230
    if (c == '\n') {
258
    if (c == '\n') {
231
        sgcn_do_putchar('\r');
259
        sgcn_do_putchar('\r');
232
    }
260
    }
233
   
261
   
234
    spinlock_unlock(&sgcn_output_lock);
262
    spinlock_unlock(&sgcn_output_lock);
235
}
263
}
236
 
264
 
237
/**
265
/**
-
 
266
 * Called when actively reading the character. Not implemented yet.
-
 
267
 */
-
 
268
static char sgcn_key_read(chardev_t *d)
-
 
269
{
-
 
270
    return (char) 0;
-
 
271
}
-
 
272
 
-
 
273
/**
-
 
274
 * Function regularly called by the keyboard polling thread. Finds out whether
-
 
275
 * there are some unread characters in the input queue. If so, it picks them up
-
 
276
 * and sends them to the upper layers of HelenOS.
-
 
277
 */
-
 
278
void sgcn_poll(void)
-
 
279
{
-
 
280
    spinlock_lock(&sgcn_input_lock);
-
 
281
   
-
 
282
    char c;
-
 
283
    uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
-
 
284
    uint32_t end = SGCN_BUFFER_HEADER->in_end;
-
 
285
    uint32_t size = end - begin;
-
 
286
   
-
 
287
    /* we need pointers to volatile variables */
-
 
288
    volatile char *buf_ptr = (volatile char *)
-
 
289
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
-
 
290
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
-
 
291
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
-
 
292
   
-
 
293
    while (*in_rdptr_ptr != *in_wrptr_ptr) {
-
 
294
        c = *buf_ptr;
-
 
295
        *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
-
 
296
        buf_ptr = (volatile char *)
-
 
297
            SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
-
 
298
        chardev_push_character(&sgcn_input, c);
-
 
299
        if (c == '\r')
-
 
300
            chardev_push_character(&sgcn_input, '\n');
-
 
301
    }
-
 
302
   
-
 
303
    spinlock_unlock(&sgcn_input_lock);
-
 
304
}
-
 
305
 
-
 
306
/**
238
 * A public function which initializes I/O from/to Serengeti console
307
 * A public function which initializes I/O from/to Serengeti console
239
 * and sets it as a default input/output.
308
 * and sets it as a default input/output.
240
 */
309
 */
241
void sgcn_init(void)
310
void sgcn_init(void)
242
{
311
{
243
    sgcn_buffer_begin_init();
312
    sgcn_buffer_begin_init();
244
   
313
   
245
    chardev_initialize("sgcn_output", &sgcn_stdout, &sgcn_ops);
314
    chardev_initialize("sgcn_output", &sgcn_stdout, &sgcn_output_ops);
246
    stdout = &sgcn_stdout;
315
    stdout = &sgcn_stdout;
247
   
316
   
248
   
-
 
249
    printf("SGCN buffer begin = %d, in read ptr = %" PRIu32 ".", sgcn_buffer_begin, SGCN_BUFFER_HEADER->in_wrptr);
317
    chardev_initialize("sgcn_input", &sgcn_input, &sgcn_input_ops);
-
 
318
    stdin = &sgcn_input;
250
}
319
}
251
 
320
 
252
/** @}
321
/** @}
253
 */
322
 */