0001
0002
0003
0004
0005
0006
0007
0008 #undef DEBUG
0009
0010 #include <linux/types.h>
0011 #include <linux/init.h>
0012 #include <linux/delay.h>
0013 #include <linux/slab.h>
0014 #include <linux/console.h>
0015 #include <linux/of.h>
0016 #include <linux/of_irq.h>
0017 #include <linux/of_platform.h>
0018 #include <linux/export.h>
0019 #include <linux/interrupt.h>
0020
0021 #include <asm/hvconsole.h>
0022 #include <asm/firmware.h>
0023 #include <asm/hvsi.h>
0024 #include <asm/udbg.h>
0025 #include <asm/opal.h>
0026
0027 #include "hvc_console.h"
0028
0029 static const char hvc_opal_name[] = "hvc_opal";
0030
0031 static const struct of_device_id hvc_opal_match[] = {
0032 { .name = "serial", .compatible = "ibm,opal-console-raw" },
0033 { .name = "serial", .compatible = "ibm,opal-console-hvsi" },
0034 { },
0035 };
0036
0037 typedef enum hv_protocol {
0038 HV_PROTOCOL_RAW,
0039 HV_PROTOCOL_HVSI
0040 } hv_protocol_t;
0041
0042 struct hvc_opal_priv {
0043 hv_protocol_t proto;
0044 struct hvsi_priv hvsi;
0045 };
0046 static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES];
0047
0048
0049 static struct hvc_opal_priv hvc_opal_boot_priv;
0050 static u32 hvc_opal_boot_termno;
0051
0052 static const struct hv_ops hvc_opal_raw_ops = {
0053 .get_chars = opal_get_chars,
0054 .put_chars = opal_put_chars,
0055 .flush = opal_flush_chars,
0056 .notifier_add = notifier_add_irq,
0057 .notifier_del = notifier_del_irq,
0058 .notifier_hangup = notifier_hangup_irq,
0059 };
0060
0061 static int hvc_opal_hvsi_get_chars(uint32_t vtermno, char *buf, int count)
0062 {
0063 struct hvc_opal_priv *pv = hvc_opal_privs[vtermno];
0064
0065 if (WARN_ON(!pv))
0066 return -ENODEV;
0067
0068 return hvsilib_get_chars(&pv->hvsi, buf, count);
0069 }
0070
0071 static int hvc_opal_hvsi_put_chars(uint32_t vtermno, const char *buf, int count)
0072 {
0073 struct hvc_opal_priv *pv = hvc_opal_privs[vtermno];
0074
0075 if (WARN_ON(!pv))
0076 return -ENODEV;
0077
0078 return hvsilib_put_chars(&pv->hvsi, buf, count);
0079 }
0080
0081 static int hvc_opal_hvsi_open(struct hvc_struct *hp, int data)
0082 {
0083 struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno];
0084 int rc;
0085
0086 pr_devel("HVSI@%x: do open !\n", hp->vtermno);
0087
0088 rc = notifier_add_irq(hp, data);
0089 if (rc)
0090 return rc;
0091
0092 return hvsilib_open(&pv->hvsi, hp);
0093 }
0094
0095 static void hvc_opal_hvsi_close(struct hvc_struct *hp, int data)
0096 {
0097 struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno];
0098
0099 pr_devel("HVSI@%x: do close !\n", hp->vtermno);
0100
0101 hvsilib_close(&pv->hvsi, hp);
0102
0103 notifier_del_irq(hp, data);
0104 }
0105
0106 static void hvc_opal_hvsi_hangup(struct hvc_struct *hp, int data)
0107 {
0108 struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno];
0109
0110 pr_devel("HVSI@%x: do hangup !\n", hp->vtermno);
0111
0112 hvsilib_close(&pv->hvsi, hp);
0113
0114 notifier_hangup_irq(hp, data);
0115 }
0116
0117 static int hvc_opal_hvsi_tiocmget(struct hvc_struct *hp)
0118 {
0119 struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno];
0120
0121 if (!pv)
0122 return -EINVAL;
0123 return pv->hvsi.mctrl;
0124 }
0125
0126 static int hvc_opal_hvsi_tiocmset(struct hvc_struct *hp, unsigned int set,
0127 unsigned int clear)
0128 {
0129 struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno];
0130
0131 pr_devel("HVSI@%x: Set modem control, set=%x,clr=%x\n",
0132 hp->vtermno, set, clear);
0133
0134 if (set & TIOCM_DTR)
0135 hvsilib_write_mctrl(&pv->hvsi, 1);
0136 else if (clear & TIOCM_DTR)
0137 hvsilib_write_mctrl(&pv->hvsi, 0);
0138
0139 return 0;
0140 }
0141
0142 static const struct hv_ops hvc_opal_hvsi_ops = {
0143 .get_chars = hvc_opal_hvsi_get_chars,
0144 .put_chars = hvc_opal_hvsi_put_chars,
0145 .flush = opal_flush_chars,
0146 .notifier_add = hvc_opal_hvsi_open,
0147 .notifier_del = hvc_opal_hvsi_close,
0148 .notifier_hangup = hvc_opal_hvsi_hangup,
0149 .tiocmget = hvc_opal_hvsi_tiocmget,
0150 .tiocmset = hvc_opal_hvsi_tiocmset,
0151 };
0152
0153 static int hvc_opal_probe(struct platform_device *dev)
0154 {
0155 const struct hv_ops *ops;
0156 struct hvc_struct *hp;
0157 struct hvc_opal_priv *pv;
0158 hv_protocol_t proto;
0159 unsigned int termno, irq, boot = 0;
0160 const __be32 *reg;
0161
0162 if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) {
0163 proto = HV_PROTOCOL_RAW;
0164 ops = &hvc_opal_raw_ops;
0165 } else if (of_device_is_compatible(dev->dev.of_node,
0166 "ibm,opal-console-hvsi")) {
0167 proto = HV_PROTOCOL_HVSI;
0168 ops = &hvc_opal_hvsi_ops;
0169 } else {
0170 pr_err("hvc_opal: Unknown protocol for %pOF\n",
0171 dev->dev.of_node);
0172 return -ENXIO;
0173 }
0174
0175 reg = of_get_property(dev->dev.of_node, "reg", NULL);
0176 termno = reg ? be32_to_cpup(reg) : 0;
0177
0178
0179 if (hvc_opal_privs[termno] == &hvc_opal_boot_priv) {
0180 pv = hvc_opal_privs[termno];
0181 boot = 1;
0182 } else if (hvc_opal_privs[termno] == NULL) {
0183 pv = kzalloc(sizeof(struct hvc_opal_priv), GFP_KERNEL);
0184 if (!pv)
0185 return -ENOMEM;
0186 pv->proto = proto;
0187 hvc_opal_privs[termno] = pv;
0188 if (proto == HV_PROTOCOL_HVSI) {
0189
0190
0191
0192
0193 hvsilib_init(&pv->hvsi,
0194 opal_get_chars, opal_put_chars_atomic,
0195 termno, 0);
0196 }
0197
0198
0199 hvc_instantiate(termno, termno, ops);
0200 } else {
0201 pr_err("hvc_opal: Device %pOF has duplicate terminal number #%d\n",
0202 dev->dev.of_node, termno);
0203 return -ENXIO;
0204 }
0205
0206 pr_info("hvc%d: %s protocol on %pOF%s\n", termno,
0207 proto == HV_PROTOCOL_RAW ? "raw" : "hvsi",
0208 dev->dev.of_node,
0209 boot ? " (boot console)" : "");
0210
0211 irq = irq_of_parse_and_map(dev->dev.of_node, 0);
0212 if (!irq) {
0213 pr_info("hvc%d: No interrupts property, using OPAL event\n",
0214 termno);
0215 irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT));
0216 }
0217
0218 if (!irq) {
0219 pr_err("hvc_opal: Unable to map interrupt for device %pOF\n",
0220 dev->dev.of_node);
0221 return irq;
0222 }
0223
0224 hp = hvc_alloc(termno, irq, ops, MAX_VIO_PUT_CHARS);
0225 if (IS_ERR(hp))
0226 return PTR_ERR(hp);
0227
0228
0229 hp->flags = IRQF_SHARED;
0230 dev_set_drvdata(&dev->dev, hp);
0231
0232 return 0;
0233 }
0234
0235 static int hvc_opal_remove(struct platform_device *dev)
0236 {
0237 struct hvc_struct *hp = dev_get_drvdata(&dev->dev);
0238 int rc, termno;
0239
0240 termno = hp->vtermno;
0241 rc = hvc_remove(hp);
0242 if (rc == 0) {
0243 if (hvc_opal_privs[termno] != &hvc_opal_boot_priv)
0244 kfree(hvc_opal_privs[termno]);
0245 hvc_opal_privs[termno] = NULL;
0246 }
0247 return rc;
0248 }
0249
0250 static struct platform_driver hvc_opal_driver = {
0251 .probe = hvc_opal_probe,
0252 .remove = hvc_opal_remove,
0253 .driver = {
0254 .name = hvc_opal_name,
0255 .of_match_table = hvc_opal_match,
0256 }
0257 };
0258
0259 static int __init hvc_opal_init(void)
0260 {
0261 if (!firmware_has_feature(FW_FEATURE_OPAL))
0262 return -ENODEV;
0263
0264
0265 return platform_driver_register(&hvc_opal_driver);
0266 }
0267 device_initcall(hvc_opal_init);
0268
0269 static void udbg_opal_putc(char c)
0270 {
0271 unsigned int termno = hvc_opal_boot_termno;
0272 int count = -1;
0273
0274 if (c == '\n')
0275 udbg_opal_putc('\r');
0276
0277 do {
0278 switch(hvc_opal_boot_priv.proto) {
0279 case HV_PROTOCOL_RAW:
0280 count = opal_put_chars(termno, &c, 1);
0281 break;
0282 case HV_PROTOCOL_HVSI:
0283 count = hvc_opal_hvsi_put_chars(termno, &c, 1);
0284 break;
0285 }
0286
0287
0288
0289
0290 opal_flush_console(termno);
0291 } while(count == 0 || count == -EAGAIN);
0292 }
0293
0294 static int udbg_opal_getc_poll(void)
0295 {
0296 unsigned int termno = hvc_opal_boot_termno;
0297 int rc = 0;
0298 char c;
0299
0300 switch(hvc_opal_boot_priv.proto) {
0301 case HV_PROTOCOL_RAW:
0302 rc = opal_get_chars(termno, &c, 1);
0303 break;
0304 case HV_PROTOCOL_HVSI:
0305 rc = hvc_opal_hvsi_get_chars(termno, &c, 1);
0306 break;
0307 }
0308 if (!rc)
0309 return -1;
0310 return c;
0311 }
0312
0313 static int udbg_opal_getc(void)
0314 {
0315 int ch;
0316 for (;;) {
0317 ch = udbg_opal_getc_poll();
0318 if (ch != -1)
0319 return ch;
0320 }
0321 }
0322
0323 static void udbg_init_opal_common(void)
0324 {
0325 udbg_putc = udbg_opal_putc;
0326 udbg_getc = udbg_opal_getc;
0327 udbg_getc_poll = udbg_opal_getc_poll;
0328 }
0329
0330 void __init hvc_opal_init_early(void)
0331 {
0332 struct device_node *stdout_node = of_node_get(of_stdout);
0333 const __be32 *termno;
0334 const struct hv_ops *ops;
0335 u32 index;
0336
0337
0338 if (!stdout_node) {
0339 struct device_node *opal, *np;
0340
0341
0342
0343
0344 opal = of_find_node_by_path("/ibm,opal/consoles");
0345 if (opal) {
0346 pr_devel("hvc_opal: Found consoles in new location\n");
0347 } else {
0348 opal = of_find_node_by_path("/ibm,opal");
0349 if (opal)
0350 pr_devel("hvc_opal: "
0351 "Found consoles in old location\n");
0352 }
0353 if (!opal)
0354 return;
0355 for_each_child_of_node(opal, np) {
0356 if (of_node_name_eq(np, "serial")) {
0357 stdout_node = np;
0358 break;
0359 }
0360 }
0361 of_node_put(opal);
0362 }
0363 if (!stdout_node)
0364 return;
0365 termno = of_get_property(stdout_node, "reg", NULL);
0366 index = termno ? be32_to_cpup(termno) : 0;
0367 if (index >= MAX_NR_HVC_CONSOLES)
0368 return;
0369 hvc_opal_privs[index] = &hvc_opal_boot_priv;
0370
0371
0372 if (of_device_is_compatible(stdout_node, "ibm,opal-console-raw")) {
0373 hvc_opal_boot_priv.proto = HV_PROTOCOL_RAW;
0374 ops = &hvc_opal_raw_ops;
0375 pr_devel("hvc_opal: Found RAW console\n");
0376 }
0377 else if (of_device_is_compatible(stdout_node,"ibm,opal-console-hvsi")) {
0378 hvc_opal_boot_priv.proto = HV_PROTOCOL_HVSI;
0379 ops = &hvc_opal_hvsi_ops;
0380 hvsilib_init(&hvc_opal_boot_priv.hvsi,
0381 opal_get_chars, opal_put_chars_atomic,
0382 index, 1);
0383
0384 hvsilib_establish(&hvc_opal_boot_priv.hvsi);
0385 pr_devel("hvc_opal: Found HVSI console\n");
0386 } else
0387 goto out;
0388 hvc_opal_boot_termno = index;
0389 udbg_init_opal_common();
0390 add_preferred_console("hvc", index, NULL);
0391 hvc_instantiate(index, index, ops);
0392 out:
0393 of_node_put(stdout_node);
0394 }
0395
0396 #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_RAW
0397 void __init udbg_init_debug_opal_raw(void)
0398 {
0399 u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO;
0400 hvc_opal_privs[index] = &hvc_opal_boot_priv;
0401 hvc_opal_boot_priv.proto = HV_PROTOCOL_RAW;
0402 hvc_opal_boot_termno = index;
0403 udbg_init_opal_common();
0404 }
0405 #endif
0406
0407 #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI
0408 void __init udbg_init_debug_opal_hvsi(void)
0409 {
0410 u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO;
0411 hvc_opal_privs[index] = &hvc_opal_boot_priv;
0412 hvc_opal_boot_termno = index;
0413 udbg_init_opal_common();
0414 hvsilib_init(&hvc_opal_boot_priv.hvsi,
0415 opal_get_chars, opal_put_chars_atomic,
0416 index, 1);
0417 hvsilib_establish(&hvc_opal_boot_priv.hvsi);
0418 }
0419 #endif