Merge pull request #1450 from MISL-EBU-System-SW/marvell-support-v6
[project/bcm63xx/atf.git] / drivers / io / io_fip.c
index c5ee6a4df59af7058c73a4e337ee35659e901e16..9d6c763e8969bb92597a6c59fba4c25d76c05050 100644 (file)
 #include <utils.h>
 #include <uuid.h>
 
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES                1
+#endif
+
 /* Useful for printing UUIDs when debugging.*/
 #define PRINT_UUID2(x)                                                         \
        "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",   \
@@ -32,11 +36,33 @@ typedef struct {
        fip_toc_entry_t entry;
 } file_state_t;
 
+/*
+ * Maintain dev_spec per FIP Device
+ * TODO - Add backend handles and file state
+ * per FIP device here once backends like io_memmap
+ * can support multiple open files
+ */
+typedef struct {
+       uintptr_t dev_spec;
+} fip_dev_state_t;
+
 static const uuid_t uuid_null = { {0} };
+/*
+ * Only one file can be open across all FIP device
+ * as backends like io_memmap don't support
+ * multiple open files. The file state and
+ * backend handle should be maintained per FIP device
+ * if the same support is available in the backend
+ */
 static file_state_t current_file = {0};
 static uintptr_t backend_dev_handle;
 static uintptr_t backend_image_spec;
 
+static fip_dev_state_t state_pool[MAX_FIP_DEVICES];
+static io_dev_info_t dev_info_pool[MAX_FIP_DEVICES];
+
+/* Track number of allocated fip devices */
+static unsigned int fip_dev_count;
 
 /* Firmware Image Package driver functions */
 static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
@@ -92,20 +118,94 @@ static const io_dev_funcs_t fip_dev_funcs = {
        .dev_close = fip_dev_close,
 };
 
+/* Locate a file state in the pool, specified by address */
+static int find_first_fip_state(const uintptr_t dev_spec,
+                                 unsigned int *index_out)
+{
+       int result = -ENOENT;
+       unsigned int index;
+
+       for (index = 0; index < (unsigned int)MAX_FIP_DEVICES; ++index) {
+               /* dev_spec is used as identifier since it's unique */
+               if (state_pool[index].dev_spec == dev_spec) {
+                       result = 0;
+                       *index_out = index;
+                       break;
+               }
+       }
+       return result;
+}
+
 
-/* No state associated with this device so structure can be const */
-static const io_dev_info_t fip_dev_info = {
-       .funcs = &fip_dev_funcs,
-       .info = (uintptr_t)NULL
-};
+/* Allocate a device info from the pool and return a pointer to it */
+static int allocate_dev_info(io_dev_info_t **dev_info)
+{
+       int result = -ENOMEM;
 
+       assert(dev_info != NULL);
+
+       if (fip_dev_count < (unsigned int)MAX_FIP_DEVICES) {
+               unsigned int index = 0;
+
+               result = find_first_fip_state(0, &index);
+               assert(result == 0);
+               /* initialize dev_info */
+               dev_info_pool[index].funcs = &fip_dev_funcs;
+               dev_info_pool[index].info =
+                               (uintptr_t)&state_pool[index];
+               *dev_info = &dev_info_pool[index];
+               ++fip_dev_count;
+       }
+
+       return result;
+}
 
-/* Open a connection to the FIP device */
-static int fip_dev_open(const uintptr_t dev_spec __unused,
+/* Release a device info to the pool */
+static int free_dev_info(io_dev_info_t *dev_info)
+{
+       int result;
+       unsigned int index = 0;
+       fip_dev_state_t *state;
+
+       assert(dev_info != NULL);
+
+       state = (fip_dev_state_t *)dev_info->info;
+       result = find_first_fip_state(state->dev_spec, &index);
+       if (result ==  0) {
+               /* free if device info is valid */
+               zeromem(state, sizeof(fip_dev_state_t));
+               --fip_dev_count;
+       }
+
+       return result;
+}
+
+/*
+ * Multiple FIP devices can be opened depending on the value of
+ * MAX_FIP_DEVICES. Given that there is only one backend, only a
+ * single file can be open at a time by any FIP device.
+ */
+static int fip_dev_open(const uintptr_t dev_spec,
                         io_dev_info_t **dev_info)
 {
+       int result;
+       io_dev_info_t *info;
+       fip_dev_state_t *state;
+
        assert(dev_info != NULL);
-       *dev_info = (io_dev_info_t *)&fip_dev_info; /* cast away const */
+#if MAX_FIP_DEVICES > 1
+       assert(dev_spec != (uintptr_t)NULL);
+#endif
+
+       result = allocate_dev_info(&info);
+       if (result != 0)
+               return -ENOMEM;
+
+       state = (fip_dev_state_t *)info->info;
+
+       state->dev_spec = dev_spec;
+
+       *dev_info = info;
 
        return 0;
 }
@@ -165,7 +265,7 @@ static int fip_dev_close(io_dev_info_t *dev_info)
        backend_dev_handle = (uintptr_t)NULL;
        backend_image_spec = (uintptr_t)NULL;
 
-       return 0;
+       return free_dev_info(dev_info);
 }
 
 
@@ -340,7 +440,11 @@ int register_io_dev_fip(const io_dev_connector_t **dev_con)
        int result;
        assert(dev_con != NULL);
 
-       result = io_register_device(&fip_dev_info);
+       /*
+        * Since dev_info isn't really used in io_register_device, always
+        * use the same device info at here instead.
+        */
+       result = io_register_device(&dev_info_pool[0]);
        if (result == 0)
                *dev_con = &fip_dev_connector;