14526ebbcSRichard Gong // SPDX-License-Identifier: GPL-2.0 24526ebbcSRichard Gong /* 34526ebbcSRichard Gong * Copyright (C) 2018-2019, Intel Corporation 44526ebbcSRichard Gong */ 54526ebbcSRichard Gong 64526ebbcSRichard Gong #include <linux/arm-smccc.h> 74526ebbcSRichard Gong #include <linux/bitfield.h> 84526ebbcSRichard Gong #include <linux/completion.h> 94526ebbcSRichard Gong #include <linux/kobject.h> 104526ebbcSRichard Gong #include <linux/module.h> 114526ebbcSRichard Gong #include <linux/mutex.h> 124526ebbcSRichard Gong #include <linux/of.h> 134526ebbcSRichard Gong #include <linux/of_platform.h> 144526ebbcSRichard Gong #include <linux/platform_device.h> 154526ebbcSRichard Gong #include <linux/firmware/intel/stratix10-svc-client.h> 164526ebbcSRichard Gong #include <linux/string.h> 174526ebbcSRichard Gong #include <linux/sysfs.h> 184526ebbcSRichard Gong 194526ebbcSRichard Gong #define RSU_STATE_MASK GENMASK_ULL(31, 0) 204526ebbcSRichard Gong #define RSU_VERSION_MASK GENMASK_ULL(63, 32) 214526ebbcSRichard Gong #define RSU_ERROR_LOCATION_MASK GENMASK_ULL(31, 0) 224526ebbcSRichard Gong #define RSU_ERROR_DETAIL_MASK GENMASK_ULL(63, 32) 2375bc73fcSRichard Gong #define RSU_DCMF0_MASK GENMASK_ULL(31, 0) 2475bc73fcSRichard Gong #define RSU_DCMF1_MASK GENMASK_ULL(63, 32) 2575bc73fcSRichard Gong #define RSU_DCMF2_MASK GENMASK_ULL(31, 0) 2675bc73fcSRichard Gong #define RSU_DCMF3_MASK GENMASK_ULL(63, 32) 274526ebbcSRichard Gong 284526ebbcSRichard Gong #define RSU_TIMEOUT (msecs_to_jiffies(SVC_RSU_REQUEST_TIMEOUT_MS)) 294526ebbcSRichard Gong 3075bc73fcSRichard Gong #define INVALID_RETRY_COUNTER 0xFF 3175bc73fcSRichard Gong #define INVALID_DCMF_VERSION 0xFF 3275bc73fcSRichard Gong 334526ebbcSRichard Gong 344526ebbcSRichard Gong typedef void (*rsu_callback)(struct stratix10_svc_client *client, 354526ebbcSRichard Gong struct stratix10_svc_cb_data *data); 364526ebbcSRichard Gong /** 374526ebbcSRichard Gong * struct stratix10_rsu_priv - rsu data structure 384526ebbcSRichard Gong * @chan: pointer to the allocated service channel 394526ebbcSRichard Gong * @client: active service client 404526ebbcSRichard Gong * @completion: state for callback completion 414526ebbcSRichard Gong * @lock: a mutex to protect callback completion state 424526ebbcSRichard Gong * @status.current_image: address of image currently running in flash 434526ebbcSRichard Gong * @status.fail_image: address of failed image in flash 4475bc73fcSRichard Gong * @status.version: the interface version number of RSU firmware 454526ebbcSRichard Gong * @status.state: the state of RSU system 464526ebbcSRichard Gong * @status.error_details: error code 474526ebbcSRichard Gong * @status.error_location: the error offset inside the image that failed 4875bc73fcSRichard Gong * @dcmf_version.dcmf0: Quartus dcmf0 version 4975bc73fcSRichard Gong * @dcmf_version.dcmf1: Quartus dcmf1 version 5075bc73fcSRichard Gong * @dcmf_version.dcmf2: Quartus dcmf2 version 5175bc73fcSRichard Gong * @dcmf_version.dcmf3: Quartus dcmf3 version 524526ebbcSRichard Gong * @retry_counter: the current image's retry counter 5375bc73fcSRichard Gong * @max_retry: the preset max retry value 544526ebbcSRichard Gong */ 554526ebbcSRichard Gong struct stratix10_rsu_priv { 564526ebbcSRichard Gong struct stratix10_svc_chan *chan; 574526ebbcSRichard Gong struct stratix10_svc_client client; 584526ebbcSRichard Gong struct completion completion; 594526ebbcSRichard Gong struct mutex lock; 604526ebbcSRichard Gong struct { 614526ebbcSRichard Gong unsigned long current_image; 624526ebbcSRichard Gong unsigned long fail_image; 634526ebbcSRichard Gong unsigned int version; 644526ebbcSRichard Gong unsigned int state; 654526ebbcSRichard Gong unsigned int error_details; 664526ebbcSRichard Gong unsigned int error_location; 674526ebbcSRichard Gong } status; 6875bc73fcSRichard Gong 6975bc73fcSRichard Gong struct { 7075bc73fcSRichard Gong unsigned int dcmf0; 7175bc73fcSRichard Gong unsigned int dcmf1; 7275bc73fcSRichard Gong unsigned int dcmf2; 7375bc73fcSRichard Gong unsigned int dcmf3; 7475bc73fcSRichard Gong } dcmf_version; 7575bc73fcSRichard Gong 764526ebbcSRichard Gong unsigned int retry_counter; 7775bc73fcSRichard Gong unsigned int max_retry; 784526ebbcSRichard Gong }; 794526ebbcSRichard Gong 804526ebbcSRichard Gong /** 814526ebbcSRichard Gong * rsu_status_callback() - Status callback from Intel Service Layer 824526ebbcSRichard Gong * @client: pointer to service client 834526ebbcSRichard Gong * @data: pointer to callback data structure 844526ebbcSRichard Gong * 854526ebbcSRichard Gong * Callback from Intel service layer for RSU status request. Status is 864526ebbcSRichard Gong * only updated after a system reboot, so a get updated status call is 874526ebbcSRichard Gong * made during driver probe. 884526ebbcSRichard Gong */ 894526ebbcSRichard Gong static void rsu_status_callback(struct stratix10_svc_client *client, 904526ebbcSRichard Gong struct stratix10_svc_cb_data *data) 914526ebbcSRichard Gong { 924526ebbcSRichard Gong struct stratix10_rsu_priv *priv = client->priv; 934526ebbcSRichard Gong struct arm_smccc_res *res = (struct arm_smccc_res *)data->kaddr1; 944526ebbcSRichard Gong 957536ad8dSRichard Gong if (data->status == BIT(SVC_STATUS_OK)) { 964526ebbcSRichard Gong priv->status.version = FIELD_GET(RSU_VERSION_MASK, 974526ebbcSRichard Gong res->a2); 984526ebbcSRichard Gong priv->status.state = FIELD_GET(RSU_STATE_MASK, res->a2); 994526ebbcSRichard Gong priv->status.fail_image = res->a1; 1004526ebbcSRichard Gong priv->status.current_image = res->a0; 1014526ebbcSRichard Gong priv->status.error_location = 1024526ebbcSRichard Gong FIELD_GET(RSU_ERROR_LOCATION_MASK, res->a3); 1034526ebbcSRichard Gong priv->status.error_details = 1044526ebbcSRichard Gong FIELD_GET(RSU_ERROR_DETAIL_MASK, res->a3); 1054526ebbcSRichard Gong } else { 1064526ebbcSRichard Gong dev_err(client->dev, "COMMAND_RSU_STATUS returned 0x%lX\n", 1074526ebbcSRichard Gong res->a0); 1084526ebbcSRichard Gong priv->status.version = 0; 1094526ebbcSRichard Gong priv->status.state = 0; 1104526ebbcSRichard Gong priv->status.fail_image = 0; 1114526ebbcSRichard Gong priv->status.current_image = 0; 1124526ebbcSRichard Gong priv->status.error_location = 0; 1134526ebbcSRichard Gong priv->status.error_details = 0; 1144526ebbcSRichard Gong } 1154526ebbcSRichard Gong 1164526ebbcSRichard Gong complete(&priv->completion); 1174526ebbcSRichard Gong } 1184526ebbcSRichard Gong 1194526ebbcSRichard Gong /** 1204526ebbcSRichard Gong * rsu_command_callback() - Update callback from Intel Service Layer 1214526ebbcSRichard Gong * @client: pointer to client 1224526ebbcSRichard Gong * @data: pointer to callback data structure 1234526ebbcSRichard Gong * 1244526ebbcSRichard Gong * Callback from Intel service layer for RSU commands. 1254526ebbcSRichard Gong */ 1264526ebbcSRichard Gong static void rsu_command_callback(struct stratix10_svc_client *client, 1274526ebbcSRichard Gong struct stratix10_svc_cb_data *data) 1284526ebbcSRichard Gong { 1294526ebbcSRichard Gong struct stratix10_rsu_priv *priv = client->priv; 1304526ebbcSRichard Gong 1317536ad8dSRichard Gong if (data->status == BIT(SVC_STATUS_NO_SUPPORT)) 13275bc73fcSRichard Gong dev_warn(client->dev, "FW doesn't support notify\n"); 1337536ad8dSRichard Gong else if (data->status == BIT(SVC_STATUS_ERROR)) 134e9cb0497SRichard Gong dev_err(client->dev, "Failure, returned status is %lu\n", 135e9cb0497SRichard Gong BIT(data->status)); 136e9cb0497SRichard Gong 1374526ebbcSRichard Gong complete(&priv->completion); 1384526ebbcSRichard Gong } 1394526ebbcSRichard Gong 1404526ebbcSRichard Gong /** 1414526ebbcSRichard Gong * rsu_retry_callback() - Callback from Intel service layer for getting 14275bc73fcSRichard Gong * the current image's retry counter from the firmware 1434526ebbcSRichard Gong * @client: pointer to client 1444526ebbcSRichard Gong * @data: pointer to callback data structure 1454526ebbcSRichard Gong * 1464526ebbcSRichard Gong * Callback from Intel service layer for retry counter, which is used by 1474526ebbcSRichard Gong * user to know how many times the images is still allowed to reload 1484526ebbcSRichard Gong * itself before giving up and starting RSU fail-over flow. 1494526ebbcSRichard Gong */ 1504526ebbcSRichard Gong static void rsu_retry_callback(struct stratix10_svc_client *client, 1514526ebbcSRichard Gong struct stratix10_svc_cb_data *data) 1524526ebbcSRichard Gong { 1534526ebbcSRichard Gong struct stratix10_rsu_priv *priv = client->priv; 1544526ebbcSRichard Gong unsigned int *counter = (unsigned int *)data->kaddr1; 1554526ebbcSRichard Gong 1567536ad8dSRichard Gong if (data->status == BIT(SVC_STATUS_OK)) 1574526ebbcSRichard Gong priv->retry_counter = *counter; 1587536ad8dSRichard Gong else if (data->status == BIT(SVC_STATUS_NO_SUPPORT)) 15975bc73fcSRichard Gong dev_warn(client->dev, "FW doesn't support retry\n"); 1604526ebbcSRichard Gong else 161e9cb0497SRichard Gong dev_err(client->dev, "Failed to get retry counter %lu\n", 162e9cb0497SRichard Gong BIT(data->status)); 1634526ebbcSRichard Gong 1644526ebbcSRichard Gong complete(&priv->completion); 1654526ebbcSRichard Gong } 1664526ebbcSRichard Gong 1674526ebbcSRichard Gong /** 16875bc73fcSRichard Gong * rsu_max_retry_callback() - Callback from Intel service layer for getting 16975bc73fcSRichard Gong * the max retry value from the firmware 17075bc73fcSRichard Gong * @client: pointer to client 17175bc73fcSRichard Gong * @data: pointer to callback data structure 17275bc73fcSRichard Gong * 17375bc73fcSRichard Gong * Callback from Intel service layer for max retry. 17475bc73fcSRichard Gong */ 17575bc73fcSRichard Gong static void rsu_max_retry_callback(struct stratix10_svc_client *client, 17675bc73fcSRichard Gong struct stratix10_svc_cb_data *data) 17775bc73fcSRichard Gong { 17875bc73fcSRichard Gong struct stratix10_rsu_priv *priv = client->priv; 17975bc73fcSRichard Gong unsigned int *max_retry = (unsigned int *)data->kaddr1; 18075bc73fcSRichard Gong 18175bc73fcSRichard Gong if (data->status == BIT(SVC_STATUS_OK)) 18275bc73fcSRichard Gong priv->max_retry = *max_retry; 18375bc73fcSRichard Gong else if (data->status == BIT(SVC_STATUS_NO_SUPPORT)) 18475bc73fcSRichard Gong dev_warn(client->dev, "FW doesn't support max retry\n"); 18575bc73fcSRichard Gong else 18675bc73fcSRichard Gong dev_err(client->dev, "Failed to get max retry %lu\n", 18775bc73fcSRichard Gong BIT(data->status)); 18875bc73fcSRichard Gong 18975bc73fcSRichard Gong complete(&priv->completion); 19075bc73fcSRichard Gong } 19175bc73fcSRichard Gong 19275bc73fcSRichard Gong /** 19375bc73fcSRichard Gong * rsu_dcmf_version_callback() - Callback from Intel service layer for getting 19475bc73fcSRichard Gong * the DCMF version 19575bc73fcSRichard Gong * @client: pointer to client 19675bc73fcSRichard Gong * @data: pointer to callback data structure 19775bc73fcSRichard Gong * 19875bc73fcSRichard Gong * Callback from Intel service layer for DCMF version number 19975bc73fcSRichard Gong */ 20075bc73fcSRichard Gong static void rsu_dcmf_version_callback(struct stratix10_svc_client *client, 20175bc73fcSRichard Gong struct stratix10_svc_cb_data *data) 20275bc73fcSRichard Gong { 20375bc73fcSRichard Gong struct stratix10_rsu_priv *priv = client->priv; 20475bc73fcSRichard Gong unsigned long long *value1 = (unsigned long long *)data->kaddr1; 20575bc73fcSRichard Gong unsigned long long *value2 = (unsigned long long *)data->kaddr2; 20675bc73fcSRichard Gong 20775bc73fcSRichard Gong if (data->status == BIT(SVC_STATUS_OK)) { 20875bc73fcSRichard Gong priv->dcmf_version.dcmf0 = FIELD_GET(RSU_DCMF0_MASK, *value1); 20975bc73fcSRichard Gong priv->dcmf_version.dcmf1 = FIELD_GET(RSU_DCMF1_MASK, *value1); 21075bc73fcSRichard Gong priv->dcmf_version.dcmf2 = FIELD_GET(RSU_DCMF2_MASK, *value2); 21175bc73fcSRichard Gong priv->dcmf_version.dcmf3 = FIELD_GET(RSU_DCMF3_MASK, *value2); 21275bc73fcSRichard Gong } else 21375bc73fcSRichard Gong dev_err(client->dev, "failed to get DCMF version\n"); 21475bc73fcSRichard Gong 21575bc73fcSRichard Gong complete(&priv->completion); 21675bc73fcSRichard Gong } 21775bc73fcSRichard Gong 21875bc73fcSRichard Gong /** 2194526ebbcSRichard Gong * rsu_send_msg() - send a message to Intel service layer 2204526ebbcSRichard Gong * @priv: pointer to rsu private data 2214526ebbcSRichard Gong * @command: RSU status or update command 2224526ebbcSRichard Gong * @arg: the request argument, the bitstream address or notify status 2234526ebbcSRichard Gong * @callback: function pointer for the callback (status or update) 2244526ebbcSRichard Gong * 2254526ebbcSRichard Gong * Start an Intel service layer transaction to perform the SMC call that 2264526ebbcSRichard Gong * is necessary to get RSU boot log or set the address of bitstream to 2274526ebbcSRichard Gong * boot after reboot. 2284526ebbcSRichard Gong * 2294526ebbcSRichard Gong * Returns 0 on success or -ETIMEDOUT on error. 2304526ebbcSRichard Gong */ 2314526ebbcSRichard Gong static int rsu_send_msg(struct stratix10_rsu_priv *priv, 2324526ebbcSRichard Gong enum stratix10_svc_command_code command, 2334526ebbcSRichard Gong unsigned long arg, 2344526ebbcSRichard Gong rsu_callback callback) 2354526ebbcSRichard Gong { 2364526ebbcSRichard Gong struct stratix10_svc_client_msg msg; 2374526ebbcSRichard Gong int ret; 2384526ebbcSRichard Gong 2394526ebbcSRichard Gong mutex_lock(&priv->lock); 2404526ebbcSRichard Gong reinit_completion(&priv->completion); 2414526ebbcSRichard Gong priv->client.receive_cb = callback; 2424526ebbcSRichard Gong 2434526ebbcSRichard Gong msg.command = command; 2444526ebbcSRichard Gong if (arg) 2454526ebbcSRichard Gong msg.arg[0] = arg; 2464526ebbcSRichard Gong 2474526ebbcSRichard Gong ret = stratix10_svc_send(priv->chan, &msg); 2484526ebbcSRichard Gong if (ret < 0) 2494526ebbcSRichard Gong goto status_done; 2504526ebbcSRichard Gong 2514526ebbcSRichard Gong ret = wait_for_completion_interruptible_timeout(&priv->completion, 2524526ebbcSRichard Gong RSU_TIMEOUT); 2534526ebbcSRichard Gong if (!ret) { 2544526ebbcSRichard Gong dev_err(priv->client.dev, 2554526ebbcSRichard Gong "timeout waiting for SMC call\n"); 2564526ebbcSRichard Gong ret = -ETIMEDOUT; 2574526ebbcSRichard Gong goto status_done; 2584526ebbcSRichard Gong } else if (ret < 0) { 2594526ebbcSRichard Gong dev_err(priv->client.dev, 2604526ebbcSRichard Gong "error %d waiting for SMC call\n", ret); 2614526ebbcSRichard Gong goto status_done; 2624526ebbcSRichard Gong } else { 2634526ebbcSRichard Gong ret = 0; 2644526ebbcSRichard Gong } 2654526ebbcSRichard Gong 2664526ebbcSRichard Gong status_done: 2674526ebbcSRichard Gong stratix10_svc_done(priv->chan); 2684526ebbcSRichard Gong mutex_unlock(&priv->lock); 2694526ebbcSRichard Gong return ret; 2704526ebbcSRichard Gong } 2714526ebbcSRichard Gong 2724526ebbcSRichard Gong /* 2734526ebbcSRichard Gong * This driver exposes some optional features of the Intel Stratix 10 SoC FPGA. 2744526ebbcSRichard Gong * The sysfs interfaces exposed here are FPGA Remote System Update (RSU) 2754526ebbcSRichard Gong * related. They allow user space software to query the configuration system 2764526ebbcSRichard Gong * status and to request optional reboot behavior specific to Intel FPGAs. 2774526ebbcSRichard Gong */ 2784526ebbcSRichard Gong 2794526ebbcSRichard Gong static ssize_t current_image_show(struct device *dev, 2804526ebbcSRichard Gong struct device_attribute *attr, char *buf) 2814526ebbcSRichard Gong { 2824526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 2834526ebbcSRichard Gong 2844526ebbcSRichard Gong if (!priv) 2854526ebbcSRichard Gong return -ENODEV; 2864526ebbcSRichard Gong 2874526ebbcSRichard Gong return sprintf(buf, "0x%08lx\n", priv->status.current_image); 2884526ebbcSRichard Gong } 2894526ebbcSRichard Gong 2904526ebbcSRichard Gong static ssize_t fail_image_show(struct device *dev, 2914526ebbcSRichard Gong struct device_attribute *attr, char *buf) 2924526ebbcSRichard Gong { 2934526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 2944526ebbcSRichard Gong 2954526ebbcSRichard Gong if (!priv) 2964526ebbcSRichard Gong return -ENODEV; 2974526ebbcSRichard Gong 2984526ebbcSRichard Gong return sprintf(buf, "0x%08lx\n", priv->status.fail_image); 2994526ebbcSRichard Gong } 3004526ebbcSRichard Gong 3014526ebbcSRichard Gong static ssize_t version_show(struct device *dev, struct device_attribute *attr, 3024526ebbcSRichard Gong char *buf) 3034526ebbcSRichard Gong { 3044526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 3054526ebbcSRichard Gong 3064526ebbcSRichard Gong if (!priv) 3074526ebbcSRichard Gong return -ENODEV; 3084526ebbcSRichard Gong 3094526ebbcSRichard Gong return sprintf(buf, "0x%08x\n", priv->status.version); 3104526ebbcSRichard Gong } 3114526ebbcSRichard Gong 3124526ebbcSRichard Gong static ssize_t state_show(struct device *dev, struct device_attribute *attr, 3134526ebbcSRichard Gong char *buf) 3144526ebbcSRichard Gong { 3154526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 3164526ebbcSRichard Gong 3174526ebbcSRichard Gong if (!priv) 3184526ebbcSRichard Gong return -ENODEV; 3194526ebbcSRichard Gong 3204526ebbcSRichard Gong return sprintf(buf, "0x%08x\n", priv->status.state); 3214526ebbcSRichard Gong } 3224526ebbcSRichard Gong 3234526ebbcSRichard Gong static ssize_t error_location_show(struct device *dev, 3244526ebbcSRichard Gong struct device_attribute *attr, char *buf) 3254526ebbcSRichard Gong { 3264526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 3274526ebbcSRichard Gong 3284526ebbcSRichard Gong if (!priv) 3294526ebbcSRichard Gong return -ENODEV; 3304526ebbcSRichard Gong 3314526ebbcSRichard Gong return sprintf(buf, "0x%08x\n", priv->status.error_location); 3324526ebbcSRichard Gong } 3334526ebbcSRichard Gong 3344526ebbcSRichard Gong static ssize_t error_details_show(struct device *dev, 3354526ebbcSRichard Gong struct device_attribute *attr, char *buf) 3364526ebbcSRichard Gong { 3374526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 3384526ebbcSRichard Gong 3394526ebbcSRichard Gong if (!priv) 3404526ebbcSRichard Gong return -ENODEV; 3414526ebbcSRichard Gong 3424526ebbcSRichard Gong return sprintf(buf, "0x%08x\n", priv->status.error_details); 3434526ebbcSRichard Gong } 3444526ebbcSRichard Gong 3454526ebbcSRichard Gong static ssize_t retry_counter_show(struct device *dev, 3464526ebbcSRichard Gong struct device_attribute *attr, char *buf) 3474526ebbcSRichard Gong { 3484526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 3494526ebbcSRichard Gong 3504526ebbcSRichard Gong if (!priv) 3514526ebbcSRichard Gong return -ENODEV; 3524526ebbcSRichard Gong 3534526ebbcSRichard Gong return sprintf(buf, "0x%08x\n", priv->retry_counter); 3544526ebbcSRichard Gong } 3554526ebbcSRichard Gong 35675bc73fcSRichard Gong static ssize_t max_retry_show(struct device *dev, 35775bc73fcSRichard Gong struct device_attribute *attr, char *buf) 35875bc73fcSRichard Gong { 35975bc73fcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 36075bc73fcSRichard Gong 36175bc73fcSRichard Gong if (!priv) 36275bc73fcSRichard Gong return -ENODEV; 36375bc73fcSRichard Gong 36475bc73fcSRichard Gong return sprintf(buf, "0x%08x\n", priv->max_retry); 36575bc73fcSRichard Gong } 36675bc73fcSRichard Gong 36775bc73fcSRichard Gong static ssize_t dcmf0_show(struct device *dev, 36875bc73fcSRichard Gong struct device_attribute *attr, char *buf) 36975bc73fcSRichard Gong { 37075bc73fcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 37175bc73fcSRichard Gong 37275bc73fcSRichard Gong if (!priv) 37375bc73fcSRichard Gong return -ENODEV; 37475bc73fcSRichard Gong 37575bc73fcSRichard Gong return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf0); 37675bc73fcSRichard Gong } 37775bc73fcSRichard Gong 37875bc73fcSRichard Gong static ssize_t dcmf1_show(struct device *dev, 37975bc73fcSRichard Gong struct device_attribute *attr, char *buf) 38075bc73fcSRichard Gong { 38175bc73fcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 38275bc73fcSRichard Gong 38375bc73fcSRichard Gong if (!priv) 38475bc73fcSRichard Gong return -ENODEV; 38575bc73fcSRichard Gong 38675bc73fcSRichard Gong return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf1); 38775bc73fcSRichard Gong } 38875bc73fcSRichard Gong 38975bc73fcSRichard Gong static ssize_t dcmf2_show(struct device *dev, 39075bc73fcSRichard Gong struct device_attribute *attr, char *buf) 39175bc73fcSRichard Gong { 39275bc73fcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 39375bc73fcSRichard Gong 39475bc73fcSRichard Gong if (!priv) 39575bc73fcSRichard Gong return -ENODEV; 39675bc73fcSRichard Gong 39775bc73fcSRichard Gong return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf2); 39875bc73fcSRichard Gong } 39975bc73fcSRichard Gong 40075bc73fcSRichard Gong static ssize_t dcmf3_show(struct device *dev, 40175bc73fcSRichard Gong struct device_attribute *attr, char *buf) 40275bc73fcSRichard Gong { 40375bc73fcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 40475bc73fcSRichard Gong 40575bc73fcSRichard Gong if (!priv) 40675bc73fcSRichard Gong return -ENODEV; 40775bc73fcSRichard Gong 40875bc73fcSRichard Gong return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf3); 40975bc73fcSRichard Gong } 41075bc73fcSRichard Gong 4114526ebbcSRichard Gong static ssize_t reboot_image_store(struct device *dev, 4124526ebbcSRichard Gong struct device_attribute *attr, 4134526ebbcSRichard Gong const char *buf, size_t count) 4144526ebbcSRichard Gong { 4154526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 4164526ebbcSRichard Gong unsigned long address; 4174526ebbcSRichard Gong int ret; 4184526ebbcSRichard Gong 419*52f944eeSRichard Gong if (!priv) 4204526ebbcSRichard Gong return -ENODEV; 4214526ebbcSRichard Gong 4224526ebbcSRichard Gong ret = kstrtoul(buf, 0, &address); 4234526ebbcSRichard Gong if (ret) 4244526ebbcSRichard Gong return ret; 4254526ebbcSRichard Gong 4264526ebbcSRichard Gong ret = rsu_send_msg(priv, COMMAND_RSU_UPDATE, 4274526ebbcSRichard Gong address, rsu_command_callback); 4284526ebbcSRichard Gong if (ret) { 4294526ebbcSRichard Gong dev_err(dev, "Error, RSU update returned %i\n", ret); 4304526ebbcSRichard Gong return ret; 4314526ebbcSRichard Gong } 4324526ebbcSRichard Gong 4334526ebbcSRichard Gong return count; 4344526ebbcSRichard Gong } 4354526ebbcSRichard Gong 4364526ebbcSRichard Gong static ssize_t notify_store(struct device *dev, 4374526ebbcSRichard Gong struct device_attribute *attr, 4384526ebbcSRichard Gong const char *buf, size_t count) 4394526ebbcSRichard Gong { 4404526ebbcSRichard Gong struct stratix10_rsu_priv *priv = dev_get_drvdata(dev); 4414526ebbcSRichard Gong unsigned long status; 4424526ebbcSRichard Gong int ret; 4434526ebbcSRichard Gong 444*52f944eeSRichard Gong if (!priv) 4454526ebbcSRichard Gong return -ENODEV; 4464526ebbcSRichard Gong 4474526ebbcSRichard Gong ret = kstrtoul(buf, 0, &status); 4484526ebbcSRichard Gong if (ret) 4494526ebbcSRichard Gong return ret; 4504526ebbcSRichard Gong 4514526ebbcSRichard Gong ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY, 4524526ebbcSRichard Gong status, rsu_command_callback); 4534526ebbcSRichard Gong if (ret) { 4544526ebbcSRichard Gong dev_err(dev, "Error, RSU notify returned %i\n", ret); 4554526ebbcSRichard Gong return ret; 4564526ebbcSRichard Gong } 4574526ebbcSRichard Gong 4584526ebbcSRichard Gong /* to get the updated state */ 4594526ebbcSRichard Gong ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 4604526ebbcSRichard Gong 0, rsu_status_callback); 4614526ebbcSRichard Gong if (ret) { 4624526ebbcSRichard Gong dev_err(dev, "Error, getting RSU status %i\n", ret); 4634526ebbcSRichard Gong return ret; 4644526ebbcSRichard Gong } 4654526ebbcSRichard Gong 466e9cb0497SRichard Gong ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); 4674526ebbcSRichard Gong if (ret) { 468e9cb0497SRichard Gong dev_err(dev, "Error, getting RSU retry %i\n", ret); 4694526ebbcSRichard Gong return ret; 4704526ebbcSRichard Gong } 4714526ebbcSRichard Gong 4724526ebbcSRichard Gong return count; 4734526ebbcSRichard Gong } 4744526ebbcSRichard Gong 4754526ebbcSRichard Gong static DEVICE_ATTR_RO(current_image); 4764526ebbcSRichard Gong static DEVICE_ATTR_RO(fail_image); 4774526ebbcSRichard Gong static DEVICE_ATTR_RO(state); 4784526ebbcSRichard Gong static DEVICE_ATTR_RO(version); 4794526ebbcSRichard Gong static DEVICE_ATTR_RO(error_location); 4804526ebbcSRichard Gong static DEVICE_ATTR_RO(error_details); 4814526ebbcSRichard Gong static DEVICE_ATTR_RO(retry_counter); 48275bc73fcSRichard Gong static DEVICE_ATTR_RO(max_retry); 48375bc73fcSRichard Gong static DEVICE_ATTR_RO(dcmf0); 48475bc73fcSRichard Gong static DEVICE_ATTR_RO(dcmf1); 48575bc73fcSRichard Gong static DEVICE_ATTR_RO(dcmf2); 48675bc73fcSRichard Gong static DEVICE_ATTR_RO(dcmf3); 4874526ebbcSRichard Gong static DEVICE_ATTR_WO(reboot_image); 4884526ebbcSRichard Gong static DEVICE_ATTR_WO(notify); 4894526ebbcSRichard Gong 4904526ebbcSRichard Gong static struct attribute *rsu_attrs[] = { 4914526ebbcSRichard Gong &dev_attr_current_image.attr, 4924526ebbcSRichard Gong &dev_attr_fail_image.attr, 4934526ebbcSRichard Gong &dev_attr_state.attr, 4944526ebbcSRichard Gong &dev_attr_version.attr, 4954526ebbcSRichard Gong &dev_attr_error_location.attr, 4964526ebbcSRichard Gong &dev_attr_error_details.attr, 4974526ebbcSRichard Gong &dev_attr_retry_counter.attr, 49875bc73fcSRichard Gong &dev_attr_max_retry.attr, 49975bc73fcSRichard Gong &dev_attr_dcmf0.attr, 50075bc73fcSRichard Gong &dev_attr_dcmf1.attr, 50175bc73fcSRichard Gong &dev_attr_dcmf2.attr, 50275bc73fcSRichard Gong &dev_attr_dcmf3.attr, 5034526ebbcSRichard Gong &dev_attr_reboot_image.attr, 5044526ebbcSRichard Gong &dev_attr_notify.attr, 5054526ebbcSRichard Gong NULL 5064526ebbcSRichard Gong }; 5074526ebbcSRichard Gong 5084526ebbcSRichard Gong ATTRIBUTE_GROUPS(rsu); 5094526ebbcSRichard Gong 5104526ebbcSRichard Gong static int stratix10_rsu_probe(struct platform_device *pdev) 5114526ebbcSRichard Gong { 5124526ebbcSRichard Gong struct device *dev = &pdev->dev; 5134526ebbcSRichard Gong struct stratix10_rsu_priv *priv; 5144526ebbcSRichard Gong int ret; 5154526ebbcSRichard Gong 5164526ebbcSRichard Gong priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 5174526ebbcSRichard Gong if (!priv) 5184526ebbcSRichard Gong return -ENOMEM; 5194526ebbcSRichard Gong 5204526ebbcSRichard Gong priv->client.dev = dev; 5214526ebbcSRichard Gong priv->client.receive_cb = NULL; 5224526ebbcSRichard Gong priv->client.priv = priv; 5234526ebbcSRichard Gong priv->status.current_image = 0; 5244526ebbcSRichard Gong priv->status.fail_image = 0; 5254526ebbcSRichard Gong priv->status.error_location = 0; 5264526ebbcSRichard Gong priv->status.error_details = 0; 5274526ebbcSRichard Gong priv->status.version = 0; 5284526ebbcSRichard Gong priv->status.state = 0; 5294526ebbcSRichard Gong priv->retry_counter = INVALID_RETRY_COUNTER; 53075bc73fcSRichard Gong priv->dcmf_version.dcmf0 = INVALID_DCMF_VERSION; 53175bc73fcSRichard Gong priv->dcmf_version.dcmf1 = INVALID_DCMF_VERSION; 53275bc73fcSRichard Gong priv->dcmf_version.dcmf2 = INVALID_DCMF_VERSION; 53375bc73fcSRichard Gong priv->dcmf_version.dcmf3 = INVALID_DCMF_VERSION; 53475bc73fcSRichard Gong priv->max_retry = INVALID_RETRY_COUNTER; 5354526ebbcSRichard Gong 5364526ebbcSRichard Gong mutex_init(&priv->lock); 5374526ebbcSRichard Gong priv->chan = stratix10_svc_request_channel_byname(&priv->client, 5384526ebbcSRichard Gong SVC_CLIENT_RSU); 5394526ebbcSRichard Gong if (IS_ERR(priv->chan)) { 5404526ebbcSRichard Gong dev_err(dev, "couldn't get service channel %s\n", 5414526ebbcSRichard Gong SVC_CLIENT_RSU); 5424526ebbcSRichard Gong return PTR_ERR(priv->chan); 5434526ebbcSRichard Gong } 5444526ebbcSRichard Gong 5454526ebbcSRichard Gong init_completion(&priv->completion); 5464526ebbcSRichard Gong platform_set_drvdata(pdev, priv); 5474526ebbcSRichard Gong 5484526ebbcSRichard Gong /* get the initial state from firmware */ 5494526ebbcSRichard Gong ret = rsu_send_msg(priv, COMMAND_RSU_STATUS, 5504526ebbcSRichard Gong 0, rsu_status_callback); 5514526ebbcSRichard Gong if (ret) { 5524526ebbcSRichard Gong dev_err(dev, "Error, getting RSU status %i\n", ret); 5534526ebbcSRichard Gong stratix10_svc_free_channel(priv->chan); 5544526ebbcSRichard Gong } 5554526ebbcSRichard Gong 55675bc73fcSRichard Gong /* get DCMF version from firmware */ 55775bc73fcSRichard Gong ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION, 55875bc73fcSRichard Gong 0, rsu_dcmf_version_callback); 55975bc73fcSRichard Gong if (ret) { 56075bc73fcSRichard Gong dev_err(dev, "Error, getting DCMF version %i\n", ret); 56175bc73fcSRichard Gong stratix10_svc_free_channel(priv->chan); 56275bc73fcSRichard Gong } 56375bc73fcSRichard Gong 564e9cb0497SRichard Gong ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback); 5654526ebbcSRichard Gong if (ret) { 566e9cb0497SRichard Gong dev_err(dev, "Error, getting RSU retry %i\n", ret); 5674526ebbcSRichard Gong stratix10_svc_free_channel(priv->chan); 5684526ebbcSRichard Gong } 5694526ebbcSRichard Gong 57075bc73fcSRichard Gong ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0, 57175bc73fcSRichard Gong rsu_max_retry_callback); 57275bc73fcSRichard Gong if (ret) { 57375bc73fcSRichard Gong dev_err(dev, "Error, getting RSU max retry %i\n", ret); 57475bc73fcSRichard Gong stratix10_svc_free_channel(priv->chan); 57575bc73fcSRichard Gong } 57675bc73fcSRichard Gong 5774526ebbcSRichard Gong return ret; 5784526ebbcSRichard Gong } 5794526ebbcSRichard Gong 5804526ebbcSRichard Gong static int stratix10_rsu_remove(struct platform_device *pdev) 5814526ebbcSRichard Gong { 5824526ebbcSRichard Gong struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev); 5834526ebbcSRichard Gong 5844526ebbcSRichard Gong stratix10_svc_free_channel(priv->chan); 5854526ebbcSRichard Gong return 0; 5864526ebbcSRichard Gong } 5874526ebbcSRichard Gong 5884526ebbcSRichard Gong static struct platform_driver stratix10_rsu_driver = { 5894526ebbcSRichard Gong .probe = stratix10_rsu_probe, 5904526ebbcSRichard Gong .remove = stratix10_rsu_remove, 5914526ebbcSRichard Gong .driver = { 5924526ebbcSRichard Gong .name = "stratix10-rsu", 5934526ebbcSRichard Gong .dev_groups = rsu_groups, 5944526ebbcSRichard Gong }, 5954526ebbcSRichard Gong }; 5964526ebbcSRichard Gong 5974526ebbcSRichard Gong module_platform_driver(stratix10_rsu_driver); 5984526ebbcSRichard Gong 5994526ebbcSRichard Gong MODULE_LICENSE("GPL v2"); 6004526ebbcSRichard Gong MODULE_DESCRIPTION("Intel Remote System Update Driver"); 6014526ebbcSRichard Gong MODULE_AUTHOR("Richard Gong <richard.gong@intel.com>"); 602