diff options
| author | Geoff Levand <geoffrey.levand@am.sony.com> | 2006-12-08 21:27:47 -0500 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2006-12-10 21:49:53 -0500 |
| commit | 74e95d5de9d8eb243cda68b546bdb29f6ef0f01c (patch) | |
| tree | c1f3a14628510af3ca134da5db409dcc8d428e99 /drivers/ps3 | |
| parent | 0204568a088fecd5478153504f9476ee2c46d5bf (diff) | |
[POWERPC] ps3: Add vuart support
Adds support for the PS3 virtual UART (vuart). The vuart provides a
bi-directional byte stream data link between logical partitions.
This is needed for the ps3 graphics driver and the ps3 power
control support to be able to communicate with the lv1 policy
module.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers/ps3')
| -rw-r--r-- | drivers/ps3/Makefile | 1 | ||||
| -rw-r--r-- | drivers/ps3/vuart.c | 965 | ||||
| -rw-r--r-- | drivers/ps3/vuart.h | 94 |
3 files changed, 1060 insertions, 0 deletions
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile index b52d547b7a..8433eb7562 100644 --- a/drivers/ps3/Makefile +++ b/drivers/ps3/Makefile | |||
| @@ -1 +1,2 @@ | |||
| 1 | obj-y += system-bus.o | 1 | obj-y += system-bus.o |
| 2 | obj-$(CONFIG_PS3_VUART) += vuart.o | ||
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c new file mode 100644 index 0000000000..6974f65bcd --- /dev/null +++ b/drivers/ps3/vuart.c | |||
| @@ -0,0 +1,965 @@ | |||
| 1 | /* | ||
| 2 | * PS3 virtual uart | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 Sony Computer Entertainment Inc. | ||
| 5 | * Copyright 2006 Sony Corp. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; version 2 of the License. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <asm/ps3.h> | ||
| 25 | |||
| 26 | #include <asm/lv1call.h> | ||
| 27 | #include <asm/bitops.h> | ||
| 28 | |||
| 29 | #include "vuart.h" | ||
| 30 | |||
| 31 | MODULE_AUTHOR("Sony Corporation"); | ||
| 32 | MODULE_LICENSE("GPL v2"); | ||
| 33 | MODULE_DESCRIPTION("ps3 vuart"); | ||
| 34 | |||
| 35 | /** | ||
| 36 | * vuart - An inter-partition data link service. | ||
| 37 | * port 0: PS3 AV Settings. | ||
| 38 | * port 2: PS3 System Manager. | ||
| 39 | * | ||
| 40 | * The vuart provides a bi-directional byte stream data link between logical | ||
| 41 | * partitions. Its primary role is as a communications link between the guest | ||
| 42 | * OS and the system policy module. The current HV does not support any | ||
| 43 | * connections other than those listed. | ||
| 44 | */ | ||
| 45 | |||
| 46 | enum {PORT_COUNT = 3,}; | ||
| 47 | |||
| 48 | enum vuart_param { | ||
| 49 | PARAM_TX_TRIGGER = 0, | ||
| 50 | PARAM_RX_TRIGGER = 1, | ||
| 51 | PARAM_INTERRUPT_MASK = 2, | ||
| 52 | PARAM_RX_BUF_SIZE = 3, /* read only */ | ||
| 53 | PARAM_RX_BYTES = 4, /* read only */ | ||
| 54 | PARAM_TX_BUF_SIZE = 5, /* read only */ | ||
| 55 | PARAM_TX_BYTES = 6, /* read only */ | ||
| 56 | PARAM_INTERRUPT_STATUS = 7, /* read only */ | ||
| 57 | }; | ||
| 58 | |||
| 59 | enum vuart_interrupt_bit { | ||
| 60 | INTERRUPT_BIT_TX = 0, | ||
| 61 | INTERRUPT_BIT_RX = 1, | ||
| 62 | INTERRUPT_BIT_DISCONNECT = 2, | ||
| 63 | }; | ||
| 64 | |||
| 65 | enum vuart_interrupt_mask { | ||
| 66 | INTERRUPT_MASK_TX = 1, | ||
| 67 | INTERRUPT_MASK_RX = 2, | ||
| 68 | INTERRUPT_MASK_DISCONNECT = 4, | ||
| 69 | }; | ||
| 70 | |||
| 71 | /** | ||
| 72 | * struct ports_bmp - bitmap indicating ports needing service. | ||
| 73 | * | ||
| 74 | * A 256 bit read only bitmap indicating ports needing service. Do not write | ||
| 75 | * to these bits. Must not cross a page boundary. | ||
| 76 | */ | ||
| 77 | |||
| 78 | struct ports_bmp { | ||
| 79 | u64 status; | ||
| 80 | u64 unused[3]; | ||
| 81 | } __attribute__ ((aligned (32))); | ||
| 82 | |||
| 83 | /* redefine dev_dbg to do a syntax check */ | ||
| 84 | |||
| 85 | #if !defined(DEBUG) | ||
| 86 | #undef dev_dbg | ||
| 87 | static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( | ||
| 88 | const struct device *_dev, const char *fmt, ...) {return 0;} | ||
| 89 | #endif | ||
| 90 | |||
| 91 | #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__) | ||
| 92 | static void __attribute__ ((unused)) _dump_ports_bmp( | ||
| 93 | const struct ports_bmp* bmp, const char* func, int line) | ||
| 94 | { | ||
| 95 | pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status); | ||
| 96 | } | ||
| 97 | |||
| 98 | static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id, | ||
| 99 | unsigned int *port_number) | ||
| 100 | { | ||
| 101 | switch(match_id) { | ||
| 102 | case PS3_MATCH_ID_AV_SETTINGS: | ||
| 103 | *port_number = 0; | ||
| 104 | return 0; | ||
| 105 | case PS3_MATCH_ID_SYSTEM_MANAGER: | ||
| 106 | *port_number = 2; | ||
| 107 | return 0; | ||
| 108 | default: | ||
| 109 | WARN_ON(1); | ||
| 110 | *port_number = UINT_MAX; | ||
| 111 | return -EINVAL; | ||
| 112 | }; | ||
| 113 | } | ||
| 114 | |||
| 115 | #define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__) | ||
| 116 | static void __attribute__ ((unused)) _dump_port_params(unsigned int port_number, | ||
| 117 | const char* func, int line) | ||
| 118 | { | ||
| 119 | #if defined(DEBUG) | ||
| 120 | static const char *strings[] = { | ||
| 121 | "tx_trigger ", | ||
| 122 | "rx_trigger ", | ||
| 123 | "interrupt_mask ", | ||
| 124 | "rx_buf_size ", | ||
| 125 | "rx_bytes ", | ||
| 126 | "tx_buf_size ", | ||
| 127 | "tx_bytes ", | ||
| 128 | "interrupt_status", | ||
| 129 | }; | ||
| 130 | int result; | ||
| 131 | unsigned int i; | ||
| 132 | u64 value; | ||
| 133 | |||
| 134 | for (i = 0; i < ARRAY_SIZE(strings); i++) { | ||
| 135 | result = lv1_get_virtual_uart_param(port_number, i, &value); | ||
| 136 | |||
| 137 | if (result) { | ||
| 138 | pr_debug("%s:%d: port_%u: %s failed: %s\n", func, line, | ||
| 139 | port_number, strings[i], ps3_result(result)); | ||
| 140 | continue; | ||
| 141 | } | ||
| 142 | pr_debug("%s:%d: port_%u: %s = %lxh\n", | ||
| 143 | func, line, port_number, strings[i], value); | ||
| 144 | } | ||
| 145 | #endif | ||
| 146 | } | ||
| 147 | |||
| 148 | struct vuart_triggers { | ||
| 149 | unsigned long rx; | ||
| 150 | unsigned long tx; | ||
| 151 | }; | ||
| 152 | |||
| 153 | int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | ||
| 154 | struct vuart_triggers *trig) | ||
| 155 | { | ||
| 156 | int result; | ||
| 157 | unsigned long size; | ||
| 158 | unsigned long val; | ||
| 159 | |||
| 160 | result = lv1_get_virtual_uart_param(dev->port_number, | ||
| 161 | PARAM_TX_TRIGGER, &trig->tx); | ||
| 162 | |||
| 163 | if (result) { | ||
| 164 | dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n", | ||
| 165 | __func__, __LINE__, ps3_result(result)); | ||
| 166 | return result; | ||
| 167 | } | ||
| 168 | |||
| 169 | result = lv1_get_virtual_uart_param(dev->port_number, | ||
| 170 | PARAM_RX_BUF_SIZE, &size); | ||
| 171 | |||
| 172 | if (result) { | ||
| 173 | dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n", | ||
| 174 | __func__, __LINE__, ps3_result(result)); | ||
| 175 | return result; | ||
| 176 | } | ||
| 177 | |||
| 178 | result = lv1_get_virtual_uart_param(dev->port_number, | ||
| 179 | PARAM_RX_TRIGGER, &val); | ||
| 180 | |||
| 181 | if (result) { | ||
| 182 | dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n", | ||
| 183 | __func__, __LINE__, ps3_result(result)); | ||
| 184 | return result; | ||
| 185 | } | ||
| 186 | |||
| 187 | trig->rx = size - val; | ||
| 188 | |||
| 189 | dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n", __func__, __LINE__, | ||
| 190 | trig->tx, trig->rx); | ||
| 191 | |||
| 192 | return result; | ||
| 193 | } | ||
| 194 | |||
| 195 | int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | ||
| 196 | unsigned int rx) | ||
| 197 | { | ||
| 198 | int result; | ||
| 199 | unsigned long size; | ||
| 200 | |||
| 201 | result = lv1_set_virtual_uart_param(dev->port_number, | ||
| 202 | PARAM_TX_TRIGGER, tx); | ||
| 203 | |||
| 204 | if (result) { | ||
| 205 | dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n", | ||
| 206 | __func__, __LINE__, ps3_result(result)); | ||
| 207 | return result; | ||
| 208 | } | ||
| 209 | |||
| 210 | result = lv1_get_virtual_uart_param(dev->port_number, | ||
| 211 | PARAM_RX_BUF_SIZE, &size); | ||
| 212 | |||
| 213 | if (result) { | ||
| 214 | dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n", | ||
| 215 | __func__, __LINE__, ps3_result(result)); | ||
| 216 | return result; | ||
| 217 | } | ||
