lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 3 Jan 2022 05:31:27 +0000
From:   Tony Huang 黃懷厚 <tony.huang@...plus.com>
To:     Greg KH <gregkh@...uxfoundation.org>,
        Tony Huang <tonyhuang.sunplus@...il.com>
CC:     "robh+dt@...nel.org" <robh+dt@...nel.org>,
        "devicetree@...r.kernel.org" <devicetree@...r.kernel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        "derek.kiernan@...inx.com" <derek.kiernan@...inx.com>,
        "dragan.cvetic@...inx.com" <dragan.cvetic@...inx.com>,
        "arnd@...db.de" <arnd@...db.de>,
        Wells Lu 呂芳騰 <wells.lu@...plus.com>
Subject: RE: [PATCH v6 2/2] misc: Add iop driver for Sunplus SP7021

Dear Greg:

> > IOP(8051) embedded inside SP7021 which is used as Processor for I/O
> > control, monitor RTC interrupt and cooperation with CPU & PMC in power
> > management purpose.
> > The IOP core is DQ8051, so also named IOP8051, it supports dedicated
> > JTAG debug pins which share with SP7021.
> > In standby mode operation, the power spec reach 400uA.
> >
> > Signed-off-by: Tony Huang <tonyhuang.sunplus@...il.com>
> > ---
> > Changes in v6:
> >  - Added sysfs read/write description.
> >  - Modify sysfs read function.
> >  - Addressed comments from kernel test robot.
> >
> >  Documentation/ABI/testing/sysfs-platform-soc@B |  25 ++
> >  MAINTAINERS                                    |   2 +
> >  drivers/misc/Kconfig                           |  12 +
> >  drivers/misc/Makefile                          |   1 +
> >  drivers/misc/sunplus_iop.c                     | 476
> +++++++++++++++++++++++++
> >  5 files changed, 516 insertions(+)
> >  create mode 100644 Documentation/ABI/testing/sysfs-platform-soc@B
> >  create mode 100644 drivers/misc/sunplus_iop.c
> >
> > diff --git a/Documentation/ABI/testing/sysfs-platform-soc@B
> > b/Documentation/ABI/testing/sysfs-platform-soc@B
> > new file mode 100644
> > index 0000000..6272919
> > --- /dev/null
> > +++ b/Documentation/ABI/testing/sysfs-platform-soc@B
> > @@ -0,0 +1,25 @@
> > +What:		/sys/devices/platform/soc@...c000400.iop/sp_iop_mailbox
> > +Date:		December 2021
> > +KernelVersion:	5.16
> > +Contact:	Tony Huang <tonyhuang.sunplus@...il.com>
> > +Description:
> > +		Show 8051 mailbox0 data.
> 
> What format is the data in?
> 

Unsigned short

> 
> 
> > +
> > +What:		/sys/devices/platform/soc@...c000400.iop/sp_iop_mode
> > +Date:		December 2021
> > +KernelVersion:	5.16
> > +Contact:	Tony Huang <tonyhuang.sunplus@...il.com>
> > +Description:
> > +		Read-Write.
> > +
> > +		Write this file.
> > +		Operation mode of IOP is switched to standby mode by writing
> > +		"1" to sysfs.
> > +		Operation mode of IOP is switched to normal mode by writing
> > +		"0" to sysfs.
> > +
> > +		Read this file.
> > +		Show operation mode of IOP. "0" is normal mode. "1" is standby
> > +		mode.
> > +
> > +
> > diff --git a/MAINTAINERS b/MAINTAINERS index 6f336c9..cbc8dff 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -18245,7 +18245,9 @@ F:	drivers/net/ethernet/dlink/sundance.c
> >  SUNPLUS IOP DRIVER
> >  M:	Tony Huang <tonyhuang.sunplus@...il.com>
> >  S:	Maintained
> > +F:	Documentation/ABI/testing/sysfs-platform-soc@B
> >  F:	Documentation/devicetree/bindings/misc/sunplu-iop.yaml
> > +F:	drivers/misc/sunplus_iop.c
> >
> >  SUPERH
> >  M:	Yoshinori Sato <ysato@...rs.sourceforge.jp>
> > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index
> > 0f5a49f..45655ea 100644
> > --- a/drivers/misc/Kconfig
> > +++ b/drivers/misc/Kconfig
> > @@ -470,6 +470,18 @@ config HISI_HIKEY_USB
> >  	  switching between the dual-role USB-C port and the USB-A host ports
> >  	  using only one USB controller.
> >
> > +config SUNPLUS_IOP
> > +	tristate "Sunplus IOP support"
> > +	default ARCH_SUNPLUS
> > +	help
> > +	  Sunplus I/O processor (8051) driver.
> > +	  Processor for I/O control, RTC wake-up proceduce management,
> > +	  and cooperation with CPU&PMC in power management.
> > +	  Need Install DQ8051, The DQ8051 bin file generated by keil C.
> 
> I do not understand this sentence, what do you mean by it?  Can you provide a
> link to where the files that are required are?  Why not include them in the
> linux-firmware project?
> 

1.We will provide users with 8051 normal and standby source code.			
  Path: https://sunplus.atlassian.net/wiki/spaces/doc/pages/610172933/How+to+use+I+O+processor+8051+of+SP7021#5.-Write-C-or-assembly-source-files-for-IOP			
2.Users can follow the operation steps to generate normal.bin and standby.bin.			
  Path: https://sunplus.atlassian.net/wiki/spaces/doc/pages/466190338/26.+IOP8051			
  26.5 How To Create 8051 bin file			

> > +
> > +	  This driver can also be built as a module.  If so, the module
> > +	  will be called sunplus_iop.
> > +
> >  source "drivers/misc/c2port/Kconfig"
> >  source "drivers/misc/eeprom/Kconfig"
> >  source "drivers/misc/cb710/Kconfig"
> > diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index
> > a086197..eafeab6 100644
> > --- a/drivers/misc/Makefile
> > +++ b/drivers/misc/Makefile
> > @@ -52,6 +52,7 @@ obj-$(CONFIG_DW_XDATA_PCIE)	+= dw-xdata-pcie.o
> >  obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
> >  obj-$(CONFIG_OCXL)		+= ocxl/
> >  obj-$(CONFIG_BCM_VK)		+= bcm-vk/
> > +obj-$(CONFIG_SUNPLUS_IOP)	+= sunplus_iop.o
> >  obj-y				+= cardreader/
> >  obj-$(CONFIG_PVPANIC)   	+= pvpanic/
> >  obj-$(CONFIG_HABANA_AI)		+= habanalabs/
> > diff --git a/drivers/misc/sunplus_iop.c b/drivers/misc/sunplus_iop.c
> > new file mode 100644 index 0000000..a16d9e6
> > --- /dev/null
> > +++ b/drivers/misc/sunplus_iop.c
> > @@ -0,0 +1,476 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * The IOP driver for Sunplus SP7021
> > + *
> > + * Copyright (C) 2021 Sunplus Technology Inc.
> > + *
> > + * All Rights Reserved.
> > + */
> > +#include <linux/delay.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/firmware.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/module.h>
> > +#include <linux/miscdevice.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_gpio.h>
> > +
> > +enum IOP_Status_e {
> > +	IOP_SUCCESS,                /* successful */
> > +	IOP_ERR_IOP_BUSY,           /* IOP is busy */
> > +};
> > +
> > +struct regs_moon0 {
> > +	u32 stamp;         /* 00 */
> > +	u32 clken[10];     /* 01~10 */
> > +	u32 gclken[10];    /* 11~20 */
> > +	u32 reset[10];     /* 21~30 */
> > +	u32 sfg_cfg_mode;  /* 31 */
> 
> What are these comments numbering?
> 

regs_moon0 is Group 0 moon register.					
The Group0 moon register range is 0x9c00000~0x9c00007F					
/*00*/: 0x9c000000~0x9c000003					
/*01~10*/:0x9c000004~0x9c00002b					
/*11~20*/:0x9c00002c~0x9c000053					
/*21~30*/:0x9c000054~0x9c00007b					
/*31*/:0x9c00007c~0x9c00007f					

> > +};
> > +
> > +struct regs_iop {
> > +	u32 iop_control;/* 00 */
> > +	u32 iop_reg1;/* 01 */
> > +	u32 iop_bp;/* 02 */
> > +	u32 iop_regsel;/* 03 */
> > +	u32 iop_regout;/* 04 */
> > +	u32 iop_reg5;/* 05 */
> > +	u32 iop_resume_pcl;/* 06 */
> > +	u32 iop_resume_pch;/* 07 */
> > +	u32 iop_data0;/* 08 */
> > +	u32 iop_data1;/* 09 */
> > +	u32 iop_data2;/* 10 */
> > +	u32 iop_data3;/* 11 */
> > +	u32 iop_data4;/* 12 */
> > +	u32 iop_data5;/* 13 */
> > +	u32 iop_data6;/* 14 */
> > +	u32 iop_data7;/* 15 */
> > +	u32 iop_data8;/* 16 */
> > +	u32 iop_data9;/* 17 */
> > +	u32 iop_data10;/* 18 */
> > +	u32 iop_data11;/* 19 */
> > +	u32 iop_base_adr_l;/* 20 */
> > +	u32 iop_base_adr_h;/* 21 */
> > +	u32 memory_bridge_control;/* 22 */
> > +	u32 iop_regmap_adr_l;/* 23 */
> > +	u32 iop_regmap_adr_h;/* 24 */
> > +	u32 iop_direct_adr;/* 25*/
> > +	u32 reserved[6];/* 26~31 */
> 
> Same here, what are these numbers?
> 
> And why are they not lined up like the previous structure?
> 

Sorry, I don't understand what you mean. Isn't this a struct?					

> 
> > +};
> > +
> > +struct regs_iop_pmc {
> > +	u32 PMC_TIMER;/* 00 */
> > +	u32 PMC_CTRL;/* 01 */
> > +	u32 XTAL27M_PASSWORD_I;/* 02 */
> > +	u32 XTAL27M_PASSWORD_II;/* 03 */
> > +	u32 XTAL32K_PASSWORD_I;/* 04 */
> > +	u32 XTAL32K_PASSWORD_II;/* 05 */
> > +	u32 CLK27M_PASSWORD_I;/* 06 */
> > +	u32 CLK27M_PASSWORD_II;/* 07 */
> > +	u32 PMC_TIMER2;/* 08 */
> > +	u32 reserved[23];/* 9~31 */
> 
> Same comment question here.
> 
> > +};
> > +
> > +#define NORMAL_CODE_MAX_SIZE 0X1000
> 
> "0x"?
> 

This is the maximum size of normal.bin that can be received.					

> > +#define STANDBY_CODE_MAX_SIZE 0x4000
> 
> What are these for?
> 

This is the maximum size of standby.bin that can be received.					

> > +struct sp_iop {
> > +	struct miscdevice dev;			// iop device
> 
> Why the comment?
> 

I will remove it.

> > +	struct mutex write_lock;
> > +	void *iop_regs;
> > +	void *pmc_regs;
> > +	void *moon0_regs;
> 
> Why void pointers?  You created structures above, use them!
> 

Because I received "Reported-by: kernel test robot <lkp@...el.com>", warmming message. As follows:										
sparse warnings: (new ones prefixed by >>)										
   drivers/misc/sunplus_iop.c:94:39: sparse: sparse: cast removes address space '__iomem' of expression										
   drivers/misc/sunplus_iop.c:95:43: sparse: sparse: cast removes address space '__iomem' of expression										
>> drivers/misc/sunplus_iop.c:100:16: sparse: sparse: incorrect type in argument 1 (different address spaces) @@     expected void *p @@     got void [noderef] __iomem *[assigned] iop_kernel_base @@										
   drivers/misc/sunplus_iop.c:100:16: sparse:     expected void *p										
   drivers/misc/sunplus_iop.c:100:16: sparse:     got void [noderef] __iomem *[assigned] iop_kernel_base										

> This is not Windows programming :)
> 

I will modify it.

> 
> > +	int irq;
> > +	int gpio_wakeup;
> > +	unsigned char iop_normal_code[NORMAL_CODE_MAX_SIZE];
> > +	unsigned char iop_standby_code[STANDBY_CODE_MAX_SIZE];
> > +	resource_size_t iop_mem_start;
> > +	resource_size_t iop_mem_size;
> > +	bool mode;
> 
> How can a "mode" be boolean?  Perhaps a better name?
> 

