root/drivers/staging/greybus/fw-core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_fw_mgmt_connection
  2. gb_fw_spi_connection_init
  3. gb_fw_spi_connection_exit
  4. gb_fw_core_probe
  5. gb_fw_core_disconnect
  6. fw_core_init
  7. fw_core_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Greybus Firmware Core Bundle Driver.
   4  *
   5  * Copyright 2016 Google Inc.
   6  * Copyright 2016 Linaro Ltd.
   7  */
   8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9 
  10 #include <linux/firmware.h>
  11 #include <linux/greybus.h>
  12 #include "firmware.h"
  13 #include "spilib.h"
  14 
  15 struct gb_fw_core {
  16         struct gb_connection    *download_connection;
  17         struct gb_connection    *mgmt_connection;
  18         struct gb_connection    *spi_connection;
  19         struct gb_connection    *cap_connection;
  20 };
  21 
  22 static struct spilib_ops *spilib_ops;
  23 
  24 struct gb_connection *to_fw_mgmt_connection(struct device *dev)
  25 {
  26         struct gb_fw_core *fw_core = dev_get_drvdata(dev);
  27 
  28         return fw_core->mgmt_connection;
  29 }
  30 
  31 static int gb_fw_spi_connection_init(struct gb_connection *connection)
  32 {
  33         int ret;
  34 
  35         if (!connection)
  36                 return 0;
  37 
  38         ret = gb_connection_enable(connection);
  39         if (ret)
  40                 return ret;
  41 
  42         ret = gb_spilib_master_init(connection, &connection->bundle->dev,
  43                                     spilib_ops);
  44         if (ret) {
  45                 gb_connection_disable(connection);
  46                 return ret;
  47         }
  48 
  49         return 0;
  50 }
  51 
  52 static void gb_fw_spi_connection_exit(struct gb_connection *connection)
  53 {
  54         if (!connection)
  55                 return;
  56 
  57         gb_spilib_master_exit(connection);
  58         gb_connection_disable(connection);
  59 }
  60 
  61 static int gb_fw_core_probe(struct gb_bundle *bundle,
  62                             const struct greybus_bundle_id *id)
  63 {
  64         struct greybus_descriptor_cport *cport_desc;
  65         struct gb_connection *connection;
  66         struct gb_fw_core *fw_core;
  67         int ret, i;
  68         u16 cport_id;
  69         u8 protocol_id;
  70 
  71         fw_core = kzalloc(sizeof(*fw_core), GFP_KERNEL);
  72         if (!fw_core)
  73                 return -ENOMEM;
  74 
  75         /* Parse CPorts and create connections */
  76         for (i = 0; i < bundle->num_cports; i++) {
  77                 cport_desc = &bundle->cport_desc[i];
  78                 cport_id = le16_to_cpu(cport_desc->id);
  79                 protocol_id = cport_desc->protocol_id;
  80 
  81                 switch (protocol_id) {
  82                 case GREYBUS_PROTOCOL_FW_MANAGEMENT:
  83                         /* Disallow multiple Firmware Management CPorts */
  84                         if (fw_core->mgmt_connection) {
  85                                 dev_err(&bundle->dev,
  86                                         "multiple management CPorts found\n");
  87                                 ret = -EINVAL;
  88                                 goto err_destroy_connections;
  89                         }
  90 
  91                         connection = gb_connection_create(bundle, cport_id,
  92                                                 gb_fw_mgmt_request_handler);
  93                         if (IS_ERR(connection)) {
  94                                 ret = PTR_ERR(connection);
  95                                 dev_err(&bundle->dev,
  96                                         "failed to create management connection (%d)\n",
  97                                         ret);
  98                                 goto err_destroy_connections;
  99                         }
 100 
 101                         fw_core->mgmt_connection = connection;
 102                         break;
 103                 case GREYBUS_PROTOCOL_FW_DOWNLOAD:
 104                         /* Disallow multiple Firmware Download CPorts */
 105                         if (fw_core->download_connection) {
 106                                 dev_err(&bundle->dev,
 107                                         "multiple download CPorts found\n");
 108                                 ret = -EINVAL;
 109                                 goto err_destroy_connections;
 110                         }
 111 
 112                         connection = gb_connection_create(bundle, cport_id,
 113                                                 gb_fw_download_request_handler);
 114                         if (IS_ERR(connection)) {
 115                                 dev_err(&bundle->dev, "failed to create download connection (%ld)\n",
 116                                         PTR_ERR(connection));
 117                         } else {
 118                                 fw_core->download_connection = connection;
 119                         }
 120 
 121                         break;
 122                 case GREYBUS_PROTOCOL_SPI:
 123                         /* Disallow multiple SPI CPorts */
 124                         if (fw_core->spi_connection) {
 125                                 dev_err(&bundle->dev,
 126                                         "multiple SPI CPorts found\n");
 127                                 ret = -EINVAL;
 128                                 goto err_destroy_connections;
 129                         }
 130 
 131                         connection = gb_connection_create(bundle, cport_id,
 132                                                           NULL);
 133                         if (IS_ERR(connection)) {
 134                                 dev_err(&bundle->dev, "failed to create SPI connection (%ld)\n",
 135                                         PTR_ERR(connection));
 136                         } else {
 137                                 fw_core->spi_connection = connection;
 138                         }
 139 
 140                         break;
 141                 case GREYBUS_PROTOCOL_AUTHENTICATION:
 142                         /* Disallow multiple CAP CPorts */
 143                         if (fw_core->cap_connection) {
 144                                 dev_err(&bundle->dev, "multiple Authentication CPorts found\n");
 145                                 ret = -EINVAL;
 146                                 goto err_destroy_connections;
 147                         }
 148 
 149                         connection = gb_connection_create(bundle, cport_id,
 150                                                           NULL);
 151                         if (IS_ERR(connection)) {
 152                                 dev_err(&bundle->dev, "failed to create Authentication connection (%ld)\n",
 153                                         PTR_ERR(connection));
 154                         } else {
 155                                 fw_core->cap_connection = connection;
 156                         }
 157 
 158                         break;
 159                 default:
 160                         dev_err(&bundle->dev, "invalid protocol id (0x%02x)\n",
 161                                 protocol_id);
 162                         ret = -EINVAL;
 163                         goto err_destroy_connections;
 164                 }
 165         }
 166 
 167         /* Firmware Management connection is mandatory */
 168         if (!fw_core->mgmt_connection) {
 169                 dev_err(&bundle->dev, "missing management connection\n");
 170                 ret = -ENODEV;
 171                 goto err_destroy_connections;
 172         }
 173 
 174         ret = gb_fw_download_connection_init(fw_core->download_connection);
 175         if (ret) {
 176                 /* We may still be able to work with the Interface */
 177                 dev_err(&bundle->dev, "failed to initialize firmware download connection, disable it (%d)\n",
 178                         ret);
 179                 gb_connection_destroy(fw_core->download_connection);
 180                 fw_core->download_connection = NULL;
 181         }
 182 
 183         ret = gb_fw_spi_connection_init(fw_core->spi_connection);
 184         if (ret) {
 185                 /* We may still be able to work with the Interface */
 186                 dev_err(&bundle->dev, "failed to initialize SPI connection, disable it (%d)\n",
 187                         ret);
 188                 gb_connection_destroy(fw_core->spi_connection);
 189                 fw_core->spi_connection = NULL;
 190         }
 191 
 192         ret = gb_cap_connection_init(fw_core->cap_connection);
 193         if (ret) {
 194                 /* We may still be able to work with the Interface */
 195                 dev_err(&bundle->dev, "failed to initialize CAP connection, disable it (%d)\n",
 196                         ret);
 197                 gb_connection_destroy(fw_core->cap_connection);
 198                 fw_core->cap_connection = NULL;
 199         }
 200 
 201         ret = gb_fw_mgmt_connection_init(fw_core->mgmt_connection);
 202         if (ret) {
 203                 /* We may still be able to work with the Interface */
 204                 dev_err(&bundle->dev, "failed to initialize firmware management connection, disable it (%d)\n",
 205                         ret);
 206                 goto err_exit_connections;
 207         }
 208 
 209         greybus_set_drvdata(bundle, fw_core);
 210 
 211         /* FIXME: Remove this after S2 Loader gets runtime PM support */
 212         if (!(bundle->intf->quirks & GB_INTERFACE_QUIRK_NO_PM))
 213                 gb_pm_runtime_put_autosuspend(bundle);
 214 
 215         return 0;
 216 
 217 err_exit_connections:
 218         gb_cap_connection_exit(fw_core->cap_connection);
 219         gb_fw_spi_connection_exit(fw_core->spi_connection);
 220         gb_fw_download_connection_exit(fw_core->download_connection);
 221 err_destroy_connections:
 222         gb_connection_destroy(fw_core->mgmt_connection);
 223         gb_connection_destroy(fw_core->cap_connection);
 224         gb_connection_destroy(fw_core->spi_connection);
 225         gb_connection_destroy(fw_core->download_connection);
 226         kfree(fw_core);
 227 
 228         return ret;
 229 }
 230 
 231 static void gb_fw_core_disconnect(struct gb_bundle *bundle)
 232 {
 233         struct gb_fw_core *fw_core = greybus_get_drvdata(bundle);
 234         int ret;
 235 
 236         /* FIXME: Remove this after S2 Loader gets runtime PM support */
 237         if (!(bundle->intf->quirks & GB_INTERFACE_QUIRK_NO_PM)) {
 238                 ret = gb_pm_runtime_get_sync(bundle);
 239                 if (ret)
 240                         gb_pm_runtime_get_noresume(bundle);
 241         }
 242 
 243         gb_fw_mgmt_connection_exit(fw_core->mgmt_connection);
 244         gb_cap_connection_exit(fw_core->cap_connection);
 245         gb_fw_spi_connection_exit(fw_core->spi_connection);
 246         gb_fw_download_connection_exit(fw_core->download_connection);
 247 
 248         gb_connection_destroy(fw_core->mgmt_connection);
 249         gb_connection_destroy(fw_core->cap_connection);
 250         gb_connection_destroy(fw_core->spi_connection);
 251         gb_connection_destroy(fw_core->download_connection);
 252 
 253         kfree(fw_core);
 254 }
 255 
 256 static const struct greybus_bundle_id gb_fw_core_id_table[] = {
 257         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_FW_MANAGEMENT) },
 258         { }
 259 };
 260 
 261 static struct greybus_driver gb_fw_core_driver = {
 262         .name           = "gb-firmware",
 263         .probe          = gb_fw_core_probe,
 264         .disconnect     = gb_fw_core_disconnect,
 265         .id_table       = gb_fw_core_id_table,
 266 };
 267 
 268 static int fw_core_init(void)
 269 {
 270         int ret;
 271 
 272         ret = fw_mgmt_init();
 273         if (ret) {
 274                 pr_err("Failed to initialize fw-mgmt core (%d)\n", ret);
 275                 return ret;
 276         }
 277 
 278         ret = cap_init();
 279         if (ret) {
 280                 pr_err("Failed to initialize component authentication core (%d)\n",
 281                        ret);
 282                 goto fw_mgmt_exit;
 283         }
 284 
 285         ret = greybus_register(&gb_fw_core_driver);
 286         if (ret)
 287                 goto cap_exit;
 288 
 289         return 0;
 290 
 291 cap_exit:
 292         cap_exit();
 293 fw_mgmt_exit:
 294         fw_mgmt_exit();
 295 
 296         return ret;
 297 }
 298 module_init(fw_core_init);
 299 
 300 static void __exit fw_core_exit(void)
 301 {
 302         greybus_deregister(&gb_fw_core_driver);
 303         cap_exit();
 304         fw_mgmt_exit();
 305 }
 306 module_exit(fw_core_exit);
 307 
 308 MODULE_ALIAS("greybus:firmware");
 309 MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
 310 MODULE_DESCRIPTION("Greybus Firmware Bundle Driver");
 311 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */