1010
1111#include <linux/acpi.h>
1212#include <linux/arm-smccc.h>
13+ #include <linux/delay.h>
1314#include <linux/module.h>
1415#include <linux/platform_device.h>
1516
@@ -44,6 +45,10 @@ static const char * const mlxbf_bootctl_lifecycle_states[] = {
4445 [3 ] = "RMA" ,
4546};
4647
48+ /* Mapped pointer for RSH_BOOT_FIFO_DATA and RSH_BOOT_FIFO_COUNT register. */
49+ static void __iomem * mlxbf_rsh_boot_data ;
50+ static void __iomem * mlxbf_rsh_boot_cnt ;
51+
4752/* ARM SMC call which is atomic and no need for lock. */
4853static int mlxbf_bootctl_smc (unsigned int smc_op , int smc_arg )
4954{
@@ -287,6 +292,45 @@ static const struct acpi_device_id mlxbf_bootctl_acpi_ids[] = {
287292
288293MODULE_DEVICE_TABLE (acpi , mlxbf_bootctl_acpi_ids );
289294
295+ static ssize_t mlxbf_bootctl_bootfifo_read (struct file * filp ,
296+ struct kobject * kobj ,
297+ struct bin_attribute * bin_attr ,
298+ char * buf , loff_t pos ,
299+ size_t count )
300+ {
301+ unsigned long timeout = msecs_to_jiffies (500 );
302+ unsigned long expire = jiffies + timeout ;
303+ u64 data , cnt = 0 ;
304+ char * p = buf ;
305+
306+ while (count >= sizeof (data )) {
307+ /* Give up reading if no more data within 500ms. */
308+ if (!cnt ) {
309+ cnt = readq (mlxbf_rsh_boot_cnt );
310+ if (!cnt ) {
311+ if (time_after (jiffies , expire ))
312+ break ;
313+ usleep_range (10 , 50 );
314+ continue ;
315+ }
316+ }
317+
318+ data = readq (mlxbf_rsh_boot_data );
319+ memcpy (p , & data , sizeof (data ));
320+ count -= sizeof (data );
321+ p += sizeof (data );
322+ cnt -- ;
323+ expire = jiffies + timeout ;
324+ }
325+
326+ return p - buf ;
327+ }
328+
329+ static struct bin_attribute mlxbf_bootctl_bootfifo_sysfs_attr = {
330+ .attr = { .name = "bootfifo" , .mode = 0400 },
331+ .read = mlxbf_bootctl_bootfifo_read ,
332+ };
333+
290334static bool mlxbf_bootctl_guid_match (const guid_t * guid ,
291335 const struct arm_smccc_res * res )
292336{
@@ -304,6 +348,16 @@ static int mlxbf_bootctl_probe(struct platform_device *pdev)
304348 guid_t guid ;
305349 int ret ;
306350
351+ /* Get the resource of the bootfifo data register. */
352+ mlxbf_rsh_boot_data = devm_platform_ioremap_resource (pdev , 0 );
353+ if (IS_ERR (mlxbf_rsh_boot_data ))
354+ return PTR_ERR (mlxbf_rsh_boot_data );
355+
356+ /* Get the resource of the bootfifo counter register. */
357+ mlxbf_rsh_boot_cnt = devm_platform_ioremap_resource (pdev , 1 );
358+ if (IS_ERR (mlxbf_rsh_boot_cnt ))
359+ return PTR_ERR (mlxbf_rsh_boot_cnt );
360+
307361 /* Ensure we have the UUID we expect for this service. */
308362 arm_smccc_smc (MLXBF_BOOTCTL_SIP_SVC_UID , 0 , 0 , 0 , 0 , 0 , 0 , 0 , & res );
309363 guid_parse (mlxbf_bootctl_svc_uuid_str , & guid );
@@ -321,11 +375,25 @@ static int mlxbf_bootctl_probe(struct platform_device *pdev)
321375 if (ret < 0 )
322376 dev_warn (& pdev -> dev , "Unable to reset the EMMC boot mode\n" );
323377
378+ ret = sysfs_create_bin_file (& pdev -> dev .kobj ,
379+ & mlxbf_bootctl_bootfifo_sysfs_attr );
380+ if (ret )
381+ pr_err ("Unable to create bootfifo sysfs file, error %d\n" , ret );
382+
383+ return ret ;
384+ }
385+
386+ static int mlxbf_bootctl_remove (struct platform_device * pdev )
387+ {
388+ sysfs_remove_bin_file (& pdev -> dev .kobj ,
389+ & mlxbf_bootctl_bootfifo_sysfs_attr );
390+
324391 return 0 ;
325392}
326393
327394static struct platform_driver mlxbf_bootctl_driver = {
328395 .probe = mlxbf_bootctl_probe ,
396+ .remove = mlxbf_bootctl_remove ,
329397 .driver = {
330398 .name = "mlxbf-bootctl" ,
331399 .dev_groups = mlxbf_bootctl_groups ,
0 commit comments