Ok. I will modify it.

> > +};
> > +
> > +static void sp_iop_normal_mode(struct sp_iop *iop) {
> > +	struct regs_iop *p_iop_reg = (struct regs_iop *)iop->iop_regs;
> 
> See, don't use a void pointer, use the real structure please.
> 

I will modify it.

> > +	struct regs_moon0 *p_moon0_reg = (struct regs_moon0
> *)iop->moon0_regs;
> > +	void *iop_kernel_base;
> 
> Why void?  Isn't this a structure too?
> 

I will modify it.

> > +	unsigned int reg;
> > +
> > +	iop_kernel_base = ioremap(iop->iop_mem_start,
> NORMAL_CODE_MAX_SIZE);
> > +	memset(iop_kernel_base, 0, NORMAL_CODE_MAX_SIZE);
> > +	memcpy(iop_kernel_base, iop->iop_normal_code,
> NORMAL_CODE_MAX_SIZE);
> > +
> > +	writel(0x00100010, &p_moon0_reg->clken[0]);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg |= 0x01;
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg &= ~(0x8000);
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg |= 0x0200;//disable watchdog event reset IOP
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	reg = (iop->iop_mem_start & 0xFFFF);
> > +	writel(reg, &p_iop_reg->iop_base_adr_l);
> > +	reg	= (iop->iop_mem_start >> 16);
> > +	writel(reg, &p_iop_reg->iop_base_adr_h);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg &= ~(0x01);
> > +	writel(reg, &p_iop_reg->iop_control);
> > +	iop->mode = 0;
> > +}
> > +
> > +static void sp_iop_standby_mode(struct sp_iop *iop) {
> > +	struct regs_iop *p_iop_reg = (struct regs_iop *)iop->iop_regs;
> > +	struct regs_moon0 *p_moon0_reg = (struct regs_moon0
> *)iop->moon0_regs;
> > +	void *iop_kernel_base;
> > +	unsigned long reg;
> > +
> > +	iop_kernel_base = ioremap(iop->iop_mem_start,
> STANDBY_CODE_MAX_SIZE);
> > +	memset(iop_kernel_base, 0, STANDBY_CODE_MAX_SIZE);
> > +	memcpy(iop_kernel_base, iop->iop_standby_code,
> > +STANDBY_CODE_MAX_SIZE);
> > +
> > +	writel(0x00100010, &p_moon0_reg->clken[0]);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg |= 0x01;
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg &= ~(0x8000);
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg |= 0x0200;//disable watchdog event reset IOP
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	reg = (iop->iop_mem_start & 0xFFFF);
> > +	writel(reg, &p_iop_reg->iop_base_adr_l);
> > +	reg = (iop->iop_mem_start >> 16);
> > +	writel(reg, &p_iop_reg->iop_base_adr_h);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg &= ~(0x01);
> > +	writel(reg, &p_iop_reg->iop_control);
> > +	iop->mode = 1;
> > +}
> > +
> > +#define IOP_READY	0x4
> > +#define RISC_READY	0x8
> > +#define WAKEUP_PIN	0xFE02
> > +#define S1	0x5331
> > +#define S3	0x5333
> 
> 
> What are these values for?
> 

These values ​​will be written in the mailbox register. System linux kernel and 8051 will read the mailbox register.
IOP_READY=0x4, RISC_READY=0x8: 8051 informs linux kernel.8051 has been switched to stanby.bin code.
WAKEUP_PIN=0xFE02: System linux kernel tells 8051 which gpio pin to wake up through. 
S1=0x5331, S3=0x5333: System linux kernel tells 8051 whether to execute S1 mode or S3 mode.

