| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * QEMU Synchronous Serial Interface support | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2009 CodeSourcery. | 
					
						
							| 
									
										
										
										
											2012-07-24 10:55:15 +10:00
										 |  |  |  * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) | 
					
						
							|  |  |  |  * Copyright (c) 2012 PetaLogix Pty Ltd. | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  |  * Written by Paul Brook | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-06-26 12:21:35 +10:00
										 |  |  |  * This code is licensed under the GNU GPL v2. | 
					
						
							| 
									
										
										
										
											2012-01-13 17:44:23 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Contributions after 2012-01-13 are licensed under the terms of the | 
					
						
							|  |  |  |  * GNU GPL, version 2 or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:30 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2016-01-21 14:15:03 +00:00
										 |  |  | #include "hw/ssi/ssi.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:45 +02:00
										 |  |  | #include "migration/vmstate.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-23 16:35:07 +02:00
										 |  |  | #include "qemu/module.h"
 | 
					
						
							| 
									
										
										
										
											2020-06-10 07:32:13 +02:00
										 |  |  | #include "qapi/error.h"
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | #include "qom/object.h"
 | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct SSIBus { | 
					
						
							| 
									
										
										
										
											2014-02-11 16:28:25 -08:00
										 |  |  |     BusState parent_obj; | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  | #define TYPE_SSI_BUS "SSI"
 | 
					
						
							| 
									
										
										
										
											2020-09-16 14:25:19 -04:00
										 |  |  | OBJECT_DECLARE_SIMPLE_TYPE(SSIBus, SSI_BUS) | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const TypeInfo ssi_bus_info = { | 
					
						
							|  |  |  |     .name = TYPE_SSI_BUS, | 
					
						
							|  |  |  |     .parent = TYPE_BUS, | 
					
						
							|  |  |  |     .instance_size = sizeof(SSIBus), | 
					
						
							| 
									
										
										
										
											2009-06-30 14:12:08 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  | static void ssi_cs_default(void *opaque, int n, int level) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     SSIPeripheral *s = SSI_PERIPHERAL(opaque); | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  |     bool cs = !!level; | 
					
						
							|  |  |  |     assert(n == 0); | 
					
						
							|  |  |  |     if (s->cs != cs) { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |         SSIPeripheralClass *ssc = SSI_PERIPHERAL_GET_CLASS(s); | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  |         if (ssc->set_cs) { | 
					
						
							|  |  |  |             ssc->set_cs(s, cs); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     s->cs = cs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static uint32_t ssi_transfer_raw_default(SSIPeripheral *dev, uint32_t val) | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     SSIPeripheralClass *ssc = SSI_PERIPHERAL_GET_CLASS(dev); | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) || | 
					
						
							|  |  |  |             (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) || | 
					
						
							|  |  |  |             ssc->cs_polarity == SSI_CS_NONE) { | 
					
						
							|  |  |  |         return ssc->transfer(dev, val); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static void ssi_peripheral_realize(DeviceState *dev, Error **errp) | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     SSIPeripheral *s = SSI_PERIPHERAL(dev); | 
					
						
							|  |  |  |     SSIPeripheralClass *ssc = SSI_PERIPHERAL_GET_CLASS(s); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  |     if (ssc->transfer_raw == ssi_transfer_raw_default && | 
					
						
							|  |  |  |             ssc->cs_polarity != SSI_CS_NONE) { | 
					
						
							| 
									
										
										
										
											2014-05-19 23:31:33 -07:00
										 |  |  |         qdev_init_gpio_in_named(dev, ssi_cs_default, SSI_GPIO_CS, 1); | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 13:06:37 +01:00
										 |  |  |     ssc->realize(s, errp); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static void ssi_peripheral_class_init(ObjectClass *klass, void *data) | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     SSIPeripheralClass *ssc = SSI_PERIPHERAL_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     DeviceClass *dc = DEVICE_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     dc->realize = ssi_peripheral_realize; | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  |     dc->bus_type = TYPE_SSI_BUS; | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  |     if (!ssc->transfer_raw) { | 
					
						
							|  |  |  |         ssc->transfer_raw = ssi_transfer_raw_default; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static const TypeInfo ssi_peripheral_info = { | 
					
						
							|  |  |  |     .name = TYPE_SSI_PERIPHERAL, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .parent = TYPE_DEVICE, | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     .class_init = ssi_peripheral_class_init, | 
					
						
							|  |  |  |     .class_size = sizeof(SSIPeripheralClass), | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .abstract = true, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  | bool ssi_realize_and_unref(DeviceState *dev, SSIBus *bus, Error **errp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return qdev_realize_and_unref(dev, &bus->parent_obj, errp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | DeviceState *ssi_create_peripheral(SSIBus *bus, const char *name) | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-10 07:32:13 +02:00
										 |  |  |     DeviceState *dev = qdev_new(name); | 
					
						
							| 
									
										
										
										
											2012-07-24 13:56:27 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  |     ssi_realize_and_unref(dev, bus, &error_fatal); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  |     return dev; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-23 00:05:19 +01:00
										 |  |  | SSIBus *ssi_create_bus(DeviceState *parent, const char *name) | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-23 00:05:19 +01:00
										 |  |  |     BusState *bus; | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  |     bus = qbus_create(TYPE_SSI_BUS, parent, name); | 
					
						
							| 
									
										
										
										
											2013-06-07 14:45:17 +02:00
										 |  |  |     return SSI_BUS(bus); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint32_t ssi_transfer(SSIBus *bus, uint32_t val) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-11 16:28:25 -08:00
										 |  |  |     BusState *b = BUS(bus); | 
					
						
							| 
									
										
										
										
											2011-12-23 15:34:39 -06:00
										 |  |  |     BusChild *kid; | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     SSIPeripheralClass *ssc; | 
					
						
							| 
									
										
										
										
											2012-07-24 10:55:15 +10:00
										 |  |  |     uint32_t r = 0; | 
					
						
							| 
									
										
										
										
											2011-12-23 15:34:39 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-11 16:28:25 -08:00
										 |  |  |     QTAILQ_FOREACH(kid, &b->children, sibling) { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |         SSIPeripheral *peripheral = SSI_PERIPHERAL(kid->child); | 
					
						
							|  |  |  |         ssc = SSI_PERIPHERAL_GET_CLASS(peripheral); | 
					
						
							|  |  |  |         r |= ssc->transfer_raw(peripheral, val); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-07-24 10:55:15 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return r; | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | const VMStateDescription vmstate_ssi_peripheral = { | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  |     .name = "SSISlave", | 
					
						
							|  |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							| 
									
										
										
										
											2014-05-13 16:09:35 +01:00
										 |  |  |     .fields = (VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |         VMSTATE_BOOL(cs, SSIPeripheral), | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static void ssi_peripheral_register_types(void) | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-05-02 09:00:20 +02:00
										 |  |  |     type_register_static(&ssi_bus_info); | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     type_register_static(&ssi_peripheral_info); | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | type_init(ssi_peripheral_register_types) |