> > +static int sp_iop_s3mode(struct device *dev, struct sp_iop *iop) {
> > +	struct regs_iop *p_iop_reg = (struct regs_iop *)iop->iop_regs;
> > +	struct regs_moon0 *p_moon0_reg = (struct regs_moon0
> *)iop->moon0_regs;
> > +	struct regs_iop_pmc *p_iop_pmc_reg = (struct regs_iop_pmc
> *)iop->pmc_regs;
> > +	unsigned int reg;
> > +	int ret, value;
> > +
> > +	writel(0x00100010, &p_moon0_reg->clken[0]);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg &= ~(0x8000);
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg |= 0x1;
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	//PMC set
> > +	writel(0x00010001, &p_iop_pmc_reg->PMC_TIMER);
> > +	reg = readl(&p_iop_pmc_reg->PMC_CTRL);
> > +	reg |= 0x23;// disable system reset PMC, enalbe power down 27M,
> > +enable gating 27M
> 
> What is "27M"?
> 

clock 27Mhz

> > +	writel(reg, &p_iop_pmc_reg->PMC_CTRL);
> > +
> > +	writel(0x55aa00ff, &p_iop_pmc_reg->XTAL27M_PASSWORD_I);
> > +	writel(0x00ff55aa, &p_iop_pmc_reg->XTAL27M_PASSWORD_II);
> > +	writel(0xaa00ff55, &p_iop_pmc_reg->XTAL32K_PASSWORD_I);
> > +	writel(0xff55aa00, &p_iop_pmc_reg->XTAL32K_PASSWORD_II);
> > +	writel(0xaaff0055, &p_iop_pmc_reg->CLK27M_PASSWORD_I);
> > +	writel(0x5500aaff, &p_iop_pmc_reg->CLK27M_PASSWORD_II);
> > +	writel(0x01000100, &p_iop_pmc_reg->PMC_TIMER2);
> > +
> > +	//IOP Hardware IP reset
> 
> Always put a ' ' after '//'
> 

OK, I will modify it.

> 
> > +	reg = readl(&p_moon0_reg->reset[0]);
> > +	reg |= 0x10;
> > +	writel(reg, (&p_moon0_reg->reset[0]));
> > +	reg &= ~(0x10);
> > +	writel(reg, (&p_moon0_reg->reset[0]));
> > +
> > +	writel(0x00ff0085, (iop->moon0_regs + 32 * 4 * 1 + 4 * 1));
> > +
> > +	reg = readl(iop->moon0_regs + 32 * 4 * 1 + 4 * 2);
> > +	reg |= 0x08000800;
> > +	writel(reg, (iop->moon0_regs + 32 * 4 * 1 + 4 * 2));
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg |= 0x0200;//disable watchdog event reset IOP
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	reg = (iop->iop_mem_start & 0xFFFF);
> > +	writel(reg, &p_iop_reg->iop_base_adr_l);
> > +	reg = (iop->iop_mem_start >> 16);
> > +	writel(reg, &p_iop_reg->iop_base_adr_h);
> > +
> > +	reg = readl(&p_iop_reg->iop_control);
> > +	reg &= ~(0x01);
> > +	writel(reg, &p_iop_reg->iop_control);
> > +
> > +	writel(WAKEUP_PIN, &p_iop_reg->iop_data0);
> > +	writel(iop->gpio_wakeup, &p_iop_reg->iop_data1);
> > +
> > +	ret = readl_poll_timeout(&p_iop_reg->iop_data2, value,
> > +				 (value & IOP_READY) == IOP_READY, 1000, 10000);
> > +	if (ret) {
> > +		dev_err(dev, "timed out\n");
> > +		return ret;
> > +	}
> > +
> > +	writel(RISC_READY, &p_iop_reg->iop_data2);
> > +	writel(0x00, &p_iop_reg->iop_data5);
> > +	writel(0x60, &p_iop_reg->iop_data6);
> > +
> > +	ret = readl_poll_timeout(&p_iop_reg->iop_data7, value,
> > +				 value == 0xaaaa, 1000, 10000);
> > +	if (ret) {
> > +		dev_err(dev, "timed out\n");
> > +		return ret;
> > +	}
> > +
> > +	writel(0xdd, &p_iop_reg->iop_data1);//8051 bin file call Ultra low
> function.
> > +	mdelay(10);
> 
> Where did 10 come from?  How do you know that is correct?
> 

I need time to move stanby.bin code 16K data from SDRAM to 8051's icache.		
10msec should be enough		

> Same comment for your other delay calls in the driver.
> 
> > +	return 0;
> > +}
> > +
> > +static int sp_iop_s1mode(struct device *dev, struct sp_iop *iop) {
> > +	struct regs_iop *p_iop_reg = (struct regs_iop *)iop->iop_regs;
> > +	int ret, value;
> > +
> > +	ret = readl_poll_timeout(&p_iop_reg->iop_data2, value,
> > +				 (value & IOP_READY) == IOP_READY, 1000, 10000);
> > +	if (ret) {
> > +		dev_err(dev, "timed out\n");
> > +		return ret;
> > +	}
> > +
> > +	writel(RISC_READY, &p_iop_reg->iop_data2);
> > +	writel(0x00, &p_iop_reg->iop_data5);
> > +	writel(0x60, &p_iop_reg->iop_data6);
> > +
> > +	ret = readl_poll_timeout(&p_iop_reg->iop_data7, value,
> > +				 value == 0xaaaa, 1000, 10000);
> > +	if (ret) {
> > +		dev_err(dev, "timed out\n");
> > +		return ret;
> > +	}
> > +
> > +	writel(0xee, &p_iop_reg->iop_data1);//8051 bin file call S1_mode
> function.
> > +	mdelay(10);
> > +	return 0;
> > +}
> > +
> > +static ssize_t sp_iop_mailbox_show(struct device *dev, struct
> > +device_attribute *attr, char *buf) {
> > +	struct sp_iop *iop = dev_get_drvdata(dev);
> > +	struct regs_iop *p_iop_reg = (struct regs_iop *)iop->iop_regs;
> > +	unsigned int mailbox;
> > +
> > +	mailbox = readl(&p_iop_reg->iop_data0);
> > +	return sysfs_emit(buf, "mailbox = 0x%x\n", mailbox); }
> > +
> > +static ssize_t sp_iop_mode_show(struct device *dev, struct
> > +device_attribute *attr, char *buf) {
> > +	struct sp_iop *iop = dev_get_drvdata(dev);
> > +
> > +	return sysfs_emit(buf, "bin code mode = 0x%x\n", iop->mode);
> 
> That is not a valid sysfs file output.  Again "ONE VALUE PER FILE", you should
> never have to parse the output like this.
> 

I will change sysfs_emit(buf, "%x\n", iop->mode);

> > +}
> > +
> > +static ssize_t sp_iop_mode_store(struct device *dev, struct device_attribute
> *attr,
> > +				 const char *buf, size_t count)
> > +{
> > +	struct sp_iop *iop = dev_get_drvdata(dev);
> > +
> > +	if (sysfs_streq(buf, "0"))
> > +		sp_iop_normal_mode(iop);
> > +	else if (sysfs_streq(buf, "1"))
> > +		sp_iop_standby_mode(iop);
> > +	return count;
> 
> So no matter what you write here, it will not return an error?
> 

I will modify it.

> That is not correct.
> 
> > +}
> > +
> > +static DEVICE_ATTR_RO(sp_iop_mailbox); static
> > +DEVICE_ATTR_RW(sp_iop_mode);
> > +
> > +static int  sp_iop_get_normal_code(struct device *dev, struct sp_iop
> > +*iop) {
> > +	const struct firmware *fw;
> > +	static const char file[] = "normal.bin";
> > +	unsigned int err, i;
> > +
> > +	err = request_firmware(&fw, file, dev);
> > +	if (err) {
> > +		dev_err(dev, "get bin file error\n");
> > +		return err;
> > +	}
> > +
> > +	for (i = 0; i < NORMAL_CODE_MAX_SIZE; i++) {
> > +		char temp;
> > +
> > +		temp = fw->data[i];
> > +		iop->iop_normal_code[i] = temp;
> > +	}
> > +	release_firmware(fw);
> > +	return err;
> > +}
> > +
> > +static int  sp_iop_get_standby_code(struct device *dev, struct sp_iop
> > +*iop) {
> > +	const struct firmware *fw;
> > +	static const char file[] = "standby.bin";
> > +	unsigned int err, i;
> > +
> > +	err = request_firmware(&fw, file, dev);
> > +	if (err) {
> > +		dev_err(dev, "get bin file error\n");
> > +		return err;
> > +	}
> > +
> > +	for (i = 0; i < STANDBY_CODE_MAX_SIZE; i++) {
> > +		char temp;
> > +
> > +		temp = fw->data[i];
> > +		iop->iop_standby_code[i] = temp;
> > +	}
> > +	release_firmware(fw);
> > +	return err;
> > +}
> > +
> > +static int sp_iop_get_resources(struct platform_device *pdev, struct
> > +sp_iop *p_sp_iop_info) {
> > +	struct resource *r;
> > +
> > +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iop");
> > +	p_sp_iop_info->iop_regs = devm_ioremap_resource(&pdev->dev, r);
> > +	if (IS_ERR(p_sp_iop_info->iop_regs)) {
> > +		dev_err(&pdev->dev, "ioremap fail\n");
> > +		return PTR_ERR(p_sp_iop_info->iop_regs);
> > +	}
> > +
> > +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> "iop_pmc");
> > +	p_sp_iop_info->pmc_regs = devm_ioremap_resource(&pdev->dev, r);
> > +	if (IS_ERR(p_sp_iop_info->pmc_regs)) {
> > +		dev_err(&pdev->dev, "ioremap fail\n");
> > +		return PTR_ERR(p_sp_iop_info->pmc_regs);
> > +	}
> > +
> > +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "moon0");
> > +	p_sp_iop_info->moon0_regs = devm_ioremap_resource(&pdev->dev, r);
> > +	if (IS_ERR(p_sp_iop_info->moon0_regs)) {
> > +		dev_err(&pdev->dev, "ioremap fail\n");
> > +		return PTR_ERR(p_sp_iop_info->moon0_regs);
> > +	}
> > +	return IOP_SUCCESS;
> > +}
> > +
> > +static int sp_iop_platform_driver_probe(struct platform_device *pdev)
> > +{
> > +	int ret = -ENXIO;
> > +	int rc;
> > +	struct sp_iop *iop;
> > +	struct device_node *memnp;
> > +	struct resource mem_res;
> > +
> > +	iop = devm_kzalloc(&pdev->dev, sizeof(struct sp_iop), GFP_KERNEL);
> > +	if (!iop) {
> > +		ret	= -ENOMEM;
> > +		goto fail_kmalloc;
> > +	}
> > +	/* init */
> > +	mutex_init(&iop->write_lock);
> > +	ret = sp_iop_get_resources(pdev, iop);
> > +
> > +	//Get reserve address
> > +	memnp = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
> > +	if (!memnp) {
> > +		dev_err(&pdev->dev, "no memory-region node\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	rc = of_address_to_resource(memnp, 0, &mem_res);
> > +	of_node_put(memnp);
> > +	if (rc) {
> > +		dev_err(&pdev->dev, "failed to translate memory-region to a
> resource\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	iop->iop_mem_start = mem_res.start;
> > +	iop->iop_mem_size = resource_size(&mem_res);
> > +
> > +	ret = sp_iop_get_normal_code(&pdev->dev, iop);
> > +	if (ret != 0) {
> > +		dev_err(&pdev->dev, "get normal code err=%d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	ret = sp_iop_get_standby_code(&pdev->dev, iop);
> > +	if (ret != 0) {
> > +		dev_err(&pdev->dev, "get standby code err=%d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	sp_iop_normal_mode(iop);
> > +	platform_set_drvdata(pdev, iop);
> > +	device_create_file(&pdev->dev, &dev_attr_sp_iop_mailbox);
> > +	device_create_file(&pdev->dev, &dev_attr_sp_iop_mode);
> 
> You just raced with userspace and lost.  Set the default groups pointer of the
> misc device to your attribute group and then they will be automatically
> created for you.
> 
> 
> 
> 
> > +	iop->gpio_wakeup = of_get_named_gpio(pdev->dev.of_node,
> "iop-wakeup", 0);
> > +	return 0;
> > +
> > +fail_kmalloc:
> > +	return ret;
> > +}
> > +
> > +static void sp_iop_platform_driver_shutdown(struct platform_device
> > +*pdev) {
> > +	struct sp_iop *iop = platform_get_drvdata(pdev);
> > +	struct regs_iop *p_iop_reg = (struct regs_iop *)iop->iop_regs;
> > +	unsigned int value;
> > +
> > +	sp_iop_standby_mode(iop);
> > +	mdelay(10);
> 
> Why sleep on shutdown?
> 

I need time to switch from normal.bin code to standby.bin code.				

> thanks,
> 
> greg k-h

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