All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/7] bcma: add device tree support
@ 2014-08-24 21:24 ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

This adds device tree support to bcma. In addition it also provides the 
sprom needed by bcma through a device tree driver.
This is needed for the Broadcom BCM47XX/BCM53XX ARM SoCs (NorthStar).

bcma drives the system AIX bus. This bus is scanable, so we 
automatically detect the cores attached to this bus. We only have to 
provide the address of the first core, this can now be done through 
device tree.
It is not possible to find out what IRQ is associated to a specific 
core, we have to provide this through device tree.

Broadcom uses a nvram which is a key value store on the flash chip. 
This nvram contains the mac addresses to be used by the wifi and 
Ethernet devices, the configuration data for the switch, the 
calibration data for the wifi cores and some more stuff. Currently bcma 
assumes to get some sprom when it gets initialized on a SoC. This sprom 
is a structure with all the data which are originally stored in the 
nvram. When bcma is used on a PCIe wifi card this data is fetched from 
some eeporm on the card. The nvram could contains more than one sprom, 
in case there is a main Baordocm SoC and a Broadcom wifi card connected 
via PCIe this PCIe cards mostly use the nvram to store the sprom with 
the calibration data.

This patch series adds two drivers, the nvram driver which reads the 
nvram and provides an interface to fetch values by giving a key and a 
driver which creates a sprom based on a given nvram. These two things 
are no real drivers, they are just converting stuff. I made them 
drivers so they can be replaced with some other drivers which are 
fetching the sprom from other storages. I know that the BCM63XX SoCs 
are also using an sprom, but there it is stored in a file on the file 
system. 

Some code was copied from the mips code at arch/mips/bcm47xx/ in the 
end I want to make this mips code also use these new drivers.

There is no device I know of which uses more than one nvram and I do 
not think there will ever be such a device. With this patch you have to 
provide a reference to the nvram you want to fetch data from which is a 
little bit annoying, should I remove this parameter and assume there is 
just one nvram driver in the system?

I am interested on comments if this architecture is correct or if there 
are some improvements I could do. I haven't fond similar code in the 
kernel.

Through which tree should I merge the final patches?

This is based on linus 3.17-rc1.

Log output:
bcma: bus0: Found chip with id 0xCF12, rev 0x00 and package 0x02
bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id 0x800, rev 0x2A, class 0x0)
bcma: bus0: Core 1 found: Chipcommon B (manuf 0x4BF, id 0x50B, rev 0x01, class 0x0)
bcma: bus0: Core 2 found: DMA (manuf 0x4BF, id 0x502, rev 0x01, class 0x0)
bcma: bus0: Core 3 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 4 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 5 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 6 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 7 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 8 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 9 found: ARM Cortex A9 core (ihost) (manuf 0x4BF, id 0x510, rev 0x01, class 0x0)
bcma: bus0: Core 10 found: USB 2.0 (manuf 0x4BF, id 0x504, rev 0x01, class 0x0)
bcma: bus0: Core 11 found: USB 3.0 (manuf 0x4BF, id 0x505, rev 0x01, class 0x0)
bcma: bus0: Core 12 found: SDIO3 (manuf 0x4BF, id 0x503, rev 0x01, class 0x0)
bcma: bus0: Core 13 found: ARM Cortex A9 JTAG (manuf 0x4BF, id 0x506, rev 0x01, class 0x0)
bcma: bus0: Core 14 found: Denali DDR2/DDR3 memory controller (manuf 0x4BF, id 0x507, rev 0x01, class 0x0)
bcma: bus0: Core 15 found: ROM (manuf 0x4BF, id 0x508, rev 0x01, class 0x0)
bcma: bus0: Core 16 found: NAND flash controller (manuf 0x4BF, id 0x509, rev 0x01, class 0x0)
bcma: bus0: Core 17 found: SPI flash controller (manuf 0x4BF, id 0x50A, rev 0x01, class 0x0)
bcma: bus0: Found sprom from device tree provider
bgmac bcma0:1: Found PHY addr: 30 (NOREGS)
bgmac bcma0:1: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed
b53_common: found switch: BCM53011, rev 2
bgmac bcma0:2: Found PHY addr: 0
bgmac bcma0:2: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed


Hauke Mehrtens (7):
  MIPS: BCM47XX: move the nvram header file into common space
  bcm47xx-nvram: add new broadcom nvram driver with dt support
  bcm47xx-sprom: add Broadcom sprom parser driver
  bcma: register bcma as device tree driver
  bcma: get IRQ numbers from dt
  bcma: get sprom from devicetree
  ARM: BCM5301X: register bcma bus

 Documentation/devicetree/bindings/bus/bcma.txt     |  46 ++
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 +
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 arch/arm/boot/dts/bcm4708.dtsi                     |  58 ++
 arch/mips/bcm47xx/board.c                          |  42 +-
 arch/mips/bcm47xx/nvram.c                          |   9 +-
 arch/mips/bcm47xx/setup.c                          |   6 +-
 arch/mips/bcm47xx/sprom.c                          |   6 +-
 arch/mips/bcm47xx/time.c                           |   4 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h |  53 --
 drivers/bcma/host_soc.c                            |  70 +++
 drivers/bcma/main.c                                |  42 +-
 drivers/bcma/sprom.c                               |  51 +-
 drivers/misc/Kconfig                               |  27 +
 drivers/misc/Makefile                              |   2 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |  10 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   7 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   9 +-
 include/linux/bcm47xx_nvram.h                      |  71 +++
 include/linux/bcma/bcma.h                          |   2 +
 22 files changed, 1350 insertions(+), 105 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 drivers/misc/bcm47xx-nvram.c
 create mode 100644 drivers/misc/bcm47xx-sprom.c
 create mode 100644 include/linux/bcm47xx_nvram.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 0/7] bcma: add device tree support
@ 2014-08-24 21:24 ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

This adds device tree support to bcma. In addition it also provides the 
sprom needed by bcma through a device tree driver.
This is needed for the Broadcom BCM47XX/BCM53XX ARM SoCs (NorthStar).

bcma drives the system AIX bus. This bus is scanable, so we 
automatically detect the cores attached to this bus. We only have to 
provide the address of the first core, this can now be done through 
device tree.
It is not possible to find out what IRQ is associated to a specific 
core, we have to provide this through device tree.

Broadcom uses a nvram which is a key value store on the flash chip. 
This nvram contains the mac addresses to be used by the wifi and 
Ethernet devices, the configuration data for the switch, the 
calibration data for the wifi cores and some more stuff. Currently bcma 
assumes to get some sprom when it gets initialized on a SoC. This sprom 
is a structure with all the data which are originally stored in the 
nvram. When bcma is used on a PCIe wifi card this data is fetched from 
some eeporm on the card. The nvram could contains more than one sprom, 
in case there is a main Baordocm SoC and a Broadcom wifi card connected 
via PCIe this PCIe cards mostly use the nvram to store the sprom with 
the calibration data.

This patch series adds two drivers, the nvram driver which reads the 
nvram and provides an interface to fetch values by giving a key and a 
driver which creates a sprom based on a given nvram. These two things 
are no real drivers, they are just converting stuff. I made them 
drivers so they can be replaced with some other drivers which are 
fetching the sprom from other storages. I know that the BCM63XX SoCs 
are also using an sprom, but there it is stored in a file on the file 
system. 

Some code was copied from the mips code at arch/mips/bcm47xx/ in the 
end I want to make this mips code also use these new drivers.

There is no device I know of which uses more than one nvram and I do 
not think there will ever be such a device. With this patch you have to 
provide a reference to the nvram you want to fetch data from which is a 
little bit annoying, should I remove this parameter and assume there is 
just one nvram driver in the system?

I am interested on comments if this architecture is correct or if there 
are some improvements I could do. I haven't fond similar code in the 
kernel.

Through which tree should I merge the final patches?

This is based on linus 3.17-rc1.

Log output:
bcma: bus0: Found chip with id 0xCF12, rev 0x00 and package 0x02
bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id 0x800, rev 0x2A, class 0x0)
bcma: bus0: Core 1 found: Chipcommon B (manuf 0x4BF, id 0x50B, rev 0x01, class 0x0)
bcma: bus0: Core 2 found: DMA (manuf 0x4BF, id 0x502, rev 0x01, class 0x0)
bcma: bus0: Core 3 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 4 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 5 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 6 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 7 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 8 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 9 found: ARM Cortex A9 core (ihost) (manuf 0x4BF, id 0x510, rev 0x01, class 0x0)
bcma: bus0: Core 10 found: USB 2.0 (manuf 0x4BF, id 0x504, rev 0x01, class 0x0)
bcma: bus0: Core 11 found: USB 3.0 (manuf 0x4BF, id 0x505, rev 0x01, class 0x0)
bcma: bus0: Core 12 found: SDIO3 (manuf 0x4BF, id 0x503, rev 0x01, class 0x0)
bcma: bus0: Core 13 found: ARM Cortex A9 JTAG (manuf 0x4BF, id 0x506, rev 0x01, class 0x0)
bcma: bus0: Core 14 found: Denali DDR2/DDR3 memory controller (manuf 0x4BF, id 0x507, rev 0x01, class 0x0)
bcma: bus0: Core 15 found: ROM (manuf 0x4BF, id 0x508, rev 0x01, class 0x0)
bcma: bus0: Core 16 found: NAND flash controller (manuf 0x4BF, id 0x509, rev 0x01, class 0x0)
bcma: bus0: Core 17 found: SPI flash controller (manuf 0x4BF, id 0x50A, rev 0x01, class 0x0)
bcma: bus0: Found sprom from device tree provider
bgmac bcma0:1: Found PHY addr: 30 (NOREGS)
bgmac bcma0:1: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed
b53_common: found switch: BCM53011, rev 2
bgmac bcma0:2: Found PHY addr: 0
bgmac bcma0:2: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed


Hauke Mehrtens (7):
  MIPS: BCM47XX: move the nvram header file into common space
  bcm47xx-nvram: add new broadcom nvram driver with dt support
  bcm47xx-sprom: add Broadcom sprom parser driver
  bcma: register bcma as device tree driver
  bcma: get IRQ numbers from dt
  bcma: get sprom from devicetree
  ARM: BCM5301X: register bcma bus

 Documentation/devicetree/bindings/bus/bcma.txt     |  46 ++
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 +
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 arch/arm/boot/dts/bcm4708.dtsi                     |  58 ++
 arch/mips/bcm47xx/board.c                          |  42 +-
 arch/mips/bcm47xx/nvram.c                          |   9 +-
 arch/mips/bcm47xx/setup.c                          |   6 +-
 arch/mips/bcm47xx/sprom.c                          |   6 +-
 arch/mips/bcm47xx/time.c                           |   4 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h |  53 --
 drivers/bcma/host_soc.c                            |  70 +++
 drivers/bcma/main.c                                |  42 +-
 drivers/bcma/sprom.c                               |  51 +-
 drivers/misc/Kconfig                               |  27 +
 drivers/misc/Makefile                              |   2 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |  10 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   7 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   9 +-
 include/linux/bcm47xx_nvram.h                      |  71 +++
 include/linux/bcma/bcma.h                          |   2 +
 22 files changed, 1350 insertions(+), 105 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 drivers/misc/bcm47xx-nvram.c
 create mode 100644 drivers/misc/bcm47xx-sprom.c
 create mode 100644 include/linux/bcm47xx_nvram.h

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 0/7] bcma: add device tree support
@ 2014-08-24 21:24 ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

This adds device tree support to bcma. In addition it also provides the 
sprom needed by bcma through a device tree driver.
This is needed for the Broadcom BCM47XX/BCM53XX ARM SoCs (NorthStar).

bcma drives the system AIX bus. This bus is scanable, so we 
automatically detect the cores attached to this bus. We only have to 
provide the address of the first core, this can now be done through 
device tree.
It is not possible to find out what IRQ is associated to a specific 
core, we have to provide this through device tree.

Broadcom uses a nvram which is a key value store on the flash chip. 
This nvram contains the mac addresses to be used by the wifi and 
Ethernet devices, the configuration data for the switch, the 
calibration data for the wifi cores and some more stuff. Currently bcma 
assumes to get some sprom when it gets initialized on a SoC. This sprom 
is a structure with all the data which are originally stored in the 
nvram. When bcma is used on a PCIe wifi card this data is fetched from 
some eeporm on the card. The nvram could contains more than one sprom, 
in case there is a main Baordocm SoC and a Broadcom wifi card connected 
via PCIe this PCIe cards mostly use the nvram to store the sprom with 
the calibration data.

This patch series adds two drivers, the nvram driver which reads the 
nvram and provides an interface to fetch values by giving a key and a 
driver which creates a sprom based on a given nvram. These two things 
are no real drivers, they are just converting stuff. I made them 
drivers so they can be replaced with some other drivers which are 
fetching the sprom from other storages. I know that the BCM63XX SoCs 
are also using an sprom, but there it is stored in a file on the file 
system. 

Some code was copied from the mips code at arch/mips/bcm47xx/ in the 
end I want to make this mips code also use these new drivers.

There is no device I know of which uses more than one nvram and I do 
not think there will ever be such a device. With this patch you have to 
provide a reference to the nvram you want to fetch data from which is a 
little bit annoying, should I remove this parameter and assume there is 
just one nvram driver in the system?

I am interested on comments if this architecture is correct or if there 
are some improvements I could do. I haven't fond similar code in the 
kernel.

Through which tree should I merge the final patches?

This is based on linus 3.17-rc1.

Log output:
bcma: bus0: Found chip with id 0xCF12, rev 0x00 and package 0x02
bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id 0x800, rev 0x2A, class 0x0)
bcma: bus0: Core 1 found: Chipcommon B (manuf 0x4BF, id 0x50B, rev 0x01, class 0x0)
bcma: bus0: Core 2 found: DMA (manuf 0x4BF, id 0x502, rev 0x01, class 0x0)
bcma: bus0: Core 3 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 4 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 5 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 6 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 7 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 8 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 9 found: ARM Cortex A9 core (ihost) (manuf 0x4BF, id 0x510, rev 0x01, class 0x0)
bcma: bus0: Core 10 found: USB 2.0 (manuf 0x4BF, id 0x504, rev 0x01, class 0x0)
bcma: bus0: Core 11 found: USB 3.0 (manuf 0x4BF, id 0x505, rev 0x01, class 0x0)
bcma: bus0: Core 12 found: SDIO3 (manuf 0x4BF, id 0x503, rev 0x01, class 0x0)
bcma: bus0: Core 13 found: ARM Cortex A9 JTAG (manuf 0x4BF, id 0x506, rev 0x01, class 0x0)
bcma: bus0: Core 14 found: Denali DDR2/DDR3 memory controller (manuf 0x4BF, id 0x507, rev 0x01, class 0x0)
bcma: bus0: Core 15 found: ROM (manuf 0x4BF, id 0x508, rev 0x01, class 0x0)
bcma: bus0: Core 16 found: NAND flash controller (manuf 0x4BF, id 0x509, rev 0x01, class 0x0)
bcma: bus0: Core 17 found: SPI flash controller (manuf 0x4BF, id 0x50A, rev 0x01, class 0x0)
bcma: bus0: Found sprom from device tree provider
bgmac bcma0:1: Found PHY addr: 30 (NOREGS)
bgmac bcma0:1: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed
b53_common: found switch: BCM53011, rev 2
bgmac bcma0:2: Found PHY addr: 0
bgmac bcma0:2: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed


Hauke Mehrtens (7):
  MIPS: BCM47XX: move the nvram header file into common space
  bcm47xx-nvram: add new broadcom nvram driver with dt support
  bcm47xx-sprom: add Broadcom sprom parser driver
  bcma: register bcma as device tree driver
  bcma: get IRQ numbers from dt
  bcma: get sprom from devicetree
  ARM: BCM5301X: register bcma bus

 Documentation/devicetree/bindings/bus/bcma.txt     |  46 ++
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 +
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 arch/arm/boot/dts/bcm4708.dtsi                     |  58 ++
 arch/mips/bcm47xx/board.c                          |  42 +-
 arch/mips/bcm47xx/nvram.c                          |   9 +-
 arch/mips/bcm47xx/setup.c                          |   6 +-
 arch/mips/bcm47xx/sprom.c                          |   6 +-
 arch/mips/bcm47xx/time.c                           |   4 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h |  53 --
 drivers/bcma/host_soc.c                            |  70 +++
 drivers/bcma/main.c                                |  42 +-
 drivers/bcma/sprom.c                               |  51 +-
 drivers/misc/Kconfig                               |  27 +
 drivers/misc/Makefile                              |   2 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |  10 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   7 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   9 +-
 include/linux/bcm47xx_nvram.h                      |  71 +++
 include/linux/bcma/bcma.h                          |   2 +
 22 files changed, 1350 insertions(+), 105 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 drivers/misc/bcm47xx-nvram.c
 create mode 100644 drivers/misc/bcm47xx-sprom.c
 create mode 100644 include/linux/bcm47xx_nvram.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 0/7] bcma: add device tree support
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

This adds device tree support to bcma. In addition it also provides the 
sprom needed by bcma through a device tree driver.
This is needed for the Broadcom BCM47XX/BCM53XX ARM SoCs (NorthStar).

bcma drives the system AIX bus. This bus is scanable, so we 
automatically detect the cores attached to this bus. We only have to 
provide the address of the first core, this can now be done through 
device tree.
It is not possible to find out what IRQ is associated to a specific 
core, we have to provide this through device tree.

Broadcom uses a nvram which is a key value store on the flash chip. 
This nvram contains the mac addresses to be used by the wifi and 
Ethernet devices, the configuration data for the switch, the 
calibration data for the wifi cores and some more stuff. Currently bcma 
assumes to get some sprom when it gets initialized on a SoC. This sprom 
is a structure with all the data which are originally stored in the 
nvram. When bcma is used on a PCIe wifi card this data is fetched from 
some eeporm on the card. The nvram could contains more than one sprom, 
in case there is a main Baordocm SoC and a Broadcom wifi card connected 
via PCIe this PCIe cards mostly use the nvram to store the sprom with 
the calibration data.

This patch series adds two drivers, the nvram driver which reads the 
nvram and provides an interface to fetch values by giving a key and a 
driver which creates a sprom based on a given nvram. These two things 
are no real drivers, they are just converting stuff. I made them 
drivers so they can be replaced with some other drivers which are 
fetching the sprom from other storages. I know that the BCM63XX SoCs 
are also using an sprom, but there it is stored in a file on the file 
system. 

Some code was copied from the mips code at arch/mips/bcm47xx/ in the 
end I want to make this mips code also use these new drivers.

There is no device I know of which uses more than one nvram and I do 
not think there will ever be such a device. With this patch you have to 
provide a reference to the nvram you want to fetch data from which is a 
little bit annoying, should I remove this parameter and assume there is 
just one nvram driver in the system?

I am interested on comments if this architecture is correct or if there 
are some improvements I could do. I haven't fond similar code in the 
kernel.

Through which tree should I merge the final patches?

This is based on linus 3.17-rc1.

Log output:
bcma: bus0: Found chip with id 0xCF12, rev 0x00 and package 0x02
bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id 0x800, rev 0x2A, class 0x0)
bcma: bus0: Core 1 found: Chipcommon B (manuf 0x4BF, id 0x50B, rev 0x01, class 0x0)
bcma: bus0: Core 2 found: DMA (manuf 0x4BF, id 0x502, rev 0x01, class 0x0)
bcma: bus0: Core 3 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 4 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 5 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 6 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 7 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 8 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 9 found: ARM Cortex A9 core (ihost) (manuf 0x4BF, id 0x510, rev 0x01, class 0x0)
bcma: bus0: Core 10 found: USB 2.0 (manuf 0x4BF, id 0x504, rev 0x01, class 0x0)
bcma: bus0: Core 11 found: USB 3.0 (manuf 0x4BF, id 0x505, rev 0x01, class 0x0)
bcma: bus0: Core 12 found: SDIO3 (manuf 0x4BF, id 0x503, rev 0x01, class 0x0)
bcma: bus0: Core 13 found: ARM Cortex A9 JTAG (manuf 0x4BF, id 0x506, rev 0x01, class 0x0)
bcma: bus0: Core 14 found: Denali DDR2/DDR3 memory controller (manuf 0x4BF, id 0x507, rev 0x01, class 0x0)
bcma: bus0: Core 15 found: ROM (manuf 0x4BF, id 0x508, rev 0x01, class 0x0)
bcma: bus0: Core 16 found: NAND flash controller (manuf 0x4BF, id 0x509, rev 0x01, class 0x0)
bcma: bus0: Core 17 found: SPI flash controller (manuf 0x4BF, id 0x50A, rev 0x01, class 0x0)
bcma: bus0: Found sprom from device tree provider
bgmac bcma0:1: Found PHY addr: 30 (NOREGS)
bgmac bcma0:1: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed
b53_common: found switch: BCM53011, rev 2
bgmac bcma0:2: Found PHY addr: 0
bgmac bcma0:2: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed


Hauke Mehrtens (7):
  MIPS: BCM47XX: move the nvram header file into common space
  bcm47xx-nvram: add new broadcom nvram driver with dt support
  bcm47xx-sprom: add Broadcom sprom parser driver
  bcma: register bcma as device tree driver
  bcma: get IRQ numbers from dt
  bcma: get sprom from devicetree
  ARM: BCM5301X: register bcma bus

 Documentation/devicetree/bindings/bus/bcma.txt     |  46 ++
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 +
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 arch/arm/boot/dts/bcm4708.dtsi                     |  58 ++
 arch/mips/bcm47xx/board.c                          |  42 +-
 arch/mips/bcm47xx/nvram.c                          |   9 +-
 arch/mips/bcm47xx/setup.c                          |   6 +-
 arch/mips/bcm47xx/sprom.c                          |   6 +-
 arch/mips/bcm47xx/time.c                           |   4 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h |  53 --
 drivers/bcma/host_soc.c                            |  70 +++
 drivers/bcma/main.c                                |  42 +-
 drivers/bcma/sprom.c                               |  51 +-
 drivers/misc/Kconfig                               |  27 +
 drivers/misc/Makefile                              |   2 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |  10 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   7 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   9 +-
 include/linux/bcm47xx_nvram.h                      |  71 +++
 include/linux/bcma/bcma.h                          |   2 +
 22 files changed, 1350 insertions(+), 105 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 drivers/misc/bcm47xx-nvram.c
 create mode 100644 drivers/misc/bcm47xx-sprom.c
 create mode 100644 include/linux/bcm47xx_nvram.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 0/7] bcma: add device tree support
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

This adds device tree support to bcma. In addition it also provides the 
sprom needed by bcma through a device tree driver.
This is needed for the Broadcom BCM47XX/BCM53XX ARM SoCs (NorthStar).

bcma drives the system AIX bus. This bus is scanable, so we 
automatically detect the cores attached to this bus. We only have to 
provide the address of the first core, this can now be done through 
device tree.
It is not possible to find out what IRQ is associated to a specific 
core, we have to provide this through device tree.

Broadcom uses a nvram which is a key value store on the flash chip. 
This nvram contains the mac addresses to be used by the wifi and 
Ethernet devices, the configuration data for the switch, the 
calibration data for the wifi cores and some more stuff. Currently bcma 
assumes to get some sprom when it gets initialized on a SoC. This sprom 
is a structure with all the data which are originally stored in the 
nvram. When bcma is used on a PCIe wifi card this data is fetched from 
some eeporm on the card. The nvram could contains more than one sprom, 
in case there is a main Baordocm SoC and a Broadcom wifi card connected 
via PCIe this PCIe cards mostly use the nvram to store the sprom with 
the calibration data.

This patch series adds two drivers, the nvram driver which reads the 
nvram and provides an interface to fetch values by giving a key and a 
driver which creates a sprom based on a given nvram. These two things 
are no real drivers, they are just converting stuff. I made them 
drivers so they can be replaced with some other drivers which are 
fetching the sprom from other storages. I know that the BCM63XX SoCs 
are also using an sprom, but there it is stored in a file on the file 
system. 

Some code was copied from the mips code at arch/mips/bcm47xx/ in the 
end I want to make this mips code also use these new drivers.

There is no device I know of which uses more than one nvram and I do 
not think there will ever be such a device. With this patch you have to 
provide a reference to the nvram you want to fetch data from which is a 
little bit annoying, should I remove this parameter and assume there is 
just one nvram driver in the system?

I am interested on comments if this architecture is correct or if there 
are some improvements I could do. I haven't fond similar code in the 
kernel.

Through which tree should I merge the final patches?

This is based on linus 3.17-rc1.

Log output:
bcma: bus0: Found chip with id 0xCF12, rev 0x00 and package 0x02
bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id 0x800, rev 0x2A, class 0x0)
bcma: bus0: Core 1 found: Chipcommon B (manuf 0x4BF, id 0x50B, rev 0x01, class 0x0)
bcma: bus0: Core 2 found: DMA (manuf 0x4BF, id 0x502, rev 0x01, class 0x0)
bcma: bus0: Core 3 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 4 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 5 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 6 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 7 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 8 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 9 found: ARM Cortex A9 core (ihost) (manuf 0x4BF, id 0x510, rev 0x01, class 0x0)
bcma: bus0: Core 10 found: USB 2.0 (manuf 0x4BF, id 0x504, rev 0x01, class 0x0)
bcma: bus0: Core 11 found: USB 3.0 (manuf 0x4BF, id 0x505, rev 0x01, class 0x0)
bcma: bus0: Core 12 found: SDIO3 (manuf 0x4BF, id 0x503, rev 0x01, class 0x0)
bcma: bus0: Core 13 found: ARM Cortex A9 JTAG (manuf 0x4BF, id 0x506, rev 0x01, class 0x0)
bcma: bus0: Core 14 found: Denali DDR2/DDR3 memory controller (manuf 0x4BF, id 0x507, rev 0x01, class 0x0)
bcma: bus0: Core 15 found: ROM (manuf 0x4BF, id 0x508, rev 0x01, class 0x0)
bcma: bus0: Core 16 found: NAND flash controller (manuf 0x4BF, id 0x509, rev 0x01, class 0x0)
bcma: bus0: Core 17 found: SPI flash controller (manuf 0x4BF, id 0x50A, rev 0x01, class 0x0)
bcma: bus0: Found sprom from device tree provider
bgmac bcma0:1: Found PHY addr: 30 (NOREGS)
bgmac bcma0:1: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed
b53_common: found switch: BCM53011, rev 2
bgmac bcma0:2: Found PHY addr: 0
bgmac bcma0:2: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed


Hauke Mehrtens (7):
  MIPS: BCM47XX: move the nvram header file into common space
  bcm47xx-nvram: add new broadcom nvram driver with dt support
  bcm47xx-sprom: add Broadcom sprom parser driver
  bcma: register bcma as device tree driver
  bcma: get IRQ numbers from dt
  bcma: get sprom from devicetree
  ARM: BCM5301X: register bcma bus

 Documentation/devicetree/bindings/bus/bcma.txt     |  46 ++
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 +
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 arch/arm/boot/dts/bcm4708.dtsi                     |  58 ++
 arch/mips/bcm47xx/board.c                          |  42 +-
 arch/mips/bcm47xx/nvram.c                          |   9 +-
 arch/mips/bcm47xx/setup.c                          |   6 +-
 arch/mips/bcm47xx/sprom.c                          |   6 +-
 arch/mips/bcm47xx/time.c                           |   4 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h |  53 --
 drivers/bcma/host_soc.c                            |  70 +++
 drivers/bcma/main.c                                |  42 +-
 drivers/bcma/sprom.c                               |  51 +-
 drivers/misc/Kconfig                               |  27 +
 drivers/misc/Makefile                              |   2 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |  10 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   7 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   9 +-
 include/linux/bcm47xx_nvram.h                      |  71 +++
 include/linux/bcma/bcma.h                          |   2 +
 22 files changed, 1350 insertions(+), 105 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 drivers/misc/bcm47xx-nvram.c
 create mode 100644 drivers/misc/bcm47xx-sprom.c
 create mode 100644 include/linux/bcm47xx_nvram.h

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 0/7] bcma: add device tree support
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

This adds device tree support to bcma. In addition it also provides the 
sprom needed by bcma through a device tree driver.
This is needed for the Broadcom BCM47XX/BCM53XX ARM SoCs (NorthStar).

bcma drives the system AIX bus. This bus is scanable, so we 
automatically detect the cores attached to this bus. We only have to 
provide the address of the first core, this can now be done through 
device tree.
It is not possible to find out what IRQ is associated to a specific 
core, we have to provide this through device tree.

Broadcom uses a nvram which is a key value store on the flash chip. 
This nvram contains the mac addresses to be used by the wifi and 
Ethernet devices, the configuration data for the switch, the 
calibration data for the wifi cores and some more stuff. Currently bcma 
assumes to get some sprom when it gets initialized on a SoC. This sprom 
is a structure with all the data which are originally stored in the 
nvram. When bcma is used on a PCIe wifi card this data is fetched from 
some eeporm on the card. The nvram could contains more than one sprom, 
in case there is a main Baordocm SoC and a Broadcom wifi card connected 
via PCIe this PCIe cards mostly use the nvram to store the sprom with 
the calibration data.

This patch series adds two drivers, the nvram driver which reads the 
nvram and provides an interface to fetch values by giving a key and a 
driver which creates a sprom based on a given nvram. These two things 
are no real drivers, they are just converting stuff. I made them 
drivers so they can be replaced with some other drivers which are 
fetching the sprom from other storages. I know that the BCM63XX SoCs 
are also using an sprom, but there it is stored in a file on the file 
system. 

Some code was copied from the mips code at arch/mips/bcm47xx/ in the 
end I want to make this mips code also use these new drivers.

There is no device I know of which uses more than one nvram and I do 
not think there will ever be such a device. With this patch you have to 
provide a reference to the nvram you want to fetch data from which is a 
little bit annoying, should I remove this parameter and assume there is 
just one nvram driver in the system?

I am interested on comments if this architecture is correct or if there 
are some improvements I could do. I haven't fond similar code in the 
kernel.

Through which tree should I merge the final patches?

This is based on linus 3.17-rc1.

Log output:
bcma: bus0: Found chip with id 0xCF12, rev 0x00 and package 0x02
bcma: bus0: Core 0 found: ChipCommon (manuf 0x4BF, id 0x800, rev 0x2A, class 0x0)
bcma: bus0: Core 1 found: Chipcommon B (manuf 0x4BF, id 0x50B, rev 0x01, class 0x0)
bcma: bus0: Core 2 found: DMA (manuf 0x4BF, id 0x502, rev 0x01, class 0x0)
bcma: bus0: Core 3 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 4 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 5 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 6 found: GBit MAC (manuf 0x4BF, id 0x82D, rev 0x04, class 0x0)
bcma: bus0: Core 7 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 8 found: PCIe Gen 2 (manuf 0x4BF, id 0x501, rev 0x01, class 0x0)
bcma: bus0: Core 9 found: ARM Cortex A9 core (ihost) (manuf 0x4BF, id 0x510, rev 0x01, class 0x0)
bcma: bus0: Core 10 found: USB 2.0 (manuf 0x4BF, id 0x504, rev 0x01, class 0x0)
bcma: bus0: Core 11 found: USB 3.0 (manuf 0x4BF, id 0x505, rev 0x01, class 0x0)
bcma: bus0: Core 12 found: SDIO3 (manuf 0x4BF, id 0x503, rev 0x01, class 0x0)
bcma: bus0: Core 13 found: ARM Cortex A9 JTAG (manuf 0x4BF, id 0x506, rev 0x01, class 0x0)
bcma: bus0: Core 14 found: Denali DDR2/DDR3 memory controller (manuf 0x4BF, id 0x507, rev 0x01, class 0x0)
bcma: bus0: Core 15 found: ROM (manuf 0x4BF, id 0x508, rev 0x01, class 0x0)
bcma: bus0: Core 16 found: NAND flash controller (manuf 0x4BF, id 0x509, rev 0x01, class 0x0)
bcma: bus0: Core 17 found: SPI flash controller (manuf 0x4BF, id 0x50A, rev 0x01, class 0x0)
bcma: bus0: Found sprom from device tree provider
bgmac bcma0:1: Found PHY addr: 30 (NOREGS)
bgmac bcma0:1: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed
b53_common: found switch: BCM53011, rev 2
bgmac bcma0:2: Found PHY addr: 0
bgmac bcma0:2: Support for Roboswitch not implemented
libphy: bgmac mii bus: probed


Hauke Mehrtens (7):
  MIPS: BCM47XX: move the nvram header file into common space
  bcm47xx-nvram: add new broadcom nvram driver with dt support
  bcm47xx-sprom: add Broadcom sprom parser driver
  bcma: register bcma as device tree driver
  bcma: get IRQ numbers from dt
  bcma: get sprom from devicetree
  ARM: BCM5301X: register bcma bus

 Documentation/devicetree/bindings/bus/bcma.txt     |  46 ++
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 +
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 arch/arm/boot/dts/bcm4708.dtsi                     |  58 ++
 arch/mips/bcm47xx/board.c                          |  42 +-
 arch/mips/bcm47xx/nvram.c                          |   9 +-
 arch/mips/bcm47xx/setup.c                          |   6 +-
 arch/mips/bcm47xx/sprom.c                          |   6 +-
 arch/mips/bcm47xx/time.c                           |   4 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h |  53 --
 drivers/bcma/host_soc.c                            |  70 +++
 drivers/bcma/main.c                                |  42 +-
 drivers/bcma/sprom.c                               |  51 +-
 drivers/misc/Kconfig                               |  27 +
 drivers/misc/Makefile                              |   2 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |  10 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   7 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   9 +-
 include/linux/bcm47xx_nvram.h                      |  71 +++
 include/linux/bcma/bcma.h                          |   2 +
 22 files changed, 1350 insertions(+), 105 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 drivers/misc/bcm47xx-nvram.c
 create mode 100644 drivers/misc/bcm47xx-sprom.c
 create mode 100644 include/linux/bcm47xx_nvram.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 1/7] MIPS: BCM47XX: move the nvram header file into common space
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

Moving mach-bcm47xx/bcm47xx_nvram.h to include/linux/bcm47xx_nvram.h
makes it possible to reuse this header on the ARM based bcm47xx/bcm53xx
SoCs (e.g. BCM5301X devices). Broadcom uses ARM CPUs in their new SoC
form the bcm47xx and bcm53xx line, but many other things like nvram
stayed the same.

This is a preparation for adding a new nvram driver, which can be used
by the ARM SoC and the MIPS SoC code. The device drivers accessing
nvram do not have to care about ARM or MIPS SoC version.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/bcm47xx/board.c                          |  2 +-
 arch/mips/bcm47xx/nvram.c                          |  2 +-
 arch/mips/bcm47xx/setup.c                          |  2 +-
 arch/mips/bcm47xx/sprom.c                          |  2 +-
 arch/mips/bcm47xx/time.c                           |  2 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h | 53 -----------------
 drivers/net/ethernet/broadcom/b44.c                |  8 +--
 drivers/net/ethernet/broadcom/bgmac.c              |  2 +-
 drivers/ssb/driver_chipcommon_pmu.c                |  6 +-
 include/linux/bcm47xx_nvram.h                      | 66 ++++++++++++++++++++++
 10 files changed, 74 insertions(+), 71 deletions(-)
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 include/linux/bcm47xx_nvram.h

diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
index b3ae068..ec46fd7 100644
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -2,7 +2,7 @@
 #include <linux/export.h>
 #include <linux/string.h>
 #include <bcm47xx_board.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 
 struct bcm47xx_board_type {
 	const enum bcm47xx_board board;
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 2bed73a..c47a4a8 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <asm/addrspace.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <asm/mach-bcm47xx/bcm47xx.h>
 
 static char nvram_buf[NVRAM_SPACE];
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 2b63e7e..deadb71 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -42,7 +42,7 @@
 #include <asm/reboot.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <bcm47xx_board.h>
 
 union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
index 41226b6..29ced12 100644
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -27,7 +27,7 @@
  */
 
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <linux/if_ether.h>
 #include <linux/etherdevice.h>
 
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 2c85d92..c57a515 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -27,7 +27,7 @@
 #include <linux/ssb/ssb.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <bcm47xx_board.h>
 
 void __init plat_time_init(void)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
deleted file mode 100644
index 36a3fc1..0000000
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  Copyright (C) 2005, Broadcom Corporation
- *  Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#ifndef __BCM47XX_NVRAM_H
-#define __BCM47XX_NVRAM_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-struct nvram_header {
-	u32 magic;
-	u32 len;
-	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
-	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
-	u32 config_ncdl;	/* ncdl values for memc */
-};
-
-#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
-#define NVRAM_VERSION		1
-#define NVRAM_HEADER_SIZE	20
-#define NVRAM_SPACE		0x8000
-
-#define FLASH_MIN		0x00020000	/* Minimum flash size */
-
-#define NVRAM_MAX_VALUE_LEN 255
-#define NVRAM_MAX_PARAM_LEN 64
-
-extern int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len);
-
-static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
-{
-	if (strchr(buf, ':'))
-		sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
-			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
-			&macaddr[5]);
-	else if (strchr(buf, '-'))
-		sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
-			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
-			&macaddr[5]);
-	else
-		printk(KERN_WARNING "Can not parse mac address: %s\n", buf);
-}
-
-int bcm47xx_nvram_gpio_pin(const char *name);
-
-#endif /* __BCM47XX_NVRAM_H */
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 4a7028d..d2714a2 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -31,6 +31,7 @@
 #include <linux/ssb/ssb.h>
 #include <linux/slab.h>
 #include <linux/phy.h>
+#include <linux/bcm47xx_nvram.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -399,8 +400,6 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
 	__b44_set_flow_ctrl(bp, pause_enab);
 }
 
-#ifdef CONFIG_BCM47XX
-#include <bcm47xx_nvram.h>
 static void b44_wap54g10_workaround(struct b44 *bp)
 {
 	char buf[20];
@@ -429,11 +428,6 @@ static void b44_wap54g10_workaround(struct b44 *bp)
 error:
 	pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
 }
-#else
-static inline void b44_wap54g10_workaround(struct b44 *bp)
-{
-}
-#endif
 
 static int b44_setup_phy(struct b44 *bp)
 {
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 05c6af6..bdda57b 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -16,7 +16,7 @@
 #include <linux/phy.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 
 static const struct bcma_device_id bgmac_bcma_tbl[] = {
 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 1173a09..8d07d4d 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -13,9 +13,7 @@
 #include <linux/ssb/ssb_driver_chipcommon.h>
 #include <linux/delay.h>
 #include <linux/export.h>
-#ifdef CONFIG_BCM47XX
-#include <bcm47xx_nvram.h>
-#endif
+#include <linux/bcm47xx_nvram.h>
 
 #include "ssb_private.h"
 
@@ -320,11 +318,9 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
 	u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
 
 	if (bus->bustype == SSB_BUSTYPE_SSB) {
-#ifdef CONFIG_BCM47XX
 		char buf[20];
 		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
 			crystalfreq = simple_strtoul(buf, NULL, 0);
-#endif
 	}
 
 	switch (bus->chip_id) {
diff --git a/include/linux/bcm47xx_nvram.h b/include/linux/bcm47xx_nvram.h
new file mode 100644
index 0000000..333d32c
--- /dev/null
+++ b/include/linux/bcm47xx_nvram.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (C) 2005, Broadcom Corporation
+ *  Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
+ *  Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __BCM47XX_NVRAM_H
+#define __BCM47XX_NVRAM_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+struct nvram_header {
+	u32 magic;
+	u32 len;
+	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
+	u32 config_ncdl;	/* ncdl values for memc */
+};
+
+#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
+#define NVRAM_VERSION		1
+#define NVRAM_HEADER_SIZE	20
+#define NVRAM_SPACE		0x8000
+
+#define FLASH_MIN		0x00020000	/* Minimum flash size */
+
+#define NVRAM_MAX_VALUE_LEN 255
+#define NVRAM_MAX_PARAM_LEN 64
+
+#ifdef CONFIG_BCM47XX
+int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+
+int bcm47xx_nvram_gpio_pin(const char *name);
+#else
+static inline int bcm47xx_nvram_getenv(const char *name, char *val,
+				       size_t val_len)
+{
+	return -ENXIO;
+}
+
+static inline int bcm47xx_nvram_gpio_pin(const char *name)
+{
+	return -ENXIO;
+}
+#endif
+
+static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
+{
+	if (strchr(buf, ':'))
+		sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
+			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+			&macaddr[5]);
+	else if (strchr(buf, '-'))
+		sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
+			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+			&macaddr[5]);
+	else
+		pr_warn("Can not parse mac address: %s\n", buf);
+}
+#endif /* __BCM47XX_NVRAM_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 1/7] MIPS: BCM47XX: move the nvram header file into common space
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

Moving mach-bcm47xx/bcm47xx_nvram.h to include/linux/bcm47xx_nvram.h
makes it possible to reuse this header on the ARM based bcm47xx/bcm53xx
SoCs (e.g. BCM5301X devices). Broadcom uses ARM CPUs in their new SoC
form the bcm47xx and bcm53xx line, but many other things like nvram
stayed the same.

This is a preparation for adding a new nvram driver, which can be used
by the ARM SoC and the MIPS SoC code. The device drivers accessing
nvram do not have to care about ARM or MIPS SoC version.

Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
---
 arch/mips/bcm47xx/board.c                          |  2 +-
 arch/mips/bcm47xx/nvram.c                          |  2 +-
 arch/mips/bcm47xx/setup.c                          |  2 +-
 arch/mips/bcm47xx/sprom.c                          |  2 +-
 arch/mips/bcm47xx/time.c                           |  2 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h | 53 -----------------
 drivers/net/ethernet/broadcom/b44.c                |  8 +--
 drivers/net/ethernet/broadcom/bgmac.c              |  2 +-
 drivers/ssb/driver_chipcommon_pmu.c                |  6 +-
 include/linux/bcm47xx_nvram.h                      | 66 ++++++++++++++++++++++
 10 files changed, 74 insertions(+), 71 deletions(-)
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 include/linux/bcm47xx_nvram.h

diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
index b3ae068..ec46fd7 100644
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -2,7 +2,7 @@
 #include <linux/export.h>
 #include <linux/string.h>
 #include <bcm47xx_board.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 
 struct bcm47xx_board_type {
 	const enum bcm47xx_board board;
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 2bed73a..c47a4a8 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <asm/addrspace.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <asm/mach-bcm47xx/bcm47xx.h>
 
 static char nvram_buf[NVRAM_SPACE];
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 2b63e7e..deadb71 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -42,7 +42,7 @@
 #include <asm/reboot.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <bcm47xx_board.h>
 
 union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
index 41226b6..29ced12 100644
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -27,7 +27,7 @@
  */
 
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <linux/if_ether.h>
 #include <linux/etherdevice.h>
 
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 2c85d92..c57a515 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -27,7 +27,7 @@
 #include <linux/ssb/ssb.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <bcm47xx_board.h>
 
 void __init plat_time_init(void)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
deleted file mode 100644
index 36a3fc1..0000000
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  Copyright (C) 2005, Broadcom Corporation
- *  Copyright (C) 2006, Felix Fietkau <nbd-p3rKhJxN3npAfugRpC6u6w@public.gmane.org>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#ifndef __BCM47XX_NVRAM_H
-#define __BCM47XX_NVRAM_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-struct nvram_header {
-	u32 magic;
-	u32 len;
-	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
-	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
-	u32 config_ncdl;	/* ncdl values for memc */
-};
-
-#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
-#define NVRAM_VERSION		1
-#define NVRAM_HEADER_SIZE	20
-#define NVRAM_SPACE		0x8000
-
-#define FLASH_MIN		0x00020000	/* Minimum flash size */
-
-#define NVRAM_MAX_VALUE_LEN 255
-#define NVRAM_MAX_PARAM_LEN 64
-
-extern int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len);
-
-static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
-{
-	if (strchr(buf, ':'))
-		sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
-			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
-			&macaddr[5]);
-	else if (strchr(buf, '-'))
-		sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
-			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
-			&macaddr[5]);
-	else
-		printk(KERN_WARNING "Can not parse mac address: %s\n", buf);
-}
-
-int bcm47xx_nvram_gpio_pin(const char *name);
-
-#endif /* __BCM47XX_NVRAM_H */
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 4a7028d..d2714a2 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -31,6 +31,7 @@
 #include <linux/ssb/ssb.h>
 #include <linux/slab.h>
 #include <linux/phy.h>
+#include <linux/bcm47xx_nvram.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -399,8 +400,6 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
 	__b44_set_flow_ctrl(bp, pause_enab);
 }
 
-#ifdef CONFIG_BCM47XX
-#include <bcm47xx_nvram.h>
 static void b44_wap54g10_workaround(struct b44 *bp)
 {
 	char buf[20];
@@ -429,11 +428,6 @@ static void b44_wap54g10_workaround(struct b44 *bp)
 error:
 	pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
 }
-#else
-static inline void b44_wap54g10_workaround(struct b44 *bp)
-{
-}
-#endif
 
 static int b44_setup_phy(struct b44 *bp)
 {
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 05c6af6..bdda57b 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -16,7 +16,7 @@
 #include <linux/phy.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 
 static const struct bcma_device_id bgmac_bcma_tbl[] = {
 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 1173a09..8d07d4d 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -13,9 +13,7 @@
 #include <linux/ssb/ssb_driver_chipcommon.h>
 #include <linux/delay.h>
 #include <linux/export.h>
-#ifdef CONFIG_BCM47XX
-#include <bcm47xx_nvram.h>
-#endif
+#include <linux/bcm47xx_nvram.h>
 
 #include "ssb_private.h"
 
@@ -320,11 +318,9 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
 	u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
 
 	if (bus->bustype == SSB_BUSTYPE_SSB) {
-#ifdef CONFIG_BCM47XX
 		char buf[20];
 		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
 			crystalfreq = simple_strtoul(buf, NULL, 0);
-#endif
 	}
 
 	switch (bus->chip_id) {
diff --git a/include/linux/bcm47xx_nvram.h b/include/linux/bcm47xx_nvram.h
new file mode 100644
index 0000000..333d32c
--- /dev/null
+++ b/include/linux/bcm47xx_nvram.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (C) 2005, Broadcom Corporation
+ *  Copyright (C) 2006, Felix Fietkau <nbd-p3rKhJxN3npAfugRpC6u6w@public.gmane.org>
+ *  Copyright (C) 2014 Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __BCM47XX_NVRAM_H
+#define __BCM47XX_NVRAM_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+struct nvram_header {
+	u32 magic;
+	u32 len;
+	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
+	u32 config_ncdl;	/* ncdl values for memc */
+};
+
+#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
+#define NVRAM_VERSION		1
+#define NVRAM_HEADER_SIZE	20
+#define NVRAM_SPACE		0x8000
+
+#define FLASH_MIN		0x00020000	/* Minimum flash size */
+
+#define NVRAM_MAX_VALUE_LEN 255
+#define NVRAM_MAX_PARAM_LEN 64
+
+#ifdef CONFIG_BCM47XX
+int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+
+int bcm47xx_nvram_gpio_pin(const char *name);
+#else
+static inline int bcm47xx_nvram_getenv(const char *name, char *val,
+				       size_t val_len)
+{
+	return -ENXIO;
+}
+
+static inline int bcm47xx_nvram_gpio_pin(const char *name)
+{
+	return -ENXIO;
+}
+#endif
+
+static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
+{
+	if (strchr(buf, ':'))
+		sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
+			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+			&macaddr[5]);
+	else if (strchr(buf, '-'))
+		sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
+			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+			&macaddr[5]);
+	else
+		pr_warn("Can not parse mac address: %s\n", buf);
+}
+#endif /* __BCM47XX_NVRAM_H */
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 1/7] MIPS: BCM47XX: move the nvram header file into common space
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

Moving mach-bcm47xx/bcm47xx_nvram.h to include/linux/bcm47xx_nvram.h
makes it possible to reuse this header on the ARM based bcm47xx/bcm53xx
SoCs (e.g. BCM5301X devices). Broadcom uses ARM CPUs in their new SoC
form the bcm47xx and bcm53xx line, but many other things like nvram
stayed the same.

This is a preparation for adding a new nvram driver, which can be used
by the ARM SoC and the MIPS SoC code. The device drivers accessing
nvram do not have to care about ARM or MIPS SoC version.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/bcm47xx/board.c                          |  2 +-
 arch/mips/bcm47xx/nvram.c                          |  2 +-
 arch/mips/bcm47xx/setup.c                          |  2 +-
 arch/mips/bcm47xx/sprom.c                          |  2 +-
 arch/mips/bcm47xx/time.c                           |  2 +-
 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h | 53 -----------------
 drivers/net/ethernet/broadcom/b44.c                |  8 +--
 drivers/net/ethernet/broadcom/bgmac.c              |  2 +-
 drivers/ssb/driver_chipcommon_pmu.c                |  6 +-
 include/linux/bcm47xx_nvram.h                      | 66 ++++++++++++++++++++++
 10 files changed, 74 insertions(+), 71 deletions(-)
 delete mode 100644 arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
 create mode 100644 include/linux/bcm47xx_nvram.h

diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
index b3ae068..ec46fd7 100644
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -2,7 +2,7 @@
 #include <linux/export.h>
 #include <linux/string.h>
 #include <bcm47xx_board.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 
 struct bcm47xx_board_type {
 	const enum bcm47xx_board board;
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 2bed73a..c47a4a8 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <asm/addrspace.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <asm/mach-bcm47xx/bcm47xx.h>
 
 static char nvram_buf[NVRAM_SPACE];
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 2b63e7e..deadb71 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -42,7 +42,7 @@
 #include <asm/reboot.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <bcm47xx_board.h>
 
 union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
index 41226b6..29ced12 100644
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -27,7 +27,7 @@
  */
 
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <linux/if_ether.h>
 #include <linux/etherdevice.h>
 
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 2c85d92..c57a515 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -27,7 +27,7 @@
 #include <linux/ssb/ssb.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 #include <bcm47xx_board.h>
 
 void __init plat_time_init(void)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
deleted file mode 100644
index 36a3fc1..0000000
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  Copyright (C) 2005, Broadcom Corporation
- *  Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- */
-
-#ifndef __BCM47XX_NVRAM_H
-#define __BCM47XX_NVRAM_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-struct nvram_header {
-	u32 magic;
-	u32 len;
-	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
-	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
-	u32 config_ncdl;	/* ncdl values for memc */
-};
-
-#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
-#define NVRAM_VERSION		1
-#define NVRAM_HEADER_SIZE	20
-#define NVRAM_SPACE		0x8000
-
-#define FLASH_MIN		0x00020000	/* Minimum flash size */
-
-#define NVRAM_MAX_VALUE_LEN 255
-#define NVRAM_MAX_PARAM_LEN 64
-
-extern int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len);
-
-static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
-{
-	if (strchr(buf, ':'))
-		sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
-			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
-			&macaddr[5]);
-	else if (strchr(buf, '-'))
-		sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
-			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
-			&macaddr[5]);
-	else
-		printk(KERN_WARNING "Can not parse mac address: %s\n", buf);
-}
-
-int bcm47xx_nvram_gpio_pin(const char *name);
-
-#endif /* __BCM47XX_NVRAM_H */
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 4a7028d..d2714a2 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -31,6 +31,7 @@
 #include <linux/ssb/ssb.h>
 #include <linux/slab.h>
 #include <linux/phy.h>
+#include <linux/bcm47xx_nvram.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -399,8 +400,6 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
 	__b44_set_flow_ctrl(bp, pause_enab);
 }
 
-#ifdef CONFIG_BCM47XX
-#include <bcm47xx_nvram.h>
 static void b44_wap54g10_workaround(struct b44 *bp)
 {
 	char buf[20];
@@ -429,11 +428,6 @@ static void b44_wap54g10_workaround(struct b44 *bp)
 error:
 	pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
 }
-#else
-static inline void b44_wap54g10_workaround(struct b44 *bp)
-{
-}
-#endif
 
 static int b44_setup_phy(struct b44 *bp)
 {
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 05c6af6..bdda57b 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -16,7 +16,7 @@
 #include <linux/phy.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
-#include <bcm47xx_nvram.h>
+#include <linux/bcm47xx_nvram.h>
 
 static const struct bcma_device_id bgmac_bcma_tbl[] = {
 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 1173a09..8d07d4d 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -13,9 +13,7 @@
 #include <linux/ssb/ssb_driver_chipcommon.h>
 #include <linux/delay.h>
 #include <linux/export.h>
-#ifdef CONFIG_BCM47XX
-#include <bcm47xx_nvram.h>
-#endif
+#include <linux/bcm47xx_nvram.h>
 
 #include "ssb_private.h"
 
@@ -320,11 +318,9 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
 	u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
 
 	if (bus->bustype == SSB_BUSTYPE_SSB) {
-#ifdef CONFIG_BCM47XX
 		char buf[20];
 		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
 			crystalfreq = simple_strtoul(buf, NULL, 0);
-#endif
 	}
 
 	switch (bus->chip_id) {
diff --git a/include/linux/bcm47xx_nvram.h b/include/linux/bcm47xx_nvram.h
new file mode 100644
index 0000000..333d32c
--- /dev/null
+++ b/include/linux/bcm47xx_nvram.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (C) 2005, Broadcom Corporation
+ *  Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
+ *  Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __BCM47XX_NVRAM_H
+#define __BCM47XX_NVRAM_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+struct nvram_header {
+	u32 magic;
+	u32 len;
+	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
+	u32 config_ncdl;	/* ncdl values for memc */
+};
+
+#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
+#define NVRAM_VERSION		1
+#define NVRAM_HEADER_SIZE	20
+#define NVRAM_SPACE		0x8000
+
+#define FLASH_MIN		0x00020000	/* Minimum flash size */
+
+#define NVRAM_MAX_VALUE_LEN 255
+#define NVRAM_MAX_PARAM_LEN 64
+
+#ifdef CONFIG_BCM47XX
+int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+
+int bcm47xx_nvram_gpio_pin(const char *name);
+#else
+static inline int bcm47xx_nvram_getenv(const char *name, char *val,
+				       size_t val_len)
+{
+	return -ENXIO;
+}
+
+static inline int bcm47xx_nvram_gpio_pin(const char *name)
+{
+	return -ENXIO;
+}
+#endif
+
+static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
+{
+	if (strchr(buf, ':'))
+		sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
+			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+			&macaddr[5]);
+	else if (strchr(buf, '-'))
+		sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
+			&macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+			&macaddr[5]);
+	else
+		pr_warn("Can not parse mac address: %s\n", buf);
+}
+#endif /* __BCM47XX_NVRAM_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

This adds a new driver which searches at a given memory range for a
nvram like it is used on the bcm47xx and bcm53xx SoCs with ARM and MIPS
CPUs. This driver provides acces to this nvram to other device in the
device tree. You have to specify the memory ranges where the content of
the flash chip is memory mapped and this driver will search there for
some nvram and parse it. Other drivers can use this driver to access the
device nvram. The nvram is used to store board configurations like the
mac addresses, the switch configuration and the calibration data for
the wifi devices.

This was copied from arch/mips/bcm47xx/nvram.c and modified to interact
with device tree. My plan is to make the MIPS bcm47xx also use this new
driver some time later.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 ++
 arch/mips/bcm47xx/board.c                          |  40 ++--
 arch/mips/bcm47xx/nvram.c                          |   7 +-
 arch/mips/bcm47xx/setup.c                          |   4 +-
 arch/mips/bcm47xx/sprom.c                          |   4 +-
 arch/mips/bcm47xx/time.c                           |   2 +-
 drivers/misc/Kconfig                               |  13 ++
 drivers/misc/Makefile                              |   1 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |   2 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   5 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   3 +-
 include/linux/bcm47xx_nvram.h                      |  17 +-
 13 files changed, 294 insertions(+), 38 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 drivers/misc/bcm47xx-nvram.c

diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt b/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
new file mode 100644
index 0000000..ed979a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
@@ -0,0 +1,19 @@
+Broadcom bcm47xx/bcm53xx nvram access driver
+
+This driver provides access to the nvram for other drivers.
+
+Required properties:
+
+- compatible : brcm,bcm47xx-nvram
+
+- reg : iomem address range
+
+On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
+NOR flash is at 0x1e000000
+
+Example:
+
+nvram0: nvram@0 {
+	compatible = "brcm,bcm47xx-nvram";
+	reg = <0x1c000000 0x01000000>;
+};
diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
index ec46fd7..2c98f74 100644
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -218,36 +218,36 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 	const struct bcm47xx_board_type_list2 *e2;
 	const struct bcm47xx_board_type_list3 *e3;
 
-	if (bcm47xx_nvram_getenv("model_name", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "model_name", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_model_name; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("model_no", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "model_no", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_model_no; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("machine_name", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "machine_name", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_machine_name; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "hardware_version", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_hardware_version; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardtype", buf2, sizeof(buf2)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "hardware_version", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardtype", buf2, sizeof(buf2)) >= 0) {
 		for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) {
 			if (!strstarts(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -255,22 +255,22 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("productid", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "productid", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_productid; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("ModelId", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "ModelId", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_ModelId; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("melco_id", buf1, sizeof(buf1)) >= 0 ||
-	    bcm47xx_nvram_getenv("buf1falo_id", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "melco_id", buf1, sizeof(buf1)) >= 0 ||
+	    bcm47xx_nvram_getenv(NULL, "buf1falo_id", buf1, sizeof(buf1)) >= 0) {
 		/* buffalo hardware, check id for specific hardware matches */
 		for (e1 = bcm47xx_board_list_melco_id; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
@@ -278,8 +278,8 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
 		for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) {
 			if (!strcmp(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -287,16 +287,16 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("board_id", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "board_id", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_board_id; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardnum", buf2, sizeof(buf2)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardrev", buf3, sizeof(buf3)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "boardtype", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardnum", buf2, sizeof(buf2)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardrev", buf3, sizeof(buf3)) >= 0) {
 		for (e3 = bcm47xx_board_list_board; e3->value1; e3++) {
 			if (!strcmp(buf1, e3->value1) &&
 			    !strcmp(buf2, e3->value2) &&
@@ -305,9 +305,9 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardrev", buf2, sizeof(buf2)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardnum", buf3, sizeof(buf3)) ==  -ENOENT) {
+	if (bcm47xx_nvram_getenv(NULL, "boardtype", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardrev", buf2, sizeof(buf2)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardnum", buf3, sizeof(buf3)) ==  -ENOENT) {
 		for (e2 = bcm47xx_board_list_board_type_rev; e2->value1; e2++) {
 			if (!strcmp(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -327,7 +327,7 @@ void __init bcm47xx_board_detect(void)
 		return;
 
 	/* check if the nvram is available */
-	err = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
+	err = bcm47xx_nvram_getenv(NULL, "boardtype", buf, sizeof(buf));
 
 	/* init of nvram failed, probably too early now */
 	if (err == -ENXIO) {
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index c47a4a8..b2112c7 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -158,7 +158,8 @@ static int nvram_init(void)
 	return -ENXIO;
 }
 
-int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len)
 {
 	char *var, *value, *end, *eq;
 	int err;
@@ -190,7 +191,7 @@ int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
 }
 EXPORT_SYMBOL(bcm47xx_nvram_getenv);
 
-int bcm47xx_nvram_gpio_pin(const char *name)
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
 {
 	int i, err;
 	char nvram_var[10];
@@ -200,7 +201,7 @@ int bcm47xx_nvram_gpio_pin(const char *name)
 		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
 		if (err <= 0)
 			continue;
-		err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
+		err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
 		if (err <= 0)
 			continue;
 		if (!strcmp(name, buf))
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index deadb71..d87709d 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -123,7 +123,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
 	memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
 	bcm47xx_fill_sprom(&iv->sprom, NULL, false);
 
-	if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
+	if (bcm47xx_nvram_getenv(NULL, "cardbus", buf, sizeof(buf)) >= 0)
 		iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
 
 	return 0;
@@ -146,7 +146,7 @@ static void __init bcm47xx_register_ssb(void)
 		panic("Failed to initialize SSB bus (err %d)", err);
 
 	mcore = &bcm47xx_bus.ssb.mipscore;
-	if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "kernel_args", buf, sizeof(buf)) >= 0) {
 		if (strstr(buf, "console=ttyS1")) {
 			struct ssb_serial_port port;
 
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
index 29ced12..f88f49b 100644
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -52,10 +52,10 @@ static int get_nvram_var(const char *prefix, const char *postfix,
 
 	create_key(prefix, postfix, name, key, sizeof(key));
 
-	err = bcm47xx_nvram_getenv(key, buf, len);
+	err = bcm47xx_nvram_getenv(NULL, key, buf, len);
 	if (fallback && err == -ENOENT && prefix) {
 		create_key(NULL, postfix, name, key, sizeof(key));
-		err = bcm47xx_nvram_getenv(key, buf, len);
+		err = bcm47xx_nvram_getenv(NULL, key, buf, len);
 	}
 	return err;
 }
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index c57a515..b2c3c7d 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -61,7 +61,7 @@ void __init plat_time_init(void)
 	}
 
 	if (chip_id == 0x5354) {
-		len = bcm47xx_nvram_getenv("clkfreq", buf, sizeof(buf));
+		len = bcm47xx_nvram_getenv(NULL, "clkfreq", buf, sizeof(buf));
 		if (len >= 0 && !strncmp(buf, "200", 4))
 			hz = 100000000;
 	}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b841180..b306c02 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -515,6 +515,19 @@ config VEXPRESS_SYSCFG
 	  bus. System Configuration interface is one of the possible means
 	  of generating transactions on this bus.
 
+config BCM47XX_NVRAM
+	tristate "BCM47XX nvram driver"
+	depends on OF
+	help
+	  This driver parses the nvram from a given memory range and
+	  provides its values to other drivers.
+
+	  The nvram is a key value store used on bcm47xx/bcm53xx SoC 
+	  with ARM and MIPS CPUs. It contains the board specific 
+	  configuration.
+
+	  If unsure, say N.
+
 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 5497d02..2331208 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,4 @@ obj-y				+= mic/
 obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
+obj-$(CONFIG_BCM47XX_NVRAM)	+= bcm47xx-nvram.o
diff --git a/drivers/misc/bcm47xx-nvram.c b/drivers/misc/bcm47xx-nvram.c
new file mode 100644
index 0000000..6ea715c
--- /dev/null
+++ b/drivers/misc/bcm47xx-nvram.c
@@ -0,0 +1,215 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2014 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bcm47xx_nvram.h>
+
+struct bcm47xx_nvram {
+	size_t nvram_len;
+	char *nvram_buf;
+};
+
+static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
+
+static u32 find_nvram_size(void __iomem *end)
+{
+	struct nvram_header __iomem *header;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+		header = (struct nvram_header __iomem *)(end - nvram_sizes[i]);
+		if (__raw_readl(&header->magic) == NVRAM_HEADER)
+			return nvram_sizes[i];
+	}
+
+	return 0;
+}
+
+/* Probe for NVRAM header */
+static int nvram_find_and_copy(struct device *dev, void __iomem *base,
+			       size_t len, char **nvram_buf,
+			       size_t *nvram_len)
+{
+	struct nvram_header __iomem *header;
+	int i;
+	u32 off;
+	u32 *dst;
+	__le32 __iomem *src;
+	u32 size;
+
+	/* TODO: when nvram is on nand flash check for bad blocks first. */
+	off = FLASH_MIN;
+	while (off <= len) {
+		/* Windowed flash access */
+		size = find_nvram_size(base + off);
+		if (size) {
+			header = (struct nvram_header __iomem *)
+					(base + off - size);
+			goto found;
+		}
+		off += 0x10000;
+	}
+
+	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+	header = (struct nvram_header __iomem *)(base + 4096);
+	if (__raw_readl(&header->magic) == NVRAM_HEADER) {
+		size = NVRAM_SPACE;
+		goto found;
+	}
+
+	header = (struct nvram_header __iomem *)(base + 1024);
+	if (__raw_readl(&header->magic) == NVRAM_HEADER) {
+		size = NVRAM_SPACE;
+		goto found;
+	}
+
+	*nvram_buf = NULL;
+	*nvram_len = 0;
+	pr_err("no nvram found\n");
+	return -ENXIO;
+
+found:
+	if (readl(&header->len) > size)
+		pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
+	*nvram_len = min_t(u32, readl(&header->len), size);
+
+	*nvram_buf = devm_kzalloc(dev, *nvram_len, GFP_KERNEL);
+	if (!*nvram_buf)
+		return -ENOMEM;
+
+	src = (__le32 __iomem *) header;
+	dst = (u32 *) *nvram_buf;
+	for (i = 0; i < sizeof(struct nvram_header); i += 4)
+		*dst++ = __raw_readl(src++);
+	for (; i < *nvram_len; i += 4)
+		*dst++ = readl(src++);
+
+	return 0;
+}
+
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len)
+{
+	char *var, *value, *end, *eq;
+	struct bcm47xx_nvram *nvram;
+
+	if (!dev)
+		return -ENODEV;
+
+	nvram = dev_get_drvdata(dev);
+
+	if (!name || !nvram || !nvram->nvram_len)
+		return -EINVAL;
+
+	/* Look for name=value and return value */
+	var = nvram->nvram_buf + sizeof(struct nvram_header);
+	end = nvram->nvram_buf + nvram->nvram_len - 2;
+	end[0] = end[1] = '\0';
+	for (; *var; var = value + strlen(value) + 1) {
+		eq = strchr(var, '=');
+		if (!eq)
+			break;
+		value = eq + 1;
+		if ((eq - var) == strlen(name) &&
+			strncmp(var, name, (eq - var)) == 0) {
+			return snprintf(val, val_len, "%s", value);
+		}
+	}
+	return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_getenv);
+
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
+{
+	int i, err;
+	char nvram_var[10];
+	char buf[30];
+
+	if (!dev)
+		return -ENODEV;
+
+	for (i = 0; i < 32; i++) {
+		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
+		if (err <= 0)
+			continue;
+		err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
+		if (err <= 0)
+			continue;
+		if (!strcmp(name, buf))
+			return i;
+	}
+	return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
+
+static int bcm47xx_nvram_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct bcm47xx_nvram *nvram;
+	int err;
+	struct resource flash_mem;
+	void __iomem *mmio;
+
+	/* Alloc */
+	nvram = devm_kzalloc(dev, sizeof(*nvram), GFP_KERNEL);
+	if (!nvram)
+		return -ENOMEM;
+
+	err = of_address_to_resource(np, 0, &flash_mem);
+	if (err)
+		return err;
+
+	mmio = ioremap_nocache(flash_mem.start, resource_size(&flash_mem));
+	if (!mmio)
+		return -ENOMEM;
+
+	err = nvram_find_and_copy(dev, mmio, resource_size(&flash_mem),
+				  &nvram->nvram_buf, &nvram->nvram_len);
+	if (err)
+		goto err_unmap_mmio;
+
+	platform_set_drvdata(pdev, nvram);
+
+err_unmap_mmio:
+	iounmap(mmio);
+	return err;
+}
+
+static const struct of_device_id bcm47xx_nvram_of_match_table[] = {
+	{ .compatible = "brcm,bcm47xx-nvram", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver bcm47xx_nvram_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "bcm47xx-nvram",
+		.of_match_table = bcm47xx_nvram_of_match_table,
+		/* driver unloading/unbinding currently not supported */
+		.suppress_bind_attrs = true,
+	},
+	.probe = bcm47xx_nvram_probe,
+};
+module_platform_driver(bcm47xx_nvram_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index d2714a2..8340498 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -411,7 +411,7 @@ static void b44_wap54g10_workaround(struct b44 *bp)
 	 * see https://dev.openwrt.org/ticket/146
 	 * check and reset bit "isolate"
 	 */
-	if (bcm47xx_nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
+	if (bcm47xx_nvram_getenv(NULL, "boardnum", buf, sizeof(buf)) < 0)
 		return;
 	if (simple_strtoul(buf, NULL, 0) == 2) {
 		err = __b44_readphy(bp, 0, MII_BMCR, &val);
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index bdda57b..1df7fb0 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -952,7 +952,8 @@ static void bgmac_chip_reset(struct bgmac *bgmac)
 			     BGMAC_CHIPCTL_1_IF_TYPE_MII;
 		char buf[4];
 
-		if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
+		if (bcm47xx_nvram_getenv(NULL, "et_swtype", buf,
+					 sizeof(buf)) > 0) {
 			if (kstrtou8(buf, 0, &et_swtype))
 				bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
 					  buf);
@@ -1501,7 +1502,7 @@ static int bgmac_probe(struct bcma_device *core)
 	}
 
 	bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
-	if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
+	if (bcm47xx_nvram_getenv(NULL, "et0_no_txint", NULL, 0) == 0)
 		bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
 
 	/* TODO: reset the external phy. Specs are needed */
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 8d07d4d..b611ea1 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -319,7 +319,8 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
 
 	if (bus->bustype == SSB_BUSTYPE_SSB) {
 		char buf[20];
-		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
+		if (bcm47xx_nvram_getenv(NULL, "xtalfreq", buf,
+					 sizeof(buf)) >= 0)
 			crystalfreq = simple_strtoul(buf, NULL, 0);
 	}
 
diff --git a/include/linux/bcm47xx_nvram.h b/include/linux/bcm47xx_nvram.h
index 333d32c..515fc06 100644
--- a/include/linux/bcm47xx_nvram.h
+++ b/include/linux/bcm47xx_nvram.h
@@ -15,9 +15,11 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 
+struct device;
+
 struct nvram_header {
 	u32 magic;
-	u32 len;
+	__le32 len;
 	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
 	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
 	u32 config_ncdl;	/* ncdl values for memc */
@@ -33,18 +35,21 @@ struct nvram_header {
 #define NVRAM_MAX_VALUE_LEN 255
 #define NVRAM_MAX_PARAM_LEN 64
 
-#ifdef CONFIG_BCM47XX
-int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+#if defined(CONFIG_BCM47XX) || defined(CONFIG_BCM47XX_NVRAM)
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len);
 
-int bcm47xx_nvram_gpio_pin(const char *name);
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name);
 #else
-static inline int bcm47xx_nvram_getenv(const char *name, char *val,
+static inline int bcm47xx_nvram_getenv(const struct device *dev,
+				       const char *name, char *val,
 				       size_t val_len)
 {
 	return -ENXIO;
 }
 
-static inline int bcm47xx_nvram_gpio_pin(const char *name)
+static inline int bcm47xx_nvram_gpio_pin(const struct device *dev,
+					 const char *name)
 {
 	return -ENXIO;
 }
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

This adds a new driver which searches at a given memory range for a
nvram like it is used on the bcm47xx and bcm53xx SoCs with ARM and MIPS
CPUs. This driver provides acces to this nvram to other device in the
device tree. You have to specify the memory ranges where the content of
the flash chip is memory mapped and this driver will search there for
some nvram and parse it. Other drivers can use this driver to access the
device nvram. The nvram is used to store board configurations like the
mac addresses, the switch configuration and the calibration data for
the wifi devices.

This was copied from arch/mips/bcm47xx/nvram.c and modified to interact
with device tree. My plan is to make the MIPS bcm47xx also use this new
driver some time later.

Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
---
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 ++
 arch/mips/bcm47xx/board.c                          |  40 ++--
 arch/mips/bcm47xx/nvram.c                          |   7 +-
 arch/mips/bcm47xx/setup.c                          |   4 +-
 arch/mips/bcm47xx/sprom.c                          |   4 +-
 arch/mips/bcm47xx/time.c                           |   2 +-
 drivers/misc/Kconfig                               |  13 ++
 drivers/misc/Makefile                              |   1 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |   2 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   5 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   3 +-
 include/linux/bcm47xx_nvram.h                      |  17 +-
 13 files changed, 294 insertions(+), 38 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 drivers/misc/bcm47xx-nvram.c

diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt b/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
new file mode 100644
index 0000000..ed979a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
@@ -0,0 +1,19 @@
+Broadcom bcm47xx/bcm53xx nvram access driver
+
+This driver provides access to the nvram for other drivers.
+
+Required properties:
+
+- compatible : brcm,bcm47xx-nvram
+
+- reg : iomem address range
+
+On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
+NOR flash is at 0x1e000000
+
+Example:
+
+nvram0: nvram@0 {
+	compatible = "brcm,bcm47xx-nvram";
+	reg = <0x1c000000 0x01000000>;
+};
diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
index ec46fd7..2c98f74 100644
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -218,36 +218,36 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 	const struct bcm47xx_board_type_list2 *e2;
 	const struct bcm47xx_board_type_list3 *e3;
 
-	if (bcm47xx_nvram_getenv("model_name", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "model_name", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_model_name; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("model_no", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "model_no", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_model_no; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("machine_name", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "machine_name", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_machine_name; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "hardware_version", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_hardware_version; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardtype", buf2, sizeof(buf2)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "hardware_version", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardtype", buf2, sizeof(buf2)) >= 0) {
 		for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) {
 			if (!strstarts(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -255,22 +255,22 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("productid", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "productid", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_productid; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("ModelId", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "ModelId", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_ModelId; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("melco_id", buf1, sizeof(buf1)) >= 0 ||
-	    bcm47xx_nvram_getenv("buf1falo_id", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "melco_id", buf1, sizeof(buf1)) >= 0 ||
+	    bcm47xx_nvram_getenv(NULL, "buf1falo_id", buf1, sizeof(buf1)) >= 0) {
 		/* buffalo hardware, check id for specific hardware matches */
 		for (e1 = bcm47xx_board_list_melco_id; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
@@ -278,8 +278,8 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
 		for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) {
 			if (!strcmp(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -287,16 +287,16 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("board_id", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "board_id", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_board_id; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardnum", buf2, sizeof(buf2)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardrev", buf3, sizeof(buf3)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "boardtype", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardnum", buf2, sizeof(buf2)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardrev", buf3, sizeof(buf3)) >= 0) {
 		for (e3 = bcm47xx_board_list_board; e3->value1; e3++) {
 			if (!strcmp(buf1, e3->value1) &&
 			    !strcmp(buf2, e3->value2) &&
@@ -305,9 +305,9 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardrev", buf2, sizeof(buf2)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardnum", buf3, sizeof(buf3)) ==  -ENOENT) {
+	if (bcm47xx_nvram_getenv(NULL, "boardtype", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardrev", buf2, sizeof(buf2)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardnum", buf3, sizeof(buf3)) ==  -ENOENT) {
 		for (e2 = bcm47xx_board_list_board_type_rev; e2->value1; e2++) {
 			if (!strcmp(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -327,7 +327,7 @@ void __init bcm47xx_board_detect(void)
 		return;
 
 	/* check if the nvram is available */
-	err = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
+	err = bcm47xx_nvram_getenv(NULL, "boardtype", buf, sizeof(buf));
 
 	/* init of nvram failed, probably too early now */
 	if (err == -ENXIO) {
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index c47a4a8..b2112c7 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -158,7 +158,8 @@ static int nvram_init(void)
 	return -ENXIO;
 }
 
-int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len)
 {
 	char *var, *value, *end, *eq;
 	int err;
@@ -190,7 +191,7 @@ int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
 }
 EXPORT_SYMBOL(bcm47xx_nvram_getenv);
 
-int bcm47xx_nvram_gpio_pin(const char *name)
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
 {
 	int i, err;
 	char nvram_var[10];
@@ -200,7 +201,7 @@ int bcm47xx_nvram_gpio_pin(const char *name)
 		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
 		if (err <= 0)
 			continue;
-		err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
+		err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
 		if (err <= 0)
 			continue;
 		if (!strcmp(name, buf))
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index deadb71..d87709d 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -123,7 +123,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
 	memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
 	bcm47xx_fill_sprom(&iv->sprom, NULL, false);
 
-	if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
+	if (bcm47xx_nvram_getenv(NULL, "cardbus", buf, sizeof(buf)) >= 0)
 		iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
 
 	return 0;
@@ -146,7 +146,7 @@ static void __init bcm47xx_register_ssb(void)
 		panic("Failed to initialize SSB bus (err %d)", err);
 
 	mcore = &bcm47xx_bus.ssb.mipscore;
-	if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "kernel_args", buf, sizeof(buf)) >= 0) {
 		if (strstr(buf, "console=ttyS1")) {
 			struct ssb_serial_port port;
 
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
index 29ced12..f88f49b 100644
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -52,10 +52,10 @@ static int get_nvram_var(const char *prefix, const char *postfix,
 
 	create_key(prefix, postfix, name, key, sizeof(key));
 
-	err = bcm47xx_nvram_getenv(key, buf, len);
+	err = bcm47xx_nvram_getenv(NULL, key, buf, len);
 	if (fallback && err == -ENOENT && prefix) {
 		create_key(NULL, postfix, name, key, sizeof(key));
-		err = bcm47xx_nvram_getenv(key, buf, len);
+		err = bcm47xx_nvram_getenv(NULL, key, buf, len);
 	}
 	return err;
 }
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index c57a515..b2c3c7d 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -61,7 +61,7 @@ void __init plat_time_init(void)
 	}
 
 	if (chip_id == 0x5354) {
-		len = bcm47xx_nvram_getenv("clkfreq", buf, sizeof(buf));
+		len = bcm47xx_nvram_getenv(NULL, "clkfreq", buf, sizeof(buf));
 		if (len >= 0 && !strncmp(buf, "200", 4))
 			hz = 100000000;
 	}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b841180..b306c02 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -515,6 +515,19 @@ config VEXPRESS_SYSCFG
 	  bus. System Configuration interface is one of the possible means
 	  of generating transactions on this bus.
 
+config BCM47XX_NVRAM
+	tristate "BCM47XX nvram driver"
+	depends on OF
+	help
+	  This driver parses the nvram from a given memory range and
+	  provides its values to other drivers.
+
+	  The nvram is a key value store used on bcm47xx/bcm53xx SoC 
+	  with ARM and MIPS CPUs. It contains the board specific 
+	  configuration.
+
+	  If unsure, say N.
+
 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 5497d02..2331208 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,4 @@ obj-y				+= mic/
 obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
+obj-$(CONFIG_BCM47XX_NVRAM)	+= bcm47xx-nvram.o
diff --git a/drivers/misc/bcm47xx-nvram.c b/drivers/misc/bcm47xx-nvram.c
new file mode 100644
index 0000000..6ea715c
--- /dev/null
+++ b/drivers/misc/bcm47xx-nvram.c
@@ -0,0 +1,215 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2006 Felix Fietkau <nbd-p3rKhJxN3npAfugRpC6u6w@public.gmane.org>
+ * Copyright (C) 2010-2014 Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bcm47xx_nvram.h>
+
+struct bcm47xx_nvram {
+	size_t nvram_len;
+	char *nvram_buf;
+};
+
+static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
+
+static u32 find_nvram_size(void __iomem *end)
+{
+	struct nvram_header __iomem *header;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+		header = (struct nvram_header __iomem *)(end - nvram_sizes[i]);
+		if (__raw_readl(&header->magic) == NVRAM_HEADER)
+			return nvram_sizes[i];
+	}
+
+	return 0;
+}
+
+/* Probe for NVRAM header */
+static int nvram_find_and_copy(struct device *dev, void __iomem *base,
+			       size_t len, char **nvram_buf,
+			       size_t *nvram_len)
+{
+	struct nvram_header __iomem *header;
+	int i;
+	u32 off;
+	u32 *dst;
+	__le32 __iomem *src;
+	u32 size;
+
+	/* TODO: when nvram is on nand flash check for bad blocks first. */
+	off = FLASH_MIN;
+	while (off <= len) {
+		/* Windowed flash access */
+		size = find_nvram_size(base + off);
+		if (size) {
+			header = (struct nvram_header __iomem *)
+					(base + off - size);
+			goto found;
+		}
+		off += 0x10000;
+	}
+
+	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+	header = (struct nvram_header __iomem *)(base + 4096);
+	if (__raw_readl(&header->magic) == NVRAM_HEADER) {
+		size = NVRAM_SPACE;
+		goto found;
+	}
+
+	header = (struct nvram_header __iomem *)(base + 1024);
+	if (__raw_readl(&header->magic) == NVRAM_HEADER) {
+		size = NVRAM_SPACE;
+		goto found;
+	}
+
+	*nvram_buf = NULL;
+	*nvram_len = 0;
+	pr_err("no nvram found\n");
+	return -ENXIO;
+
+found:
+	if (readl(&header->len) > size)
+		pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
+	*nvram_len = min_t(u32, readl(&header->len), size);
+
+	*nvram_buf = devm_kzalloc(dev, *nvram_len, GFP_KERNEL);
+	if (!*nvram_buf)
+		return -ENOMEM;
+
+	src = (__le32 __iomem *) header;
+	dst = (u32 *) *nvram_buf;
+	for (i = 0; i < sizeof(struct nvram_header); i += 4)
+		*dst++ = __raw_readl(src++);
+	for (; i < *nvram_len; i += 4)
+		*dst++ = readl(src++);
+
+	return 0;
+}
+
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len)
+{
+	char *var, *value, *end, *eq;
+	struct bcm47xx_nvram *nvram;
+
+	if (!dev)
+		return -ENODEV;
+
+	nvram = dev_get_drvdata(dev);
+
+	if (!name || !nvram || !nvram->nvram_len)
+		return -EINVAL;
+
+	/* Look for name=value and return value */
+	var = nvram->nvram_buf + sizeof(struct nvram_header);
+	end = nvram->nvram_buf + nvram->nvram_len - 2;
+	end[0] = end[1] = '\0';
+	for (; *var; var = value + strlen(value) + 1) {
+		eq = strchr(var, '=');
+		if (!eq)
+			break;
+		value = eq + 1;
+		if ((eq - var) == strlen(name) &&
+			strncmp(var, name, (eq - var)) == 0) {
+			return snprintf(val, val_len, "%s", value);
+		}
+	}
+	return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_getenv);
+
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
+{
+	int i, err;
+	char nvram_var[10];
+	char buf[30];
+
+	if (!dev)
+		return -ENODEV;
+
+	for (i = 0; i < 32; i++) {
+		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
+		if (err <= 0)
+			continue;
+		err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
+		if (err <= 0)
+			continue;
+		if (!strcmp(name, buf))
+			return i;
+	}
+	return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
+
+static int bcm47xx_nvram_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct bcm47xx_nvram *nvram;
+	int err;
+	struct resource flash_mem;
+	void __iomem *mmio;
+
+	/* Alloc */
+	nvram = devm_kzalloc(dev, sizeof(*nvram), GFP_KERNEL);
+	if (!nvram)
+		return -ENOMEM;
+
+	err = of_address_to_resource(np, 0, &flash_mem);
+	if (err)
+		return err;
+
+	mmio = ioremap_nocache(flash_mem.start, resource_size(&flash_mem));
+	if (!mmio)
+		return -ENOMEM;
+
+	err = nvram_find_and_copy(dev, mmio, resource_size(&flash_mem),
+				  &nvram->nvram_buf, &nvram->nvram_len);
+	if (err)
+		goto err_unmap_mmio;
+
+	platform_set_drvdata(pdev, nvram);
+
+err_unmap_mmio:
+	iounmap(mmio);
+	return err;
+}
+
+static const struct of_device_id bcm47xx_nvram_of_match_table[] = {
+	{ .compatible = "brcm,bcm47xx-nvram", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver bcm47xx_nvram_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "bcm47xx-nvram",
+		.of_match_table = bcm47xx_nvram_of_match_table,
+		/* driver unloading/unbinding currently not supported */
+		.suppress_bind_attrs = true,
+	},
+	.probe = bcm47xx_nvram_probe,
+};
+module_platform_driver(bcm47xx_nvram_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index d2714a2..8340498 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -411,7 +411,7 @@ static void b44_wap54g10_workaround(struct b44 *bp)
 	 * see https://dev.openwrt.org/ticket/146
 	 * check and reset bit "isolate"
 	 */
-	if (bcm47xx_nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
+	if (bcm47xx_nvram_getenv(NULL, "boardnum", buf, sizeof(buf)) < 0)
 		return;
 	if (simple_strtoul(buf, NULL, 0) == 2) {
 		err = __b44_readphy(bp, 0, MII_BMCR, &val);
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index bdda57b..1df7fb0 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -952,7 +952,8 @@ static void bgmac_chip_reset(struct bgmac *bgmac)
 			     BGMAC_CHIPCTL_1_IF_TYPE_MII;
 		char buf[4];
 
-		if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
+		if (bcm47xx_nvram_getenv(NULL, "et_swtype", buf,
+					 sizeof(buf)) > 0) {
 			if (kstrtou8(buf, 0, &et_swtype))
 				bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
 					  buf);
@@ -1501,7 +1502,7 @@ static int bgmac_probe(struct bcma_device *core)
 	}
 
 	bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
-	if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
+	if (bcm47xx_nvram_getenv(NULL, "et0_no_txint", NULL, 0) == 0)
 		bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
 
 	/* TODO: reset the external phy. Specs are needed */
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 8d07d4d..b611ea1 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -319,7 +319,8 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
 
 	if (bus->bustype == SSB_BUSTYPE_SSB) {
 		char buf[20];
-		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
+		if (bcm47xx_nvram_getenv(NULL, "xtalfreq", buf,
+					 sizeof(buf)) >= 0)
 			crystalfreq = simple_strtoul(buf, NULL, 0);
 	}
 
diff --git a/include/linux/bcm47xx_nvram.h b/include/linux/bcm47xx_nvram.h
index 333d32c..515fc06 100644
--- a/include/linux/bcm47xx_nvram.h
+++ b/include/linux/bcm47xx_nvram.h
@@ -15,9 +15,11 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 
+struct device;
+
 struct nvram_header {
 	u32 magic;
-	u32 len;
+	__le32 len;
 	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
 	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
 	u32 config_ncdl;	/* ncdl values for memc */
@@ -33,18 +35,21 @@ struct nvram_header {
 #define NVRAM_MAX_VALUE_LEN 255
 #define NVRAM_MAX_PARAM_LEN 64
 
-#ifdef CONFIG_BCM47XX
-int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+#if defined(CONFIG_BCM47XX) || defined(CONFIG_BCM47XX_NVRAM)
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len);
 
-int bcm47xx_nvram_gpio_pin(const char *name);
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name);
 #else
-static inline int bcm47xx_nvram_getenv(const char *name, char *val,
+static inline int bcm47xx_nvram_getenv(const struct device *dev,
+				       const char *name, char *val,
 				       size_t val_len)
 {
 	return -ENXIO;
 }
 
-static inline int bcm47xx_nvram_gpio_pin(const char *name)
+static inline int bcm47xx_nvram_gpio_pin(const struct device *dev,
+					 const char *name)
 {
 	return -ENXIO;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a new driver which searches at a given memory range for a
nvram like it is used on the bcm47xx and bcm53xx SoCs with ARM and MIPS
CPUs. This driver provides acces to this nvram to other device in the
device tree. You have to specify the memory ranges where the content of
the flash chip is memory mapped and this driver will search there for
some nvram and parse it. Other drivers can use this driver to access the
device nvram. The nvram is used to store board configurations like the
mac addresses, the switch configuration and the calibration data for
the wifi devices.

This was copied from arch/mips/bcm47xx/nvram.c and modified to interact
with device tree. My plan is to make the MIPS bcm47xx also use this new
driver some time later.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 .../devicetree/bindings/misc/bcm47xx-nvram.txt     |  19 ++
 arch/mips/bcm47xx/board.c                          |  40 ++--
 arch/mips/bcm47xx/nvram.c                          |   7 +-
 arch/mips/bcm47xx/setup.c                          |   4 +-
 arch/mips/bcm47xx/sprom.c                          |   4 +-
 arch/mips/bcm47xx/time.c                           |   2 +-
 drivers/misc/Kconfig                               |  13 ++
 drivers/misc/Makefile                              |   1 +
 drivers/misc/bcm47xx-nvram.c                       | 215 +++++++++++++++++++++
 drivers/net/ethernet/broadcom/b44.c                |   2 +-
 drivers/net/ethernet/broadcom/bgmac.c              |   5 +-
 drivers/ssb/driver_chipcommon_pmu.c                |   3 +-
 include/linux/bcm47xx_nvram.h                      |  17 +-
 13 files changed, 294 insertions(+), 38 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
 create mode 100644 drivers/misc/bcm47xx-nvram.c

diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt b/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
new file mode 100644
index 0000000..ed979a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bcm47xx-nvram.txt
@@ -0,0 +1,19 @@
+Broadcom bcm47xx/bcm53xx nvram access driver
+
+This driver provides access to the nvram for other drivers.
+
+Required properties:
+
+- compatible : brcm,bcm47xx-nvram
+
+- reg : iomem address range
+
+On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
+NOR flash is at 0x1e000000
+
+Example:
+
+nvram0: nvram at 0 {
+	compatible = "brcm,bcm47xx-nvram";
+	reg = <0x1c000000 0x01000000>;
+};
diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
index ec46fd7..2c98f74 100644
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -218,36 +218,36 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 	const struct bcm47xx_board_type_list2 *e2;
 	const struct bcm47xx_board_type_list3 *e3;
 
-	if (bcm47xx_nvram_getenv("model_name", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "model_name", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_model_name; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("model_no", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "model_no", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_model_no; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("machine_name", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "machine_name", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_machine_name; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "hardware_version", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_hardware_version; e1->value1; e1++) {
 			if (strstarts(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("hardware_version", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardtype", buf2, sizeof(buf2)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "hardware_version", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardtype", buf2, sizeof(buf2)) >= 0) {
 		for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) {
 			if (!strstarts(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -255,22 +255,22 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("productid", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "productid", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_productid; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("ModelId", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "ModelId", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_ModelId; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("melco_id", buf1, sizeof(buf1)) >= 0 ||
-	    bcm47xx_nvram_getenv("buf1falo_id", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "melco_id", buf1, sizeof(buf1)) >= 0 ||
+	    bcm47xx_nvram_getenv(NULL, "buf1falo_id", buf1, sizeof(buf1)) >= 0) {
 		/* buffalo hardware, check id for specific hardware matches */
 		for (e1 = bcm47xx_board_list_melco_id; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
@@ -278,8 +278,8 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "boot_hw_model", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boot_hw_ver", buf2, sizeof(buf2)) >= 0) {
 		for (e2 = bcm47xx_board_list_boot_hw; e2->value1; e2++) {
 			if (!strcmp(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -287,16 +287,16 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("board_id", buf1, sizeof(buf1)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "board_id", buf1, sizeof(buf1)) >= 0) {
 		for (e1 = bcm47xx_board_list_board_id; e1->value1; e1++) {
 			if (!strcmp(buf1, e1->value1))
 				return &e1->board;
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardnum", buf2, sizeof(buf2)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardrev", buf3, sizeof(buf3)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "boardtype", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardnum", buf2, sizeof(buf2)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardrev", buf3, sizeof(buf3)) >= 0) {
 		for (e3 = bcm47xx_board_list_board; e3->value1; e3++) {
 			if (!strcmp(buf1, e3->value1) &&
 			    !strcmp(buf2, e3->value2) &&
@@ -305,9 +305,9 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
 		}
 	}
 
-	if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardrev", buf2, sizeof(buf2)) >= 0 &&
-	    bcm47xx_nvram_getenv("boardnum", buf3, sizeof(buf3)) ==  -ENOENT) {
+	if (bcm47xx_nvram_getenv(NULL, "boardtype", buf1, sizeof(buf1)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardrev", buf2, sizeof(buf2)) >= 0 &&
+	    bcm47xx_nvram_getenv(NULL, "boardnum", buf3, sizeof(buf3)) ==  -ENOENT) {
 		for (e2 = bcm47xx_board_list_board_type_rev; e2->value1; e2++) {
 			if (!strcmp(buf1, e2->value1) &&
 			    !strcmp(buf2, e2->value2))
@@ -327,7 +327,7 @@ void __init bcm47xx_board_detect(void)
 		return;
 
 	/* check if the nvram is available */
-	err = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
+	err = bcm47xx_nvram_getenv(NULL, "boardtype", buf, sizeof(buf));
 
 	/* init of nvram failed, probably too early now */
 	if (err == -ENXIO) {
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index c47a4a8..b2112c7 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -158,7 +158,8 @@ static int nvram_init(void)
 	return -ENXIO;
 }
 
-int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len)
 {
 	char *var, *value, *end, *eq;
 	int err;
@@ -190,7 +191,7 @@ int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len)
 }
 EXPORT_SYMBOL(bcm47xx_nvram_getenv);
 
-int bcm47xx_nvram_gpio_pin(const char *name)
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
 {
 	int i, err;
 	char nvram_var[10];
@@ -200,7 +201,7 @@ int bcm47xx_nvram_gpio_pin(const char *name)
 		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
 		if (err <= 0)
 			continue;
-		err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
+		err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
 		if (err <= 0)
 			continue;
 		if (!strcmp(name, buf))
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index deadb71..d87709d 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -123,7 +123,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
 	memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
 	bcm47xx_fill_sprom(&iv->sprom, NULL, false);
 
-	if (bcm47xx_nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
+	if (bcm47xx_nvram_getenv(NULL, "cardbus", buf, sizeof(buf)) >= 0)
 		iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
 
 	return 0;
@@ -146,7 +146,7 @@ static void __init bcm47xx_register_ssb(void)
 		panic("Failed to initialize SSB bus (err %d)", err);
 
 	mcore = &bcm47xx_bus.ssb.mipscore;
-	if (bcm47xx_nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+	if (bcm47xx_nvram_getenv(NULL, "kernel_args", buf, sizeof(buf)) >= 0) {
 		if (strstr(buf, "console=ttyS1")) {
 			struct ssb_serial_port port;
 
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
index 29ced12..f88f49b 100644
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -52,10 +52,10 @@ static int get_nvram_var(const char *prefix, const char *postfix,
 
 	create_key(prefix, postfix, name, key, sizeof(key));
 
-	err = bcm47xx_nvram_getenv(key, buf, len);
+	err = bcm47xx_nvram_getenv(NULL, key, buf, len);
 	if (fallback && err == -ENOENT && prefix) {
 		create_key(NULL, postfix, name, key, sizeof(key));
-		err = bcm47xx_nvram_getenv(key, buf, len);
+		err = bcm47xx_nvram_getenv(NULL, key, buf, len);
 	}
 	return err;
 }
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index c57a515..b2c3c7d 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -61,7 +61,7 @@ void __init plat_time_init(void)
 	}
 
 	if (chip_id == 0x5354) {
-		len = bcm47xx_nvram_getenv("clkfreq", buf, sizeof(buf));
+		len = bcm47xx_nvram_getenv(NULL, "clkfreq", buf, sizeof(buf));
 		if (len >= 0 && !strncmp(buf, "200", 4))
 			hz = 100000000;
 	}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b841180..b306c02 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -515,6 +515,19 @@ config VEXPRESS_SYSCFG
 	  bus. System Configuration interface is one of the possible means
 	  of generating transactions on this bus.
 
+config BCM47XX_NVRAM
+	tristate "BCM47XX nvram driver"
+	depends on OF
+	help
+	  This driver parses the nvram from a given memory range and
+	  provides its values to other drivers.
+
+	  The nvram is a key value store used on bcm47xx/bcm53xx SoC 
+	  with ARM and MIPS CPUs. It contains the board specific 
+	  configuration.
+
+	  If unsure, say N.
+
 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 5497d02..2331208 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,4 @@ obj-y				+= mic/
 obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
+obj-$(CONFIG_BCM47XX_NVRAM)	+= bcm47xx-nvram.o
diff --git a/drivers/misc/bcm47xx-nvram.c b/drivers/misc/bcm47xx-nvram.c
new file mode 100644
index 0000000..6ea715c
--- /dev/null
+++ b/drivers/misc/bcm47xx-nvram.c
@@ -0,0 +1,215 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2014 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bcm47xx_nvram.h>
+
+struct bcm47xx_nvram {
+	size_t nvram_len;
+	char *nvram_buf;
+};
+
+static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
+
+static u32 find_nvram_size(void __iomem *end)
+{
+	struct nvram_header __iomem *header;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+		header = (struct nvram_header __iomem *)(end - nvram_sizes[i]);
+		if (__raw_readl(&header->magic) == NVRAM_HEADER)
+			return nvram_sizes[i];
+	}
+
+	return 0;
+}
+
+/* Probe for NVRAM header */
+static int nvram_find_and_copy(struct device *dev, void __iomem *base,
+			       size_t len, char **nvram_buf,
+			       size_t *nvram_len)
+{
+	struct nvram_header __iomem *header;
+	int i;
+	u32 off;
+	u32 *dst;
+	__le32 __iomem *src;
+	u32 size;
+
+	/* TODO: when nvram is on nand flash check for bad blocks first. */
+	off = FLASH_MIN;
+	while (off <= len) {
+		/* Windowed flash access */
+		size = find_nvram_size(base + off);
+		if (size) {
+			header = (struct nvram_header __iomem *)
+					(base + off - size);
+			goto found;
+		}
+		off += 0x10000;
+	}
+
+	/* Try embedded NVRAM@4 KB and 1 KB as last resorts */
+	header = (struct nvram_header __iomem *)(base + 4096);
+	if (__raw_readl(&header->magic) == NVRAM_HEADER) {
+		size = NVRAM_SPACE;
+		goto found;
+	}
+
+	header = (struct nvram_header __iomem *)(base + 1024);
+	if (__raw_readl(&header->magic) == NVRAM_HEADER) {
+		size = NVRAM_SPACE;
+		goto found;
+	}
+
+	*nvram_buf = NULL;
+	*nvram_len = 0;
+	pr_err("no nvram found\n");
+	return -ENXIO;
+
+found:
+	if (readl(&header->len) > size)
+		pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
+	*nvram_len = min_t(u32, readl(&header->len), size);
+
+	*nvram_buf = devm_kzalloc(dev, *nvram_len, GFP_KERNEL);
+	if (!*nvram_buf)
+		return -ENOMEM;
+
+	src = (__le32 __iomem *) header;
+	dst = (u32 *) *nvram_buf;
+	for (i = 0; i < sizeof(struct nvram_header); i += 4)
+		*dst++ = __raw_readl(src++);
+	for (; i < *nvram_len; i += 4)
+		*dst++ = readl(src++);
+
+	return 0;
+}
+
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len)
+{
+	char *var, *value, *end, *eq;
+	struct bcm47xx_nvram *nvram;
+
+	if (!dev)
+		return -ENODEV;
+
+	nvram = dev_get_drvdata(dev);
+
+	if (!name || !nvram || !nvram->nvram_len)
+		return -EINVAL;
+
+	/* Look for name=value and return value */
+	var = nvram->nvram_buf + sizeof(struct nvram_header);
+	end = nvram->nvram_buf + nvram->nvram_len - 2;
+	end[0] = end[1] = '\0';
+	for (; *var; var = value + strlen(value) + 1) {
+		eq = strchr(var, '=');
+		if (!eq)
+			break;
+		value = eq + 1;
+		if ((eq - var) == strlen(name) &&
+			strncmp(var, name, (eq - var)) == 0) {
+			return snprintf(val, val_len, "%s", value);
+		}
+	}
+	return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_getenv);
+
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name)
+{
+	int i, err;
+	char nvram_var[10];
+	char buf[30];
+
+	if (!dev)
+		return -ENODEV;
+
+	for (i = 0; i < 32; i++) {
+		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
+		if (err <= 0)
+			continue;
+		err = bcm47xx_nvram_getenv(dev, nvram_var, buf, sizeof(buf));
+		if (err <= 0)
+			continue;
+		if (!strcmp(name, buf))
+			return i;
+	}
+	return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
+
+static int bcm47xx_nvram_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct bcm47xx_nvram *nvram;
+	int err;
+	struct resource flash_mem;
+	void __iomem *mmio;
+
+	/* Alloc */
+	nvram = devm_kzalloc(dev, sizeof(*nvram), GFP_KERNEL);
+	if (!nvram)
+		return -ENOMEM;
+
+	err = of_address_to_resource(np, 0, &flash_mem);
+	if (err)
+		return err;
+
+	mmio = ioremap_nocache(flash_mem.start, resource_size(&flash_mem));
+	if (!mmio)
+		return -ENOMEM;
+
+	err = nvram_find_and_copy(dev, mmio, resource_size(&flash_mem),
+				  &nvram->nvram_buf, &nvram->nvram_len);
+	if (err)
+		goto err_unmap_mmio;
+
+	platform_set_drvdata(pdev, nvram);
+
+err_unmap_mmio:
+	iounmap(mmio);
+	return err;
+}
+
+static const struct of_device_id bcm47xx_nvram_of_match_table[] = {
+	{ .compatible = "brcm,bcm47xx-nvram", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver bcm47xx_nvram_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "bcm47xx-nvram",
+		.of_match_table = bcm47xx_nvram_of_match_table,
+		/* driver unloading/unbinding currently not supported */
+		.suppress_bind_attrs = true,
+	},
+	.probe = bcm47xx_nvram_probe,
+};
+module_platform_driver(bcm47xx_nvram_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index d2714a2..8340498 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -411,7 +411,7 @@ static void b44_wap54g10_workaround(struct b44 *bp)
 	 * see https://dev.openwrt.org/ticket/146
 	 * check and reset bit "isolate"
 	 */
-	if (bcm47xx_nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
+	if (bcm47xx_nvram_getenv(NULL, "boardnum", buf, sizeof(buf)) < 0)
 		return;
 	if (simple_strtoul(buf, NULL, 0) == 2) {
 		err = __b44_readphy(bp, 0, MII_BMCR, &val);
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index bdda57b..1df7fb0 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -952,7 +952,8 @@ static void bgmac_chip_reset(struct bgmac *bgmac)
 			     BGMAC_CHIPCTL_1_IF_TYPE_MII;
 		char buf[4];
 
-		if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
+		if (bcm47xx_nvram_getenv(NULL, "et_swtype", buf,
+					 sizeof(buf)) > 0) {
 			if (kstrtou8(buf, 0, &et_swtype))
 				bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
 					  buf);
@@ -1501,7 +1502,7 @@ static int bgmac_probe(struct bcma_device *core)
 	}
 
 	bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
-	if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
+	if (bcm47xx_nvram_getenv(NULL, "et0_no_txint", NULL, 0) == 0)
 		bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
 
 	/* TODO: reset the external phy. Specs are needed */
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 8d07d4d..b611ea1 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -319,7 +319,8 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
 
 	if (bus->bustype == SSB_BUSTYPE_SSB) {
 		char buf[20];
-		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
+		if (bcm47xx_nvram_getenv(NULL, "xtalfreq", buf,
+					 sizeof(buf)) >= 0)
 			crystalfreq = simple_strtoul(buf, NULL, 0);
 	}
 
diff --git a/include/linux/bcm47xx_nvram.h b/include/linux/bcm47xx_nvram.h
index 333d32c..515fc06 100644
--- a/include/linux/bcm47xx_nvram.h
+++ b/include/linux/bcm47xx_nvram.h
@@ -15,9 +15,11 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 
+struct device;
+
 struct nvram_header {
 	u32 magic;
-	u32 len;
+	__le32 len;
 	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
 	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
 	u32 config_ncdl;	/* ncdl values for memc */
@@ -33,18 +35,21 @@ struct nvram_header {
 #define NVRAM_MAX_VALUE_LEN 255
 #define NVRAM_MAX_PARAM_LEN 64
 
-#ifdef CONFIG_BCM47XX
-int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+#if defined(CONFIG_BCM47XX) || defined(CONFIG_BCM47XX_NVRAM)
+int bcm47xx_nvram_getenv(const struct device *dev, const char *name, char *val,
+			 size_t val_len);
 
-int bcm47xx_nvram_gpio_pin(const char *name);
+int bcm47xx_nvram_gpio_pin(const struct device *dev, const char *name);
 #else
-static inline int bcm47xx_nvram_getenv(const char *name, char *val,
+static inline int bcm47xx_nvram_getenv(const struct device *dev,
+				       const char *name, char *val,
 				       size_t val_len)
 {
 	return -ENXIO;
 }
 
-static inline int bcm47xx_nvram_gpio_pin(const char *name)
+static inline int bcm47xx_nvram_gpio_pin(const struct device *dev,
+					 const char *name)
 {
 	return -ENXIO;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

This driver needs an nvram driver and fetches the sprom values from the
nvram and provides it to any other driver. The calibration data for the
wifi chip the mac address and some more board description data is
stores in the sprom.

This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
make the bcm47xx MIPS SoCs also use this driver some time later.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 drivers/misc/Kconfig                               |  14 +
 drivers/misc/Makefile                              |   1 +
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 4 files changed, 721 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 create mode 100644 drivers/misc/bcm47xx-sprom.c

diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
new file mode 100644
index 0000000..eed2a4a
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
@@ -0,0 +1,16 @@
+Broadcom bcm47xx/bcm53xx sprom converter
+
+This driver provbides an sprom based on a given nvram.
+
+Required properties:
+
+- compatible : brcm,bcm47xx-sprom
+
+- nvram : reference to a nvram driver, e.g. bcm47xx-nvram
+
+Example:
+
+sprom0: sprom@0 {
+	compatible = "brcm,bcm47xx-sprom";
+	nvram = <&nvram0>;
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b306c02..fe9e2f2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -528,6 +528,20 @@ config BCM47XX_NVRAM
 
 	  If unsure, say N.
 
+config BCM47XX_SPROM
+	tristate "BCM47XX sprom driver"
+	depends on OF
+	help
+	  This driver parses the sprom from a given nvram which is found on
+	  Broadcom bcm47xx and bcm53xx SoCs.
+
+	  The sprom contains board configuration data like the
+	  calibration data fro the wifi chips, the mac addresses used
+	  by the board and many other board configuration data. This
+	  driver will provide the sprom to bcma.
+
+	  If unsure, say N.
+
 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 2331208..e958e35 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_BCM47XX_NVRAM)	+= bcm47xx-nvram.o
+obj-$(CONFIG_BCM47XX_SPROM)	+= bcm47xx-sprom.o
diff --git a/drivers/misc/bcm47xx-sprom.c b/drivers/misc/bcm47xx-sprom.c
new file mode 100644
index 0000000..3221b12
--- /dev/null
+++ b/drivers/misc/bcm47xx-sprom.c
@@ -0,0 +1,690 @@
+/*
+ * BCM47xx/BCM53xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
+ * Copyright (C) 2006 Michael Buesch <m@bues.ch>
+ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2014 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/ssb/ssb.h>
+#include <linux/bcm47xx_nvram.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+
+struct bcm47xx_sprom_fill {
+	const char *prefix;
+	bool fallback;
+	int (*getenv)(const struct bcm47xx_sprom_fill *fill, const char *name,
+		      char *val, size_t val_len);
+	const void *priv;
+};
+
+static void create_key(const char *prefix, const char *postfix,
+		       const char *name, char *buf, int len)
+{
+	if (prefix && postfix)
+		snprintf(buf, len, "%s%s%s", prefix, name, postfix);
+	else if (prefix)
+		snprintf(buf, len, "%s%s", prefix, name);
+	else if (postfix)
+		snprintf(buf, len, "%s%s", name, postfix);
+	else
+		snprintf(buf, len, "%s", name);
+}
+
+static int get_nvram_var(const struct bcm47xx_sprom_fill *fill,
+			 const char *postfix, const char *name, char *buf,
+			 int len)
+{
+	char key[40];
+	int err;
+
+	create_key(fill->prefix, postfix, name, key, sizeof(key));
+
+	err = fill->getenv(fill, key, buf, len);
+	if (fill->fallback && err == -ENOENT && fill->prefix) {
+		create_key(NULL, postfix, name, key, sizeof(key));
+		err = fill->getenv(fill, key, buf, len);
+	}
+	return err;
+}
+
+#define NVRAM_READ_VAL(type)						\
+static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
+				 const char *postfix, const char *name, \
+				 type *val, type allset)		\
+{									\
+	char buf[100];							\
+	int err;							\
+	type var;							\
+									\
+	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
+	if (err < 0)							\
+		return;							\
+	err = kstrto ## type(strim(buf), 0, &var);			\
+	if (err) {							\
+		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
+			fill->prefix, name, postfix, buf, err);		\
+		return;							\
+	}								\
+	if (allset && var == allset)					\
+		return;							\
+	*val = var;							\
+}
+
+NVRAM_READ_VAL(u8)
+NVRAM_READ_VAL(s8)
+NVRAM_READ_VAL(u16)
+NVRAM_READ_VAL(u32)
+
+#undef NVRAM_READ_VAL
+
+static void nvram_read_u32_2(const struct bcm47xx_sprom_fill *fill,
+			     const char *name, u16 *val_lo, u16 *val_hi)
+{
+	char buf[100];
+	int err;
+	u32 val;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	err = kstrtou32(strim(buf), 0, &val);
+	if (err) {
+		pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+			fill->prefix, name, buf, err);
+		return;
+	}
+	*val_lo = (val & 0x0000FFFFU);
+	*val_hi = (val & 0xFFFF0000U) >> 16;
+}
+
+static void nvram_read_leddc(const struct bcm47xx_sprom_fill *fill,
+			     const char *name, u8 *leddc_on_time,
+			     u8 *leddc_off_time)
+{
+	char buf[100];
+	int err;
+	u32 val;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	err = kstrtou32(strim(buf), 0, &val);
+	if (err) {
+		pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+			fill->prefix, name, buf, err);
+		return;
+	}
+
+	if (val == 0xffff || val == 0xffffffff)
+		return;
+
+	*leddc_on_time = val & 0xff;
+	*leddc_off_time = (val >> 16) & 0xff;
+}
+
+static void nvram_read_macaddr(const struct bcm47xx_sprom_fill *fill,
+			       const char *name, u8 val[6])
+{
+	char buf[100];
+	int err;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+
+	bcm47xx_nvram_parse_macaddr(buf, val);
+}
+
+static void nvram_read_alpha2(const struct bcm47xx_sprom_fill *fill,
+			      const char *name, char val[2])
+{
+	char buf[10];
+	int err;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	if (buf[0] == '0')
+		return;
+	if (strlen(buf) > 2) {
+		pr_warn("alpha2 is too long %s\n", buf);
+		return;
+	}
+	memcpy(val, buf, 2);
+}
+
+static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
+	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
+	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
+	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
+	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
+	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
+	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
+}
+
+static void bcm47xx_sprom_fill_r12389(struct ssb_sprom *sprom,
+				      const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "pa0b0", &sprom->pa0b0, 0);
+	nvram_read_u16(fill, NULL, "pa0b1", &sprom->pa0b1, 0);
+	nvram_read_u16(fill, NULL, "pa0b2", &sprom->pa0b2, 0);
+	nvram_read_u8(fill, NULL, "pa0itssit", &sprom->itssi_bg, 0);
+	nvram_read_u8(fill, NULL, "pa0maxpwr", &sprom->maxpwr_bg, 0);
+	nvram_read_u16(fill, NULL, "pa1b0", &sprom->pa1b0, 0);
+	nvram_read_u16(fill, NULL, "pa1b1", &sprom->pa1b1, 0);
+	nvram_read_u16(fill, NULL, "pa1b2", &sprom->pa1b2, 0);
+	nvram_read_u8(fill, NULL, "pa1itssit", &sprom->itssi_a, 0);
+	nvram_read_u8(fill, NULL, "pa1maxpwr", &sprom->maxpwr_a, 0);
+}
+
+static void bcm47xx_sprom_fill_r1(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "boardflags", &sprom->boardflags_lo, 0);
+	nvram_read_u8(fill, NULL, "cc", &sprom->country_code, 0);
+}
+
+static void bcm47xx_sprom_fill_r2389(struct ssb_sprom *sprom,
+				     const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "opo", &sprom->opo, 0);
+	nvram_read_u16(fill, NULL, "pa1lob0", &sprom->pa1lob0, 0);
+	nvram_read_u16(fill, NULL, "pa1lob1", &sprom->pa1lob1, 0);
+	nvram_read_u16(fill, NULL, "pa1lob2", &sprom->pa1lob2, 0);
+	nvram_read_u16(fill, NULL, "pa1hib0", &sprom->pa1hib0, 0);
+	nvram_read_u16(fill, NULL, "pa1hib1", &sprom->pa1hib1, 0);
+	nvram_read_u16(fill, NULL, "pa1hib2", &sprom->pa1hib2, 0);
+	nvram_read_u8(fill, NULL, "pa1lomaxpwr", &sprom->maxpwr_al, 0);
+	nvram_read_u8(fill, NULL, "pa1himaxpwr", &sprom->maxpwr_ah, 0);
+}
+
+static void bcm47xx_sprom_fill_r389(struct ssb_sprom *sprom,
+				    const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "bxa2g", &sprom->bxa2g, 0);
+	nvram_read_u8(fill, NULL, "rssisav2g", &sprom->rssisav2g, 0);
+	nvram_read_u8(fill, NULL, "rssismc2g", &sprom->rssismc2g, 0);
+	nvram_read_u8(fill, NULL, "rssismf2g", &sprom->rssismf2g, 0);
+	nvram_read_u8(fill, NULL, "bxa5g", &sprom->bxa5g, 0);
+	nvram_read_u8(fill, NULL, "rssisav5g", &sprom->rssisav5g, 0);
+	nvram_read_u8(fill, NULL, "rssismc5g", &sprom->rssismc5g, 0);
+	nvram_read_u8(fill, NULL, "rssismf5g", &sprom->rssismf5g, 0);
+	nvram_read_u8(fill, NULL, "tri2g", &sprom->tri2g, 0);
+	nvram_read_u8(fill, NULL, "tri5g", &sprom->tri5g, 0);
+	nvram_read_u8(fill, NULL, "tri5gl", &sprom->tri5gl, 0);
+	nvram_read_u8(fill, NULL, "tri5gh", &sprom->tri5gh, 0);
+	nvram_read_s8(fill, NULL, "rxpo2g", &sprom->rxpo2g, 0);
+	nvram_read_s8(fill, NULL, "rxpo5g", &sprom->rxpo5g, 0);
+}
+
+static void bcm47xx_sprom_fill_r3(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
+	nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
+			 &sprom->leddc_off_time);
+}
+
+static void bcm47xx_sprom_fill_r4589(struct ssb_sprom *sprom,
+				     const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
+	nvram_read_s8(fill, NULL, "ag2", &sprom->antenna_gain.a2, 0);
+	nvram_read_s8(fill, NULL, "ag3", &sprom->antenna_gain.a3, 0);
+	nvram_read_u8(fill, NULL, "txchain", &sprom->txchain, 0xf);
+	nvram_read_u8(fill, NULL, "rxchain", &sprom->rxchain, 0xf);
+	nvram_read_u8(fill, NULL, "antswitch", &sprom->antswitch, 0xff);
+	nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
+			 &sprom->leddc_off_time);
+}
+
+static void bcm47xx_sprom_fill_r458(struct ssb_sprom *sprom,
+				    const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "cck2gpo", &sprom->cck2gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm2gpo", &sprom->ofdm2gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5gpo", &sprom->ofdm5gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5glpo", &sprom->ofdm5glpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5ghpo", &sprom->ofdm5ghpo, 0);
+	nvram_read_u16(fill, NULL, "cddpo", &sprom->cddpo, 0);
+	nvram_read_u16(fill, NULL, "stbcpo", &sprom->stbcpo, 0);
+	nvram_read_u16(fill, NULL, "bw40po", &sprom->bw40po, 0);
+	nvram_read_u16(fill, NULL, "bwduppo", &sprom->bwduppo, 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo0", &sprom->mcs2gpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo1", &sprom->mcs2gpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo2", &sprom->mcs2gpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo3", &sprom->mcs2gpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo4", &sprom->mcs2gpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo5", &sprom->mcs2gpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo6", &sprom->mcs2gpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo7", &sprom->mcs2gpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo0", &sprom->mcs5gpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo1", &sprom->mcs5gpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo2", &sprom->mcs5gpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo3", &sprom->mcs5gpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo4", &sprom->mcs5gpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo5", &sprom->mcs5gpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo6", &sprom->mcs5gpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo7", &sprom->mcs5gpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo0", &sprom->mcs5glpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo1", &sprom->mcs5glpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo2", &sprom->mcs5glpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo3", &sprom->mcs5glpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo4", &sprom->mcs5glpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo5", &sprom->mcs5glpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo6", &sprom->mcs5glpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo7", &sprom->mcs5glpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo0", &sprom->mcs5ghpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo1", &sprom->mcs5ghpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo2", &sprom->mcs5ghpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo3", &sprom->mcs5ghpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo4", &sprom->mcs5ghpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo5", &sprom->mcs5ghpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo6", &sprom->mcs5ghpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo7", &sprom->mcs5ghpo[7], 0);
+}
+
+static void bcm47xx_sprom_fill_r45(struct ssb_sprom *sprom,
+				   const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "txpid2ga0", &sprom->txpid2g[0], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga1", &sprom->txpid2g[1], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga2", &sprom->txpid2g[2], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga3", &sprom->txpid2g[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga0", &sprom->txpid5g[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga1", &sprom->txpid5g[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga2", &sprom->txpid5g[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga3", &sprom->txpid5g[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla0", &sprom->txpid5gl[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla1", &sprom->txpid5gl[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla2", &sprom->txpid5gl[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla3", &sprom->txpid5gl[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha0", &sprom->txpid5gh[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha1", &sprom->txpid5gh[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha2", &sprom->txpid5gh[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha3", &sprom->txpid5gh[3], 0);
+}
+
+static void bcm47xx_sprom_fill_r89(struct ssb_sprom *sprom,
+				   const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "tssipos2g", &sprom->fem.ghz2.tssipos, 0);
+	nvram_read_u8(fill, NULL, "extpagain2g", &sprom->fem.ghz2.extpa_gain, 0);
+	nvram_read_u8(fill, NULL, "pdetrange2g", &sprom->fem.ghz2.pdet_range, 0);
+	nvram_read_u8(fill, NULL, "triso2g", &sprom->fem.ghz2.tr_iso, 0);
+	nvram_read_u8(fill, NULL, "antswctl2g", &sprom->fem.ghz2.antswlut, 0);
+	nvram_read_u8(fill, NULL, "tssipos5g", &sprom->fem.ghz5.tssipos, 0);
+	nvram_read_u8(fill, NULL, "extpagain5g", &sprom->fem.ghz5.extpa_gain, 0);
+	nvram_read_u8(fill, NULL, "pdetrange5g", &sprom->fem.ghz5.pdet_range, 0);
+	nvram_read_u8(fill, NULL, "triso5g", &sprom->fem.ghz5.tr_iso, 0);
+	nvram_read_u8(fill, NULL, "antswctl5g", &sprom->fem.ghz5.antswlut, 0);
+	nvram_read_u8(fill, NULL, "tempthresh", &sprom->tempthresh, 0);
+	nvram_read_u8(fill, NULL, "tempoffset", &sprom->tempoffset, 0);
+	nvram_read_u16(fill, NULL, "rawtempsense", &sprom->rawtempsense, 0);
+	nvram_read_u8(fill, NULL, "measpower", &sprom->measpower, 0);
+	nvram_read_u8(fill, NULL, "tempsense_slope", &sprom->tempsense_slope, 0);
+	nvram_read_u8(fill, NULL, "tempcorrx", &sprom->tempcorrx, 0);
+	nvram_read_u8(fill, NULL, "tempsense_option", &sprom->tempsense_option, 0);
+	nvram_read_u8(fill, NULL, "freqoffset_corr", &sprom->freqoffset_corr, 0);
+	nvram_read_u8(fill, NULL, "iqcal_swp_dis", &sprom->iqcal_swp_dis, 0);
+	nvram_read_u8(fill, NULL, "hw_iqcal_en", &sprom->hw_iqcal_en, 0);
+	nvram_read_u8(fill, NULL, "elna2g", &sprom->elna2g, 0);
+	nvram_read_u8(fill, NULL, "elna5g", &sprom->elna5g, 0);
+	nvram_read_u8(fill, NULL, "phycal_tempdelta", &sprom->phycal_tempdelta, 0);
+	nvram_read_u8(fill, NULL, "temps_period", &sprom->temps_period, 0);
+	nvram_read_u8(fill, NULL, "temps_hysteresis", &sprom->temps_hysteresis, 0);
+	nvram_read_u8(fill, NULL, "measpower1", &sprom->measpower1, 0);
+	nvram_read_u8(fill, NULL, "measpower2", &sprom->measpower2, 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga0", &sprom->rxgainerr2ga[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga1", &sprom->rxgainerr2ga[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga2", &sprom->rxgainerr2ga[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla0", &sprom->rxgainerr5gla[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla1", &sprom->rxgainerr5gla[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla2", &sprom->rxgainerr5gla[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma0", &sprom->rxgainerr5gma[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma1", &sprom->rxgainerr5gma[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma2", &sprom->rxgainerr5gma[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha0", &sprom->rxgainerr5gha[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha1", &sprom->rxgainerr5gha[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha2", &sprom->rxgainerr5gha[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua0", &sprom->rxgainerr5gua[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua1", &sprom->rxgainerr5gua[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua2", &sprom->rxgainerr5gua[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga0", &sprom->noiselvl2ga[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga1", &sprom->noiselvl2ga[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga2", &sprom->noiselvl2ga[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla0", &sprom->noiselvl5gla[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla1", &sprom->noiselvl5gla[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla2", &sprom->noiselvl5gla[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma0", &sprom->noiselvl5gma[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma1", &sprom->noiselvl5gma[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma2", &sprom->noiselvl5gma[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha0", &sprom->noiselvl5gha[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha1", &sprom->noiselvl5gha[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha2", &sprom->noiselvl5gha[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua0", &sprom->noiselvl5gua[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua1", &sprom->noiselvl5gua[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua2", &sprom->noiselvl5gua[2], 0);
+	nvram_read_u8(fill, NULL, "pcieingress_war", &sprom->pcieingress_war, 0);
+}
+
+static void bcm47xx_sprom_fill_r9(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "cckbw202gpo", &sprom->cckbw202gpo, 0);
+	nvram_read_u16(fill, NULL, "cckbw20ul2gpo", &sprom->cckbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw202gpo", &sprom->legofdmbw202gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul2gpo", &sprom->legofdmbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205glpo", &sprom->legofdmbw205glpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5glpo", &sprom->legofdmbw20ul5glpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205gmpo", &sprom->legofdmbw205gmpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5gmpo", &sprom->legofdmbw20ul5gmpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205ghpo", &sprom->legofdmbw205ghpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5ghpo", &sprom->legofdmbw20ul5ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw202gpo", &sprom->mcsbw202gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul2gpo", &sprom->mcsbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw402gpo", &sprom->mcsbw402gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205glpo", &sprom->mcsbw205glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5glpo", &sprom->mcsbw20ul5glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405glpo", &sprom->mcsbw405glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205gmpo", &sprom->mcsbw205gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5gmpo", &sprom->mcsbw20ul5gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405gmpo", &sprom->mcsbw405gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205ghpo", &sprom->mcsbw205ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5ghpo", &sprom->mcsbw20ul5ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405ghpo", &sprom->mcsbw405ghpo, 0);
+	nvram_read_u16(fill, NULL, "mcs32po", &sprom->mcs32po, 0);
+	nvram_read_u16(fill, NULL, "legofdm40duppo", &sprom->legofdm40duppo, 0);
+	nvram_read_u8(fill, NULL, "sar2g", &sprom->sar2g, 0);
+	nvram_read_u8(fill, NULL, "sar5g", &sprom->sar5g, 0);
+}
+
+static void bcm47xx_sprom_fill_path_r4589(struct ssb_sprom *sprom,
+					  const struct bcm47xx_sprom_fill *fill)
+{
+	char postfix[2];
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+		struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+
+		snprintf(postfix, sizeof(postfix), "%i", i);
+		nvram_read_u8(fill, postfix, "maxp2ga", &pwr_info->maxpwr_2g, 0);
+		nvram_read_u8(fill, postfix, "itt2ga", &pwr_info->itssi_2g, 0);
+		nvram_read_u8(fill, postfix, "itt5ga", &pwr_info->itssi_5g, 0);
+		nvram_read_u16(fill, postfix, "pa2gw0a", &pwr_info->pa_2g[0], 0);
+		nvram_read_u16(fill, postfix, "pa2gw1a", &pwr_info->pa_2g[1], 0);
+		nvram_read_u16(fill, postfix, "pa2gw2a", &pwr_info->pa_2g[2], 0);
+		nvram_read_u8(fill, postfix, "maxp5ga", &pwr_info->maxpwr_5g, 0);
+		nvram_read_u8(fill, postfix, "maxp5gha", &pwr_info->maxpwr_5gh, 0);
+		nvram_read_u8(fill, postfix, "maxp5gla", &pwr_info->maxpwr_5gl, 0);
+		nvram_read_u16(fill, postfix, "pa5gw0a", &pwr_info->pa_5g[0], 0);
+		nvram_read_u16(fill, postfix, "pa5gw1a", &pwr_info->pa_5g[1], 0);
+		nvram_read_u16(fill, postfix, "pa5gw2a", &pwr_info->pa_5g[2], 0);
+		nvram_read_u16(fill, postfix, "pa5glw0a", &pwr_info->pa_5gl[0], 0);
+		nvram_read_u16(fill, postfix, "pa5glw1a", &pwr_info->pa_5gl[1], 0);
+		nvram_read_u16(fill, postfix, "pa5glw2a", &pwr_info->pa_5gl[2], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw0a", &pwr_info->pa_5gh[0], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw1a", &pwr_info->pa_5gh[1], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw2a", &pwr_info->pa_5gh[2], 0);
+	}
+}
+
+static void bcm47xx_sprom_fill_path_r45(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	char postfix[2];
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+		struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+
+		snprintf(postfix, sizeof(postfix), "%i", i);
+		nvram_read_u16(fill, postfix, "pa2gw3a", &pwr_info->pa_2g[3], 0);
+		nvram_read_u16(fill, postfix, "pa5gw3a", &pwr_info->pa_5g[3], 0);
+		nvram_read_u16(fill, postfix, "pa5glw3a", &pwr_info->pa_5gl[3], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw3a", &pwr_info->pa_5gh[3], 0);
+	}
+}
+
+static bool bcm47xx_is_valid_mac(u8 *mac)
+{
+	return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c);
+}
+
+static int bcm47xx_increase_mac_addr(u8 *mac, u8 num)
+{
+	u8 *oui = mac + ETH_ALEN/2 - 1;
+	u8 *p = mac + ETH_ALEN - 1;
+
+	do {
+		(*p) += num;
+		if (*p > num)
+			break;
+		p--;
+		num = 1;
+	} while (p != oui);
+
+	if (p == oui) {
+		pr_err("unable to fetch mac address\n");
+		return -ENOENT;
+	}
+	return 0;
+}
+
+/*
+ * This is a global counter because different instances of sprom will
+ * access the same nvram.
+ */
+static int mac_addr_used = 2;
+
+static void bcm47xx_sprom_fill_ethernet(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_macaddr(fill, "et0macaddr", sprom->et0mac);
+	nvram_read_u8(fill, NULL, "et0mdcport", &sprom->et0mdcport, 0);
+	nvram_read_u8(fill, NULL, "et0phyaddr", &sprom->et0phyaddr, 0);
+
+	nvram_read_macaddr(fill, "et1macaddr", sprom->et1mac);
+	nvram_read_u8(fill, NULL, "et1mdcport", &sprom->et1mdcport, 0);
+	nvram_read_u8(fill, NULL, "et1phyaddr", &sprom->et1phyaddr, 0);
+
+	nvram_read_macaddr(fill, "macaddr", sprom->il0mac);
+	nvram_read_macaddr(fill, "il0macaddr", sprom->il0mac);
+
+	/*
+	 * The address prefix 00:90:4C is used by Broadcom in their initial
+	 * configuration. When a mac address with the prefix 00:90:4C is used
+	 * all devices from the same series are sharing the same mac address.
+	 * To prevent mac address collisions we replace them with a mac address
+	 * based on the base address.
+	 */
+	if (!bcm47xx_is_valid_mac(sprom->il0mac)) {
+		u8 mac[6];
+		struct bcm47xx_sprom_fill fill_no_prefix;
+
+		memcpy(&fill_no_prefix, fill, sizeof(fill_no_prefix));
+		fill_no_prefix.prefix = NULL;
+
+		nvram_read_macaddr(&fill_no_prefix, "et0macaddr", mac);
+		if (bcm47xx_is_valid_mac(mac)) {
+			int err = bcm47xx_increase_mac_addr(mac, mac_addr_used);
+
+			if (!err) {
+				ether_addr_copy(sprom->il0mac, mac);
+				mac_addr_used++;
+			}
+		}
+	}
+}
+
+static void bcm47xx_sprom_fill_board_data(struct ssb_sprom *sprom,
+					  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "boardrev", &sprom->board_rev, 0);
+	nvram_read_u16(fill, NULL, "boardnum", &sprom->board_num, 0);
+	nvram_read_u16(fill, NULL, "boardtype", &sprom->board_type, 0);
+	nvram_read_u32_2(fill, "boardflags", &sprom->boardflags_lo,
+			 &sprom->boardflags_hi);
+	nvram_read_u32_2(fill, "boardflags2", &sprom->boardflags2_lo,
+			 &sprom->boardflags2_hi);
+}
+
+static void bcm47xx_sprom_fill(struct ssb_sprom *sprom,
+			       const struct bcm47xx_sprom_fill *fill)
+{
+	bcm47xx_sprom_fill_ethernet(sprom, fill);
+	bcm47xx_sprom_fill_board_data(sprom, fill);
+
+	nvram_read_u8(fill, NULL, "sromrev", &sprom->revision, 0);
+
+	switch (sprom->revision) {
+	case 1:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r1(sprom, fill);
+		break;
+	case 2:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		break;
+	case 3:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r3(sprom, fill);
+		break;
+	case 4:
+	case 5:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r458(sprom, fill);
+		bcm47xx_sprom_fill_r45(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		bcm47xx_sprom_fill_path_r45(sprom, fill);
+		break;
+	case 8:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r458(sprom, fill);
+		bcm47xx_sprom_fill_r89(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		break;
+	case 9:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r89(sprom, fill);
+		bcm47xx_sprom_fill_r9(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		break;
+	default:
+		pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
+			sprom->revision);
+		sprom->revision = 1;
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r1(sprom, fill);
+	}
+}
+
+static int bcm47xx_sprom_getenv(const struct bcm47xx_sprom_fill *fill,
+				const char *name, char *val, size_t val_len)
+{
+	const struct platform_device *nvram_dev = fill->priv;
+
+	return bcm47xx_nvram_getenv(&nvram_dev->dev, name, val, val_len);
+};
+
+static int bcm47xx_sprom_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct ssb_sprom *sprom;
+	const __be32 *handle;
+	struct device_node *nvram_node;
+	struct platform_device *nvram_dev;
+	struct bcm47xx_sprom_fill fill;
+
+	/* Alloc */
+	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
+	if (!sprom)
+		return -ENOMEM;
+
+	handle = of_get_property(np, "nvram", NULL);
+	if (!handle)
+		return -ENOMEM;
+
+	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));
+	if (!nvram_node)
+		return -ENOMEM;
+
+	nvram_dev = of_find_device_by_node(nvram_node);
+	if (!nvram_dev)
+		return -ENOMEM;
+
+	fill.prefix = of_get_property(np, "prefix", NULL);
+
+	fill.fallback = false;
+	fill.getenv = bcm47xx_sprom_getenv;
+	fill.priv = nvram_dev;
+
+	bcm47xx_sprom_fill(sprom, &fill);
+
+	platform_set_drvdata(pdev, sprom);
+
+	return 0;
+}
+
+static const struct of_device_id bcm47xx_sprom_of_match_table[] = {
+	{ .compatible = "brcm,bcm47xx-sprom", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver bcm47xx_sprom_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "bcm47xx-sprom",
+		.of_match_table = bcm47xx_sprom_of_match_table,
+		/* driver unloading/unbinding currently not supported */
+		.suppress_bind_attrs = true,
+	},
+	.probe = bcm47xx_sprom_probe,
+};
+module_platform_driver(bcm47xx_sprom_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

This driver needs an nvram driver and fetches the sprom values from the
nvram and provides it to any other driver. The calibration data for the
wifi chip the mac address and some more board description data is
stores in the sprom.

This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
make the bcm47xx MIPS SoCs also use this driver some time later.

Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
---
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 drivers/misc/Kconfig                               |  14 +
 drivers/misc/Makefile                              |   1 +
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 4 files changed, 721 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 create mode 100644 drivers/misc/bcm47xx-sprom.c

diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
new file mode 100644
index 0000000..eed2a4a
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
@@ -0,0 +1,16 @@
+Broadcom bcm47xx/bcm53xx sprom converter
+
+This driver provbides an sprom based on a given nvram.
+
+Required properties:
+
+- compatible : brcm,bcm47xx-sprom
+
+- nvram : reference to a nvram driver, e.g. bcm47xx-nvram
+
+Example:
+
+sprom0: sprom@0 {
+	compatible = "brcm,bcm47xx-sprom";
+	nvram = <&nvram0>;
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b306c02..fe9e2f2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -528,6 +528,20 @@ config BCM47XX_NVRAM
 
 	  If unsure, say N.
 
+config BCM47XX_SPROM
+	tristate "BCM47XX sprom driver"
+	depends on OF
+	help
+	  This driver parses the sprom from a given nvram which is found on
+	  Broadcom bcm47xx and bcm53xx SoCs.
+
+	  The sprom contains board configuration data like the
+	  calibration data fro the wifi chips, the mac addresses used
+	  by the board and many other board configuration data. This
+	  driver will provide the sprom to bcma.
+
+	  If unsure, say N.
+
 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 2331208..e958e35 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_BCM47XX_NVRAM)	+= bcm47xx-nvram.o
+obj-$(CONFIG_BCM47XX_SPROM)	+= bcm47xx-sprom.o
diff --git a/drivers/misc/bcm47xx-sprom.c b/drivers/misc/bcm47xx-sprom.c
new file mode 100644
index 0000000..3221b12
--- /dev/null
+++ b/drivers/misc/bcm47xx-sprom.c
@@ -0,0 +1,690 @@
+/*
+ * BCM47xx/BCM53xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2004 Florian Schirmer <jolt-8fvKG/JI9D0dnm+yROfE0A@public.gmane.org>
+ * Copyright (C) 2006 Michael Buesch <m@bues.ch>
+ * Copyright (C) 2010 Waldemar Brodkorb <wbx-bm4kxRPcj/hAfugRpC6u6w@public.gmane.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd-p3rKhJxN3npAfugRpC6u6w@public.gmane.org>
+ * Copyright (C) 2010-2014 Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/ssb/ssb.h>
+#include <linux/bcm47xx_nvram.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+
+struct bcm47xx_sprom_fill {
+	const char *prefix;
+	bool fallback;
+	int (*getenv)(const struct bcm47xx_sprom_fill *fill, const char *name,
+		      char *val, size_t val_len);
+	const void *priv;
+};
+
+static void create_key(const char *prefix, const char *postfix,
+		       const char *name, char *buf, int len)
+{
+	if (prefix && postfix)
+		snprintf(buf, len, "%s%s%s", prefix, name, postfix);
+	else if (prefix)
+		snprintf(buf, len, "%s%s", prefix, name);
+	else if (postfix)
+		snprintf(buf, len, "%s%s", name, postfix);
+	else
+		snprintf(buf, len, "%s", name);
+}
+
+static int get_nvram_var(const struct bcm47xx_sprom_fill *fill,
+			 const char *postfix, const char *name, char *buf,
+			 int len)
+{
+	char key[40];
+	int err;
+
+	create_key(fill->prefix, postfix, name, key, sizeof(key));
+
+	err = fill->getenv(fill, key, buf, len);
+	if (fill->fallback && err == -ENOENT && fill->prefix) {
+		create_key(NULL, postfix, name, key, sizeof(key));
+		err = fill->getenv(fill, key, buf, len);
+	}
+	return err;
+}
+
+#define NVRAM_READ_VAL(type)						\
+static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
+				 const char *postfix, const char *name, \
+				 type *val, type allset)		\
+{									\
+	char buf[100];							\
+	int err;							\
+	type var;							\
+									\
+	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
+	if (err < 0)							\
+		return;							\
+	err = kstrto ## type(strim(buf), 0, &var);			\
+	if (err) {							\
+		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
+			fill->prefix, name, postfix, buf, err);		\
+		return;							\
+	}								\
+	if (allset && var == allset)					\
+		return;							\
+	*val = var;							\
+}
+
+NVRAM_READ_VAL(u8)
+NVRAM_READ_VAL(s8)
+NVRAM_READ_VAL(u16)
+NVRAM_READ_VAL(u32)
+
+#undef NVRAM_READ_VAL
+
+static void nvram_read_u32_2(const struct bcm47xx_sprom_fill *fill,
+			     const char *name, u16 *val_lo, u16 *val_hi)
+{
+	char buf[100];
+	int err;
+	u32 val;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	err = kstrtou32(strim(buf), 0, &val);
+	if (err) {
+		pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+			fill->prefix, name, buf, err);
+		return;
+	}
+	*val_lo = (val & 0x0000FFFFU);
+	*val_hi = (val & 0xFFFF0000U) >> 16;
+}
+
+static void nvram_read_leddc(const struct bcm47xx_sprom_fill *fill,
+			     const char *name, u8 *leddc_on_time,
+			     u8 *leddc_off_time)
+{
+	char buf[100];
+	int err;
+	u32 val;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	err = kstrtou32(strim(buf), 0, &val);
+	if (err) {
+		pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+			fill->prefix, name, buf, err);
+		return;
+	}
+
+	if (val == 0xffff || val == 0xffffffff)
+		return;
+
+	*leddc_on_time = val & 0xff;
+	*leddc_off_time = (val >> 16) & 0xff;
+}
+
+static void nvram_read_macaddr(const struct bcm47xx_sprom_fill *fill,
+			       const char *name, u8 val[6])
+{
+	char buf[100];
+	int err;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+
+	bcm47xx_nvram_parse_macaddr(buf, val);
+}
+
+static void nvram_read_alpha2(const struct bcm47xx_sprom_fill *fill,
+			      const char *name, char val[2])
+{
+	char buf[10];
+	int err;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	if (buf[0] == '0')
+		return;
+	if (strlen(buf) > 2) {
+		pr_warn("alpha2 is too long %s\n", buf);
+		return;
+	}
+	memcpy(val, buf, 2);
+}
+
+static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
+	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
+	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
+	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
+	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
+	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
+	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
+}
+
+static void bcm47xx_sprom_fill_r12389(struct ssb_sprom *sprom,
+				      const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "pa0b0", &sprom->pa0b0, 0);
+	nvram_read_u16(fill, NULL, "pa0b1", &sprom->pa0b1, 0);
+	nvram_read_u16(fill, NULL, "pa0b2", &sprom->pa0b2, 0);
+	nvram_read_u8(fill, NULL, "pa0itssit", &sprom->itssi_bg, 0);
+	nvram_read_u8(fill, NULL, "pa0maxpwr", &sprom->maxpwr_bg, 0);
+	nvram_read_u16(fill, NULL, "pa1b0", &sprom->pa1b0, 0);
+	nvram_read_u16(fill, NULL, "pa1b1", &sprom->pa1b1, 0);
+	nvram_read_u16(fill, NULL, "pa1b2", &sprom->pa1b2, 0);
+	nvram_read_u8(fill, NULL, "pa1itssit", &sprom->itssi_a, 0);
+	nvram_read_u8(fill, NULL, "pa1maxpwr", &sprom->maxpwr_a, 0);
+}
+
+static void bcm47xx_sprom_fill_r1(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "boardflags", &sprom->boardflags_lo, 0);
+	nvram_read_u8(fill, NULL, "cc", &sprom->country_code, 0);
+}
+
+static void bcm47xx_sprom_fill_r2389(struct ssb_sprom *sprom,
+				     const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "opo", &sprom->opo, 0);
+	nvram_read_u16(fill, NULL, "pa1lob0", &sprom->pa1lob0, 0);
+	nvram_read_u16(fill, NULL, "pa1lob1", &sprom->pa1lob1, 0);
+	nvram_read_u16(fill, NULL, "pa1lob2", &sprom->pa1lob2, 0);
+	nvram_read_u16(fill, NULL, "pa1hib0", &sprom->pa1hib0, 0);
+	nvram_read_u16(fill, NULL, "pa1hib1", &sprom->pa1hib1, 0);
+	nvram_read_u16(fill, NULL, "pa1hib2", &sprom->pa1hib2, 0);
+	nvram_read_u8(fill, NULL, "pa1lomaxpwr", &sprom->maxpwr_al, 0);
+	nvram_read_u8(fill, NULL, "pa1himaxpwr", &sprom->maxpwr_ah, 0);
+}
+
+static void bcm47xx_sprom_fill_r389(struct ssb_sprom *sprom,
+				    const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "bxa2g", &sprom->bxa2g, 0);
+	nvram_read_u8(fill, NULL, "rssisav2g", &sprom->rssisav2g, 0);
+	nvram_read_u8(fill, NULL, "rssismc2g", &sprom->rssismc2g, 0);
+	nvram_read_u8(fill, NULL, "rssismf2g", &sprom->rssismf2g, 0);
+	nvram_read_u8(fill, NULL, "bxa5g", &sprom->bxa5g, 0);
+	nvram_read_u8(fill, NULL, "rssisav5g", &sprom->rssisav5g, 0);
+	nvram_read_u8(fill, NULL, "rssismc5g", &sprom->rssismc5g, 0);
+	nvram_read_u8(fill, NULL, "rssismf5g", &sprom->rssismf5g, 0);
+	nvram_read_u8(fill, NULL, "tri2g", &sprom->tri2g, 0);
+	nvram_read_u8(fill, NULL, "tri5g", &sprom->tri5g, 0);
+	nvram_read_u8(fill, NULL, "tri5gl", &sprom->tri5gl, 0);
+	nvram_read_u8(fill, NULL, "tri5gh", &sprom->tri5gh, 0);
+	nvram_read_s8(fill, NULL, "rxpo2g", &sprom->rxpo2g, 0);
+	nvram_read_s8(fill, NULL, "rxpo5g", &sprom->rxpo5g, 0);
+}
+
+static void bcm47xx_sprom_fill_r3(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
+	nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
+			 &sprom->leddc_off_time);
+}
+
+static void bcm47xx_sprom_fill_r4589(struct ssb_sprom *sprom,
+				     const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
+	nvram_read_s8(fill, NULL, "ag2", &sprom->antenna_gain.a2, 0);
+	nvram_read_s8(fill, NULL, "ag3", &sprom->antenna_gain.a3, 0);
+	nvram_read_u8(fill, NULL, "txchain", &sprom->txchain, 0xf);
+	nvram_read_u8(fill, NULL, "rxchain", &sprom->rxchain, 0xf);
+	nvram_read_u8(fill, NULL, "antswitch", &sprom->antswitch, 0xff);
+	nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
+			 &sprom->leddc_off_time);
+}
+
+static void bcm47xx_sprom_fill_r458(struct ssb_sprom *sprom,
+				    const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "cck2gpo", &sprom->cck2gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm2gpo", &sprom->ofdm2gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5gpo", &sprom->ofdm5gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5glpo", &sprom->ofdm5glpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5ghpo", &sprom->ofdm5ghpo, 0);
+	nvram_read_u16(fill, NULL, "cddpo", &sprom->cddpo, 0);
+	nvram_read_u16(fill, NULL, "stbcpo", &sprom->stbcpo, 0);
+	nvram_read_u16(fill, NULL, "bw40po", &sprom->bw40po, 0);
+	nvram_read_u16(fill, NULL, "bwduppo", &sprom->bwduppo, 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo0", &sprom->mcs2gpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo1", &sprom->mcs2gpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo2", &sprom->mcs2gpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo3", &sprom->mcs2gpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo4", &sprom->mcs2gpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo5", &sprom->mcs2gpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo6", &sprom->mcs2gpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo7", &sprom->mcs2gpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo0", &sprom->mcs5gpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo1", &sprom->mcs5gpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo2", &sprom->mcs5gpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo3", &sprom->mcs5gpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo4", &sprom->mcs5gpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo5", &sprom->mcs5gpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo6", &sprom->mcs5gpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo7", &sprom->mcs5gpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo0", &sprom->mcs5glpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo1", &sprom->mcs5glpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo2", &sprom->mcs5glpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo3", &sprom->mcs5glpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo4", &sprom->mcs5glpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo5", &sprom->mcs5glpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo6", &sprom->mcs5glpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo7", &sprom->mcs5glpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo0", &sprom->mcs5ghpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo1", &sprom->mcs5ghpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo2", &sprom->mcs5ghpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo3", &sprom->mcs5ghpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo4", &sprom->mcs5ghpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo5", &sprom->mcs5ghpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo6", &sprom->mcs5ghpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo7", &sprom->mcs5ghpo[7], 0);
+}
+
+static void bcm47xx_sprom_fill_r45(struct ssb_sprom *sprom,
+				   const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "txpid2ga0", &sprom->txpid2g[0], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga1", &sprom->txpid2g[1], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga2", &sprom->txpid2g[2], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga3", &sprom->txpid2g[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga0", &sprom->txpid5g[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga1", &sprom->txpid5g[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga2", &sprom->txpid5g[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga3", &sprom->txpid5g[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla0", &sprom->txpid5gl[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla1", &sprom->txpid5gl[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla2", &sprom->txpid5gl[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla3", &sprom->txpid5gl[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha0", &sprom->txpid5gh[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha1", &sprom->txpid5gh[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha2", &sprom->txpid5gh[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha3", &sprom->txpid5gh[3], 0);
+}
+
+static void bcm47xx_sprom_fill_r89(struct ssb_sprom *sprom,
+				   const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "tssipos2g", &sprom->fem.ghz2.tssipos, 0);
+	nvram_read_u8(fill, NULL, "extpagain2g", &sprom->fem.ghz2.extpa_gain, 0);
+	nvram_read_u8(fill, NULL, "pdetrange2g", &sprom->fem.ghz2.pdet_range, 0);
+	nvram_read_u8(fill, NULL, "triso2g", &sprom->fem.ghz2.tr_iso, 0);
+	nvram_read_u8(fill, NULL, "antswctl2g", &sprom->fem.ghz2.antswlut, 0);
+	nvram_read_u8(fill, NULL, "tssipos5g", &sprom->fem.ghz5.tssipos, 0);
+	nvram_read_u8(fill, NULL, "extpagain5g", &sprom->fem.ghz5.extpa_gain, 0);
+	nvram_read_u8(fill, NULL, "pdetrange5g", &sprom->fem.ghz5.pdet_range, 0);
+	nvram_read_u8(fill, NULL, "triso5g", &sprom->fem.ghz5.tr_iso, 0);
+	nvram_read_u8(fill, NULL, "antswctl5g", &sprom->fem.ghz5.antswlut, 0);
+	nvram_read_u8(fill, NULL, "tempthresh", &sprom->tempthresh, 0);
+	nvram_read_u8(fill, NULL, "tempoffset", &sprom->tempoffset, 0);
+	nvram_read_u16(fill, NULL, "rawtempsense", &sprom->rawtempsense, 0);
+	nvram_read_u8(fill, NULL, "measpower", &sprom->measpower, 0);
+	nvram_read_u8(fill, NULL, "tempsense_slope", &sprom->tempsense_slope, 0);
+	nvram_read_u8(fill, NULL, "tempcorrx", &sprom->tempcorrx, 0);
+	nvram_read_u8(fill, NULL, "tempsense_option", &sprom->tempsense_option, 0);
+	nvram_read_u8(fill, NULL, "freqoffset_corr", &sprom->freqoffset_corr, 0);
+	nvram_read_u8(fill, NULL, "iqcal_swp_dis", &sprom->iqcal_swp_dis, 0);
+	nvram_read_u8(fill, NULL, "hw_iqcal_en", &sprom->hw_iqcal_en, 0);
+	nvram_read_u8(fill, NULL, "elna2g", &sprom->elna2g, 0);
+	nvram_read_u8(fill, NULL, "elna5g", &sprom->elna5g, 0);
+	nvram_read_u8(fill, NULL, "phycal_tempdelta", &sprom->phycal_tempdelta, 0);
+	nvram_read_u8(fill, NULL, "temps_period", &sprom->temps_period, 0);
+	nvram_read_u8(fill, NULL, "temps_hysteresis", &sprom->temps_hysteresis, 0);
+	nvram_read_u8(fill, NULL, "measpower1", &sprom->measpower1, 0);
+	nvram_read_u8(fill, NULL, "measpower2", &sprom->measpower2, 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga0", &sprom->rxgainerr2ga[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga1", &sprom->rxgainerr2ga[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga2", &sprom->rxgainerr2ga[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla0", &sprom->rxgainerr5gla[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla1", &sprom->rxgainerr5gla[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla2", &sprom->rxgainerr5gla[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma0", &sprom->rxgainerr5gma[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma1", &sprom->rxgainerr5gma[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma2", &sprom->rxgainerr5gma[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha0", &sprom->rxgainerr5gha[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha1", &sprom->rxgainerr5gha[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha2", &sprom->rxgainerr5gha[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua0", &sprom->rxgainerr5gua[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua1", &sprom->rxgainerr5gua[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua2", &sprom->rxgainerr5gua[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga0", &sprom->noiselvl2ga[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga1", &sprom->noiselvl2ga[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga2", &sprom->noiselvl2ga[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla0", &sprom->noiselvl5gla[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla1", &sprom->noiselvl5gla[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla2", &sprom->noiselvl5gla[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma0", &sprom->noiselvl5gma[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma1", &sprom->noiselvl5gma[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma2", &sprom->noiselvl5gma[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha0", &sprom->noiselvl5gha[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha1", &sprom->noiselvl5gha[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha2", &sprom->noiselvl5gha[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua0", &sprom->noiselvl5gua[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua1", &sprom->noiselvl5gua[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua2", &sprom->noiselvl5gua[2], 0);
+	nvram_read_u8(fill, NULL, "pcieingress_war", &sprom->pcieingress_war, 0);
+}
+
+static void bcm47xx_sprom_fill_r9(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "cckbw202gpo", &sprom->cckbw202gpo, 0);
+	nvram_read_u16(fill, NULL, "cckbw20ul2gpo", &sprom->cckbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw202gpo", &sprom->legofdmbw202gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul2gpo", &sprom->legofdmbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205glpo", &sprom->legofdmbw205glpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5glpo", &sprom->legofdmbw20ul5glpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205gmpo", &sprom->legofdmbw205gmpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5gmpo", &sprom->legofdmbw20ul5gmpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205ghpo", &sprom->legofdmbw205ghpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5ghpo", &sprom->legofdmbw20ul5ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw202gpo", &sprom->mcsbw202gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul2gpo", &sprom->mcsbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw402gpo", &sprom->mcsbw402gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205glpo", &sprom->mcsbw205glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5glpo", &sprom->mcsbw20ul5glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405glpo", &sprom->mcsbw405glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205gmpo", &sprom->mcsbw205gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5gmpo", &sprom->mcsbw20ul5gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405gmpo", &sprom->mcsbw405gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205ghpo", &sprom->mcsbw205ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5ghpo", &sprom->mcsbw20ul5ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405ghpo", &sprom->mcsbw405ghpo, 0);
+	nvram_read_u16(fill, NULL, "mcs32po", &sprom->mcs32po, 0);
+	nvram_read_u16(fill, NULL, "legofdm40duppo", &sprom->legofdm40duppo, 0);
+	nvram_read_u8(fill, NULL, "sar2g", &sprom->sar2g, 0);
+	nvram_read_u8(fill, NULL, "sar5g", &sprom->sar5g, 0);
+}
+
+static void bcm47xx_sprom_fill_path_r4589(struct ssb_sprom *sprom,
+					  const struct bcm47xx_sprom_fill *fill)
+{
+	char postfix[2];
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+		struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+
+		snprintf(postfix, sizeof(postfix), "%i", i);
+		nvram_read_u8(fill, postfix, "maxp2ga", &pwr_info->maxpwr_2g, 0);
+		nvram_read_u8(fill, postfix, "itt2ga", &pwr_info->itssi_2g, 0);
+		nvram_read_u8(fill, postfix, "itt5ga", &pwr_info->itssi_5g, 0);
+		nvram_read_u16(fill, postfix, "pa2gw0a", &pwr_info->pa_2g[0], 0);
+		nvram_read_u16(fill, postfix, "pa2gw1a", &pwr_info->pa_2g[1], 0);
+		nvram_read_u16(fill, postfix, "pa2gw2a", &pwr_info->pa_2g[2], 0);
+		nvram_read_u8(fill, postfix, "maxp5ga", &pwr_info->maxpwr_5g, 0);
+		nvram_read_u8(fill, postfix, "maxp5gha", &pwr_info->maxpwr_5gh, 0);
+		nvram_read_u8(fill, postfix, "maxp5gla", &pwr_info->maxpwr_5gl, 0);
+		nvram_read_u16(fill, postfix, "pa5gw0a", &pwr_info->pa_5g[0], 0);
+		nvram_read_u16(fill, postfix, "pa5gw1a", &pwr_info->pa_5g[1], 0);
+		nvram_read_u16(fill, postfix, "pa5gw2a", &pwr_info->pa_5g[2], 0);
+		nvram_read_u16(fill, postfix, "pa5glw0a", &pwr_info->pa_5gl[0], 0);
+		nvram_read_u16(fill, postfix, "pa5glw1a", &pwr_info->pa_5gl[1], 0);
+		nvram_read_u16(fill, postfix, "pa5glw2a", &pwr_info->pa_5gl[2], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw0a", &pwr_info->pa_5gh[0], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw1a", &pwr_info->pa_5gh[1], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw2a", &pwr_info->pa_5gh[2], 0);
+	}
+}
+
+static void bcm47xx_sprom_fill_path_r45(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	char postfix[2];
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+		struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+
+		snprintf(postfix, sizeof(postfix), "%i", i);
+		nvram_read_u16(fill, postfix, "pa2gw3a", &pwr_info->pa_2g[3], 0);
+		nvram_read_u16(fill, postfix, "pa5gw3a", &pwr_info->pa_5g[3], 0);
+		nvram_read_u16(fill, postfix, "pa5glw3a", &pwr_info->pa_5gl[3], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw3a", &pwr_info->pa_5gh[3], 0);
+	}
+}
+
+static bool bcm47xx_is_valid_mac(u8 *mac)
+{
+	return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c);
+}
+
+static int bcm47xx_increase_mac_addr(u8 *mac, u8 num)
+{
+	u8 *oui = mac + ETH_ALEN/2 - 1;
+	u8 *p = mac + ETH_ALEN - 1;
+
+	do {
+		(*p) += num;
+		if (*p > num)
+			break;
+		p--;
+		num = 1;
+	} while (p != oui);
+
+	if (p == oui) {
+		pr_err("unable to fetch mac address\n");
+		return -ENOENT;
+	}
+	return 0;
+}
+
+/*
+ * This is a global counter because different instances of sprom will
+ * access the same nvram.
+ */
+static int mac_addr_used = 2;
+
+static void bcm47xx_sprom_fill_ethernet(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_macaddr(fill, "et0macaddr", sprom->et0mac);
+	nvram_read_u8(fill, NULL, "et0mdcport", &sprom->et0mdcport, 0);
+	nvram_read_u8(fill, NULL, "et0phyaddr", &sprom->et0phyaddr, 0);
+
+	nvram_read_macaddr(fill, "et1macaddr", sprom->et1mac);
+	nvram_read_u8(fill, NULL, "et1mdcport", &sprom->et1mdcport, 0);
+	nvram_read_u8(fill, NULL, "et1phyaddr", &sprom->et1phyaddr, 0);
+
+	nvram_read_macaddr(fill, "macaddr", sprom->il0mac);
+	nvram_read_macaddr(fill, "il0macaddr", sprom->il0mac);
+
+	/*
+	 * The address prefix 00:90:4C is used by Broadcom in their initial
+	 * configuration. When a mac address with the prefix 00:90:4C is used
+	 * all devices from the same series are sharing the same mac address.
+	 * To prevent mac address collisions we replace them with a mac address
+	 * based on the base address.
+	 */
+	if (!bcm47xx_is_valid_mac(sprom->il0mac)) {
+		u8 mac[6];
+		struct bcm47xx_sprom_fill fill_no_prefix;
+
+		memcpy(&fill_no_prefix, fill, sizeof(fill_no_prefix));
+		fill_no_prefix.prefix = NULL;
+
+		nvram_read_macaddr(&fill_no_prefix, "et0macaddr", mac);
+		if (bcm47xx_is_valid_mac(mac)) {
+			int err = bcm47xx_increase_mac_addr(mac, mac_addr_used);
+
+			if (!err) {
+				ether_addr_copy(sprom->il0mac, mac);
+				mac_addr_used++;
+			}
+		}
+	}
+}
+
+static void bcm47xx_sprom_fill_board_data(struct ssb_sprom *sprom,
+					  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "boardrev", &sprom->board_rev, 0);
+	nvram_read_u16(fill, NULL, "boardnum", &sprom->board_num, 0);
+	nvram_read_u16(fill, NULL, "boardtype", &sprom->board_type, 0);
+	nvram_read_u32_2(fill, "boardflags", &sprom->boardflags_lo,
+			 &sprom->boardflags_hi);
+	nvram_read_u32_2(fill, "boardflags2", &sprom->boardflags2_lo,
+			 &sprom->boardflags2_hi);
+}
+
+static void bcm47xx_sprom_fill(struct ssb_sprom *sprom,
+			       const struct bcm47xx_sprom_fill *fill)
+{
+	bcm47xx_sprom_fill_ethernet(sprom, fill);
+	bcm47xx_sprom_fill_board_data(sprom, fill);
+
+	nvram_read_u8(fill, NULL, "sromrev", &sprom->revision, 0);
+
+	switch (sprom->revision) {
+	case 1:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r1(sprom, fill);
+		break;
+	case 2:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		break;
+	case 3:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r3(sprom, fill);
+		break;
+	case 4:
+	case 5:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r458(sprom, fill);
+		bcm47xx_sprom_fill_r45(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		bcm47xx_sprom_fill_path_r45(sprom, fill);
+		break;
+	case 8:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r458(sprom, fill);
+		bcm47xx_sprom_fill_r89(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		break;
+	case 9:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r89(sprom, fill);
+		bcm47xx_sprom_fill_r9(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		break;
+	default:
+		pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
+			sprom->revision);
+		sprom->revision = 1;
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r1(sprom, fill);
+	}
+}
+
+static int bcm47xx_sprom_getenv(const struct bcm47xx_sprom_fill *fill,
+				const char *name, char *val, size_t val_len)
+{
+	const struct platform_device *nvram_dev = fill->priv;
+
+	return bcm47xx_nvram_getenv(&nvram_dev->dev, name, val, val_len);
+};
+
+static int bcm47xx_sprom_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct ssb_sprom *sprom;
+	const __be32 *handle;
+	struct device_node *nvram_node;
+	struct platform_device *nvram_dev;
+	struct bcm47xx_sprom_fill fill;
+
+	/* Alloc */
+	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
+	if (!sprom)
+		return -ENOMEM;
+
+	handle = of_get_property(np, "nvram", NULL);
+	if (!handle)
+		return -ENOMEM;
+
+	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));
+	if (!nvram_node)
+		return -ENOMEM;
+
+	nvram_dev = of_find_device_by_node(nvram_node);
+	if (!nvram_dev)
+		return -ENOMEM;
+
+	fill.prefix = of_get_property(np, "prefix", NULL);
+
+	fill.fallback = false;
+	fill.getenv = bcm47xx_sprom_getenv;
+	fill.priv = nvram_dev;
+
+	bcm47xx_sprom_fill(sprom, &fill);
+
+	platform_set_drvdata(pdev, sprom);
+
+	return 0;
+}
+
+static const struct of_device_id bcm47xx_sprom_of_match_table[] = {
+	{ .compatible = "brcm,bcm47xx-sprom", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver bcm47xx_sprom_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "bcm47xx-sprom",
+		.of_match_table = bcm47xx_sprom_of_match_table,
+		/* driver unloading/unbinding currently not supported */
+		.suppress_bind_attrs = true,
+	},
+	.probe = bcm47xx_sprom_probe,
+};
+module_platform_driver(bcm47xx_sprom_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

This driver needs an nvram driver and fetches the sprom values from the
nvram and provides it to any other driver. The calibration data for the
wifi chip the mac address and some more board description data is
stores in the sprom.

This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
make the bcm47xx MIPS SoCs also use this driver some time later.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
 drivers/misc/Kconfig                               |  14 +
 drivers/misc/Makefile                              |   1 +
 drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
 4 files changed, 721 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
 create mode 100644 drivers/misc/bcm47xx-sprom.c

diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
new file mode 100644
index 0000000..eed2a4a
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
@@ -0,0 +1,16 @@
+Broadcom bcm47xx/bcm53xx sprom converter
+
+This driver provbides an sprom based on a given nvram.
+
+Required properties:
+
+- compatible : brcm,bcm47xx-sprom
+
+- nvram : reference to a nvram driver, e.g. bcm47xx-nvram
+
+Example:
+
+sprom0: sprom at 0 {
+	compatible = "brcm,bcm47xx-sprom";
+	nvram = <&nvram0>;
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b306c02..fe9e2f2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -528,6 +528,20 @@ config BCM47XX_NVRAM
 
 	  If unsure, say N.
 
+config BCM47XX_SPROM
+	tristate "BCM47XX sprom driver"
+	depends on OF
+	help
+	  This driver parses the sprom from a given nvram which is found on
+	  Broadcom bcm47xx and bcm53xx SoCs.
+
+	  The sprom contains board configuration data like the
+	  calibration data fro the wifi chips, the mac addresses used
+	  by the board and many other board configuration data. This
+	  driver will provide the sprom to bcma.
+
+	  If unsure, say N.
+
 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 2331208..e958e35 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_BCM47XX_NVRAM)	+= bcm47xx-nvram.o
+obj-$(CONFIG_BCM47XX_SPROM)	+= bcm47xx-sprom.o
diff --git a/drivers/misc/bcm47xx-sprom.c b/drivers/misc/bcm47xx-sprom.c
new file mode 100644
index 0000000..3221b12
--- /dev/null
+++ b/drivers/misc/bcm47xx-sprom.c
@@ -0,0 +1,690 @@
+/*
+ * BCM47xx/BCM53xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
+ * Copyright (C) 2006 Michael Buesch <m@bues.ch>
+ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2014 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/ssb/ssb.h>
+#include <linux/bcm47xx_nvram.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+
+struct bcm47xx_sprom_fill {
+	const char *prefix;
+	bool fallback;
+	int (*getenv)(const struct bcm47xx_sprom_fill *fill, const char *name,
+		      char *val, size_t val_len);
+	const void *priv;
+};
+
+static void create_key(const char *prefix, const char *postfix,
+		       const char *name, char *buf, int len)
+{
+	if (prefix && postfix)
+		snprintf(buf, len, "%s%s%s", prefix, name, postfix);
+	else if (prefix)
+		snprintf(buf, len, "%s%s", prefix, name);
+	else if (postfix)
+		snprintf(buf, len, "%s%s", name, postfix);
+	else
+		snprintf(buf, len, "%s", name);
+}
+
+static int get_nvram_var(const struct bcm47xx_sprom_fill *fill,
+			 const char *postfix, const char *name, char *buf,
+			 int len)
+{
+	char key[40];
+	int err;
+
+	create_key(fill->prefix, postfix, name, key, sizeof(key));
+
+	err = fill->getenv(fill, key, buf, len);
+	if (fill->fallback && err == -ENOENT && fill->prefix) {
+		create_key(NULL, postfix, name, key, sizeof(key));
+		err = fill->getenv(fill, key, buf, len);
+	}
+	return err;
+}
+
+#define NVRAM_READ_VAL(type)						\
+static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
+				 const char *postfix, const char *name, \
+				 type *val, type allset)		\
+{									\
+	char buf[100];							\
+	int err;							\
+	type var;							\
+									\
+	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
+	if (err < 0)							\
+		return;							\
+	err = kstrto ## type(strim(buf), 0, &var);			\
+	if (err) {							\
+		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
+			fill->prefix, name, postfix, buf, err);		\
+		return;							\
+	}								\
+	if (allset && var == allset)					\
+		return;							\
+	*val = var;							\
+}
+
+NVRAM_READ_VAL(u8)
+NVRAM_READ_VAL(s8)
+NVRAM_READ_VAL(u16)
+NVRAM_READ_VAL(u32)
+
+#undef NVRAM_READ_VAL
+
+static void nvram_read_u32_2(const struct bcm47xx_sprom_fill *fill,
+			     const char *name, u16 *val_lo, u16 *val_hi)
+{
+	char buf[100];
+	int err;
+	u32 val;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	err = kstrtou32(strim(buf), 0, &val);
+	if (err) {
+		pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+			fill->prefix, name, buf, err);
+		return;
+	}
+	*val_lo = (val & 0x0000FFFFU);
+	*val_hi = (val & 0xFFFF0000U) >> 16;
+}
+
+static void nvram_read_leddc(const struct bcm47xx_sprom_fill *fill,
+			     const char *name, u8 *leddc_on_time,
+			     u8 *leddc_off_time)
+{
+	char buf[100];
+	int err;
+	u32 val;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	err = kstrtou32(strim(buf), 0, &val);
+	if (err) {
+		pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+			fill->prefix, name, buf, err);
+		return;
+	}
+
+	if (val == 0xffff || val == 0xffffffff)
+		return;
+
+	*leddc_on_time = val & 0xff;
+	*leddc_off_time = (val >> 16) & 0xff;
+}
+
+static void nvram_read_macaddr(const struct bcm47xx_sprom_fill *fill,
+			       const char *name, u8 val[6])
+{
+	char buf[100];
+	int err;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+
+	bcm47xx_nvram_parse_macaddr(buf, val);
+}
+
+static void nvram_read_alpha2(const struct bcm47xx_sprom_fill *fill,
+			      const char *name, char val[2])
+{
+	char buf[10];
+	int err;
+
+	err = get_nvram_var(fill, NULL, name, buf, sizeof(buf));
+	if (err < 0)
+		return;
+	if (buf[0] == '0')
+		return;
+	if (strlen(buf) > 2) {
+		pr_warn("alpha2 is too long %s\n", buf);
+		return;
+	}
+	memcpy(val, buf, 2);
+}
+
+static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
+	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
+	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
+	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
+	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
+	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
+	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
+	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
+}
+
+static void bcm47xx_sprom_fill_r12389(struct ssb_sprom *sprom,
+				      const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "pa0b0", &sprom->pa0b0, 0);
+	nvram_read_u16(fill, NULL, "pa0b1", &sprom->pa0b1, 0);
+	nvram_read_u16(fill, NULL, "pa0b2", &sprom->pa0b2, 0);
+	nvram_read_u8(fill, NULL, "pa0itssit", &sprom->itssi_bg, 0);
+	nvram_read_u8(fill, NULL, "pa0maxpwr", &sprom->maxpwr_bg, 0);
+	nvram_read_u16(fill, NULL, "pa1b0", &sprom->pa1b0, 0);
+	nvram_read_u16(fill, NULL, "pa1b1", &sprom->pa1b1, 0);
+	nvram_read_u16(fill, NULL, "pa1b2", &sprom->pa1b2, 0);
+	nvram_read_u8(fill, NULL, "pa1itssit", &sprom->itssi_a, 0);
+	nvram_read_u8(fill, NULL, "pa1maxpwr", &sprom->maxpwr_a, 0);
+}
+
+static void bcm47xx_sprom_fill_r1(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "boardflags", &sprom->boardflags_lo, 0);
+	nvram_read_u8(fill, NULL, "cc", &sprom->country_code, 0);
+}
+
+static void bcm47xx_sprom_fill_r2389(struct ssb_sprom *sprom,
+				     const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "opo", &sprom->opo, 0);
+	nvram_read_u16(fill, NULL, "pa1lob0", &sprom->pa1lob0, 0);
+	nvram_read_u16(fill, NULL, "pa1lob1", &sprom->pa1lob1, 0);
+	nvram_read_u16(fill, NULL, "pa1lob2", &sprom->pa1lob2, 0);
+	nvram_read_u16(fill, NULL, "pa1hib0", &sprom->pa1hib0, 0);
+	nvram_read_u16(fill, NULL, "pa1hib1", &sprom->pa1hib1, 0);
+	nvram_read_u16(fill, NULL, "pa1hib2", &sprom->pa1hib2, 0);
+	nvram_read_u8(fill, NULL, "pa1lomaxpwr", &sprom->maxpwr_al, 0);
+	nvram_read_u8(fill, NULL, "pa1himaxpwr", &sprom->maxpwr_ah, 0);
+}
+
+static void bcm47xx_sprom_fill_r389(struct ssb_sprom *sprom,
+				    const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "bxa2g", &sprom->bxa2g, 0);
+	nvram_read_u8(fill, NULL, "rssisav2g", &sprom->rssisav2g, 0);
+	nvram_read_u8(fill, NULL, "rssismc2g", &sprom->rssismc2g, 0);
+	nvram_read_u8(fill, NULL, "rssismf2g", &sprom->rssismf2g, 0);
+	nvram_read_u8(fill, NULL, "bxa5g", &sprom->bxa5g, 0);
+	nvram_read_u8(fill, NULL, "rssisav5g", &sprom->rssisav5g, 0);
+	nvram_read_u8(fill, NULL, "rssismc5g", &sprom->rssismc5g, 0);
+	nvram_read_u8(fill, NULL, "rssismf5g", &sprom->rssismf5g, 0);
+	nvram_read_u8(fill, NULL, "tri2g", &sprom->tri2g, 0);
+	nvram_read_u8(fill, NULL, "tri5g", &sprom->tri5g, 0);
+	nvram_read_u8(fill, NULL, "tri5gl", &sprom->tri5gl, 0);
+	nvram_read_u8(fill, NULL, "tri5gh", &sprom->tri5gh, 0);
+	nvram_read_s8(fill, NULL, "rxpo2g", &sprom->rxpo2g, 0);
+	nvram_read_s8(fill, NULL, "rxpo5g", &sprom->rxpo5g, 0);
+}
+
+static void bcm47xx_sprom_fill_r3(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
+	nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
+			 &sprom->leddc_off_time);
+}
+
+static void bcm47xx_sprom_fill_r4589(struct ssb_sprom *sprom,
+				     const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "regrev", &sprom->regrev, 0);
+	nvram_read_s8(fill, NULL, "ag2", &sprom->antenna_gain.a2, 0);
+	nvram_read_s8(fill, NULL, "ag3", &sprom->antenna_gain.a3, 0);
+	nvram_read_u8(fill, NULL, "txchain", &sprom->txchain, 0xf);
+	nvram_read_u8(fill, NULL, "rxchain", &sprom->rxchain, 0xf);
+	nvram_read_u8(fill, NULL, "antswitch", &sprom->antswitch, 0xff);
+	nvram_read_leddc(fill, "leddc", &sprom->leddc_on_time,
+			 &sprom->leddc_off_time);
+}
+
+static void bcm47xx_sprom_fill_r458(struct ssb_sprom *sprom,
+				    const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "cck2gpo", &sprom->cck2gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm2gpo", &sprom->ofdm2gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5gpo", &sprom->ofdm5gpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5glpo", &sprom->ofdm5glpo, 0);
+	nvram_read_u32(fill, NULL, "ofdm5ghpo", &sprom->ofdm5ghpo, 0);
+	nvram_read_u16(fill, NULL, "cddpo", &sprom->cddpo, 0);
+	nvram_read_u16(fill, NULL, "stbcpo", &sprom->stbcpo, 0);
+	nvram_read_u16(fill, NULL, "bw40po", &sprom->bw40po, 0);
+	nvram_read_u16(fill, NULL, "bwduppo", &sprom->bwduppo, 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo0", &sprom->mcs2gpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo1", &sprom->mcs2gpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo2", &sprom->mcs2gpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo3", &sprom->mcs2gpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo4", &sprom->mcs2gpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo5", &sprom->mcs2gpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo6", &sprom->mcs2gpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs2gpo7", &sprom->mcs2gpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo0", &sprom->mcs5gpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo1", &sprom->mcs5gpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo2", &sprom->mcs5gpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo3", &sprom->mcs5gpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo4", &sprom->mcs5gpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo5", &sprom->mcs5gpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo6", &sprom->mcs5gpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5gpo7", &sprom->mcs5gpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo0", &sprom->mcs5glpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo1", &sprom->mcs5glpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo2", &sprom->mcs5glpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo3", &sprom->mcs5glpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo4", &sprom->mcs5glpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo5", &sprom->mcs5glpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo6", &sprom->mcs5glpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5glpo7", &sprom->mcs5glpo[7], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo0", &sprom->mcs5ghpo[0], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo1", &sprom->mcs5ghpo[1], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo2", &sprom->mcs5ghpo[2], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo3", &sprom->mcs5ghpo[3], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo4", &sprom->mcs5ghpo[4], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo5", &sprom->mcs5ghpo[5], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo6", &sprom->mcs5ghpo[6], 0);
+	nvram_read_u16(fill, NULL, "mcs5ghpo7", &sprom->mcs5ghpo[7], 0);
+}
+
+static void bcm47xx_sprom_fill_r45(struct ssb_sprom *sprom,
+				   const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "txpid2ga0", &sprom->txpid2g[0], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga1", &sprom->txpid2g[1], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga2", &sprom->txpid2g[2], 0);
+	nvram_read_u8(fill, NULL, "txpid2ga3", &sprom->txpid2g[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga0", &sprom->txpid5g[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga1", &sprom->txpid5g[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga2", &sprom->txpid5g[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5ga3", &sprom->txpid5g[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla0", &sprom->txpid5gl[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla1", &sprom->txpid5gl[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla2", &sprom->txpid5gl[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5gla3", &sprom->txpid5gl[3], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha0", &sprom->txpid5gh[0], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha1", &sprom->txpid5gh[1], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha2", &sprom->txpid5gh[2], 0);
+	nvram_read_u8(fill, NULL, "txpid5gha3", &sprom->txpid5gh[3], 0);
+}
+
+static void bcm47xx_sprom_fill_r89(struct ssb_sprom *sprom,
+				   const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u8(fill, NULL, "tssipos2g", &sprom->fem.ghz2.tssipos, 0);
+	nvram_read_u8(fill, NULL, "extpagain2g", &sprom->fem.ghz2.extpa_gain, 0);
+	nvram_read_u8(fill, NULL, "pdetrange2g", &sprom->fem.ghz2.pdet_range, 0);
+	nvram_read_u8(fill, NULL, "triso2g", &sprom->fem.ghz2.tr_iso, 0);
+	nvram_read_u8(fill, NULL, "antswctl2g", &sprom->fem.ghz2.antswlut, 0);
+	nvram_read_u8(fill, NULL, "tssipos5g", &sprom->fem.ghz5.tssipos, 0);
+	nvram_read_u8(fill, NULL, "extpagain5g", &sprom->fem.ghz5.extpa_gain, 0);
+	nvram_read_u8(fill, NULL, "pdetrange5g", &sprom->fem.ghz5.pdet_range, 0);
+	nvram_read_u8(fill, NULL, "triso5g", &sprom->fem.ghz5.tr_iso, 0);
+	nvram_read_u8(fill, NULL, "antswctl5g", &sprom->fem.ghz5.antswlut, 0);
+	nvram_read_u8(fill, NULL, "tempthresh", &sprom->tempthresh, 0);
+	nvram_read_u8(fill, NULL, "tempoffset", &sprom->tempoffset, 0);
+	nvram_read_u16(fill, NULL, "rawtempsense", &sprom->rawtempsense, 0);
+	nvram_read_u8(fill, NULL, "measpower", &sprom->measpower, 0);
+	nvram_read_u8(fill, NULL, "tempsense_slope", &sprom->tempsense_slope, 0);
+	nvram_read_u8(fill, NULL, "tempcorrx", &sprom->tempcorrx, 0);
+	nvram_read_u8(fill, NULL, "tempsense_option", &sprom->tempsense_option, 0);
+	nvram_read_u8(fill, NULL, "freqoffset_corr", &sprom->freqoffset_corr, 0);
+	nvram_read_u8(fill, NULL, "iqcal_swp_dis", &sprom->iqcal_swp_dis, 0);
+	nvram_read_u8(fill, NULL, "hw_iqcal_en", &sprom->hw_iqcal_en, 0);
+	nvram_read_u8(fill, NULL, "elna2g", &sprom->elna2g, 0);
+	nvram_read_u8(fill, NULL, "elna5g", &sprom->elna5g, 0);
+	nvram_read_u8(fill, NULL, "phycal_tempdelta", &sprom->phycal_tempdelta, 0);
+	nvram_read_u8(fill, NULL, "temps_period", &sprom->temps_period, 0);
+	nvram_read_u8(fill, NULL, "temps_hysteresis", &sprom->temps_hysteresis, 0);
+	nvram_read_u8(fill, NULL, "measpower1", &sprom->measpower1, 0);
+	nvram_read_u8(fill, NULL, "measpower2", &sprom->measpower2, 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga0", &sprom->rxgainerr2ga[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga1", &sprom->rxgainerr2ga[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr2ga2", &sprom->rxgainerr2ga[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla0", &sprom->rxgainerr5gla[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla1", &sprom->rxgainerr5gla[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gla2", &sprom->rxgainerr5gla[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma0", &sprom->rxgainerr5gma[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma1", &sprom->rxgainerr5gma[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gma2", &sprom->rxgainerr5gma[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha0", &sprom->rxgainerr5gha[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha1", &sprom->rxgainerr5gha[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gha2", &sprom->rxgainerr5gha[2], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua0", &sprom->rxgainerr5gua[0], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua1", &sprom->rxgainerr5gua[1], 0);
+	nvram_read_u8(fill, NULL, "rxgainerr5gua2", &sprom->rxgainerr5gua[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga0", &sprom->noiselvl2ga[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga1", &sprom->noiselvl2ga[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl2ga2", &sprom->noiselvl2ga[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla0", &sprom->noiselvl5gla[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla1", &sprom->noiselvl5gla[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gla2", &sprom->noiselvl5gla[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma0", &sprom->noiselvl5gma[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma1", &sprom->noiselvl5gma[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gma2", &sprom->noiselvl5gma[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha0", &sprom->noiselvl5gha[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha1", &sprom->noiselvl5gha[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gha2", &sprom->noiselvl5gha[2], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua0", &sprom->noiselvl5gua[0], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua1", &sprom->noiselvl5gua[1], 0);
+	nvram_read_u8(fill, NULL, "noiselvl5gua2", &sprom->noiselvl5gua[2], 0);
+	nvram_read_u8(fill, NULL, "pcieingress_war", &sprom->pcieingress_war, 0);
+}
+
+static void bcm47xx_sprom_fill_r9(struct ssb_sprom *sprom,
+				  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "cckbw202gpo", &sprom->cckbw202gpo, 0);
+	nvram_read_u16(fill, NULL, "cckbw20ul2gpo", &sprom->cckbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw202gpo", &sprom->legofdmbw202gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul2gpo", &sprom->legofdmbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205glpo", &sprom->legofdmbw205glpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5glpo", &sprom->legofdmbw20ul5glpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205gmpo", &sprom->legofdmbw205gmpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5gmpo", &sprom->legofdmbw20ul5gmpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw205ghpo", &sprom->legofdmbw205ghpo, 0);
+	nvram_read_u32(fill, NULL, "legofdmbw20ul5ghpo", &sprom->legofdmbw20ul5ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw202gpo", &sprom->mcsbw202gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul2gpo", &sprom->mcsbw20ul2gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw402gpo", &sprom->mcsbw402gpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205glpo", &sprom->mcsbw205glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5glpo", &sprom->mcsbw20ul5glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405glpo", &sprom->mcsbw405glpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205gmpo", &sprom->mcsbw205gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5gmpo", &sprom->mcsbw20ul5gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405gmpo", &sprom->mcsbw405gmpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw205ghpo", &sprom->mcsbw205ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw20ul5ghpo", &sprom->mcsbw20ul5ghpo, 0);
+	nvram_read_u32(fill, NULL, "mcsbw405ghpo", &sprom->mcsbw405ghpo, 0);
+	nvram_read_u16(fill, NULL, "mcs32po", &sprom->mcs32po, 0);
+	nvram_read_u16(fill, NULL, "legofdm40duppo", &sprom->legofdm40duppo, 0);
+	nvram_read_u8(fill, NULL, "sar2g", &sprom->sar2g, 0);
+	nvram_read_u8(fill, NULL, "sar5g", &sprom->sar5g, 0);
+}
+
+static void bcm47xx_sprom_fill_path_r4589(struct ssb_sprom *sprom,
+					  const struct bcm47xx_sprom_fill *fill)
+{
+	char postfix[2];
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+		struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+
+		snprintf(postfix, sizeof(postfix), "%i", i);
+		nvram_read_u8(fill, postfix, "maxp2ga", &pwr_info->maxpwr_2g, 0);
+		nvram_read_u8(fill, postfix, "itt2ga", &pwr_info->itssi_2g, 0);
+		nvram_read_u8(fill, postfix, "itt5ga", &pwr_info->itssi_5g, 0);
+		nvram_read_u16(fill, postfix, "pa2gw0a", &pwr_info->pa_2g[0], 0);
+		nvram_read_u16(fill, postfix, "pa2gw1a", &pwr_info->pa_2g[1], 0);
+		nvram_read_u16(fill, postfix, "pa2gw2a", &pwr_info->pa_2g[2], 0);
+		nvram_read_u8(fill, postfix, "maxp5ga", &pwr_info->maxpwr_5g, 0);
+		nvram_read_u8(fill, postfix, "maxp5gha", &pwr_info->maxpwr_5gh, 0);
+		nvram_read_u8(fill, postfix, "maxp5gla", &pwr_info->maxpwr_5gl, 0);
+		nvram_read_u16(fill, postfix, "pa5gw0a", &pwr_info->pa_5g[0], 0);
+		nvram_read_u16(fill, postfix, "pa5gw1a", &pwr_info->pa_5g[1], 0);
+		nvram_read_u16(fill, postfix, "pa5gw2a", &pwr_info->pa_5g[2], 0);
+		nvram_read_u16(fill, postfix, "pa5glw0a", &pwr_info->pa_5gl[0], 0);
+		nvram_read_u16(fill, postfix, "pa5glw1a", &pwr_info->pa_5gl[1], 0);
+		nvram_read_u16(fill, postfix, "pa5glw2a", &pwr_info->pa_5gl[2], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw0a", &pwr_info->pa_5gh[0], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw1a", &pwr_info->pa_5gh[1], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw2a", &pwr_info->pa_5gh[2], 0);
+	}
+}
+
+static void bcm47xx_sprom_fill_path_r45(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	char postfix[2];
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+		struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+
+		snprintf(postfix, sizeof(postfix), "%i", i);
+		nvram_read_u16(fill, postfix, "pa2gw3a", &pwr_info->pa_2g[3], 0);
+		nvram_read_u16(fill, postfix, "pa5gw3a", &pwr_info->pa_5g[3], 0);
+		nvram_read_u16(fill, postfix, "pa5glw3a", &pwr_info->pa_5gl[3], 0);
+		nvram_read_u16(fill, postfix, "pa5ghw3a", &pwr_info->pa_5gh[3], 0);
+	}
+}
+
+static bool bcm47xx_is_valid_mac(u8 *mac)
+{
+	return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c);
+}
+
+static int bcm47xx_increase_mac_addr(u8 *mac, u8 num)
+{
+	u8 *oui = mac + ETH_ALEN/2 - 1;
+	u8 *p = mac + ETH_ALEN - 1;
+
+	do {
+		(*p) += num;
+		if (*p > num)
+			break;
+		p--;
+		num = 1;
+	} while (p != oui);
+
+	if (p == oui) {
+		pr_err("unable to fetch mac address\n");
+		return -ENOENT;
+	}
+	return 0;
+}
+
+/*
+ * This is a global counter because different instances of sprom will
+ * access the same nvram.
+ */
+static int mac_addr_used = 2;
+
+static void bcm47xx_sprom_fill_ethernet(struct ssb_sprom *sprom,
+					const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_macaddr(fill, "et0macaddr", sprom->et0mac);
+	nvram_read_u8(fill, NULL, "et0mdcport", &sprom->et0mdcport, 0);
+	nvram_read_u8(fill, NULL, "et0phyaddr", &sprom->et0phyaddr, 0);
+
+	nvram_read_macaddr(fill, "et1macaddr", sprom->et1mac);
+	nvram_read_u8(fill, NULL, "et1mdcport", &sprom->et1mdcport, 0);
+	nvram_read_u8(fill, NULL, "et1phyaddr", &sprom->et1phyaddr, 0);
+
+	nvram_read_macaddr(fill, "macaddr", sprom->il0mac);
+	nvram_read_macaddr(fill, "il0macaddr", sprom->il0mac);
+
+	/*
+	 * The address prefix 00:90:4C is used by Broadcom in their initial
+	 * configuration. When a mac address with the prefix 00:90:4C is used
+	 * all devices from the same series are sharing the same mac address.
+	 * To prevent mac address collisions we replace them with a mac address
+	 * based on the base address.
+	 */
+	if (!bcm47xx_is_valid_mac(sprom->il0mac)) {
+		u8 mac[6];
+		struct bcm47xx_sprom_fill fill_no_prefix;
+
+		memcpy(&fill_no_prefix, fill, sizeof(fill_no_prefix));
+		fill_no_prefix.prefix = NULL;
+
+		nvram_read_macaddr(&fill_no_prefix, "et0macaddr", mac);
+		if (bcm47xx_is_valid_mac(mac)) {
+			int err = bcm47xx_increase_mac_addr(mac, mac_addr_used);
+
+			if (!err) {
+				ether_addr_copy(sprom->il0mac, mac);
+				mac_addr_used++;
+			}
+		}
+	}
+}
+
+static void bcm47xx_sprom_fill_board_data(struct ssb_sprom *sprom,
+					  const struct bcm47xx_sprom_fill *fill)
+{
+	nvram_read_u16(fill, NULL, "boardrev", &sprom->board_rev, 0);
+	nvram_read_u16(fill, NULL, "boardnum", &sprom->board_num, 0);
+	nvram_read_u16(fill, NULL, "boardtype", &sprom->board_type, 0);
+	nvram_read_u32_2(fill, "boardflags", &sprom->boardflags_lo,
+			 &sprom->boardflags_hi);
+	nvram_read_u32_2(fill, "boardflags2", &sprom->boardflags2_lo,
+			 &sprom->boardflags2_hi);
+}
+
+static void bcm47xx_sprom_fill(struct ssb_sprom *sprom,
+			       const struct bcm47xx_sprom_fill *fill)
+{
+	bcm47xx_sprom_fill_ethernet(sprom, fill);
+	bcm47xx_sprom_fill_board_data(sprom, fill);
+
+	nvram_read_u8(fill, NULL, "sromrev", &sprom->revision, 0);
+
+	switch (sprom->revision) {
+	case 1:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r1(sprom, fill);
+		break;
+	case 2:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		break;
+	case 3:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r3(sprom, fill);
+		break;
+	case 4:
+	case 5:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r458(sprom, fill);
+		bcm47xx_sprom_fill_r45(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		bcm47xx_sprom_fill_path_r45(sprom, fill);
+		break;
+	case 8:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r458(sprom, fill);
+		bcm47xx_sprom_fill_r89(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		break;
+	case 9:
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r2389(sprom, fill);
+		bcm47xx_sprom_fill_r389(sprom, fill);
+		bcm47xx_sprom_fill_r4589(sprom, fill);
+		bcm47xx_sprom_fill_r89(sprom, fill);
+		bcm47xx_sprom_fill_r9(sprom, fill);
+		bcm47xx_sprom_fill_path_r4589(sprom, fill);
+		break;
+	default:
+		pr_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
+			sprom->revision);
+		sprom->revision = 1;
+		bcm47xx_sprom_fill_r1234589(sprom, fill);
+		bcm47xx_sprom_fill_r12389(sprom, fill);
+		bcm47xx_sprom_fill_r1(sprom, fill);
+	}
+}
+
+static int bcm47xx_sprom_getenv(const struct bcm47xx_sprom_fill *fill,
+				const char *name, char *val, size_t val_len)
+{
+	const struct platform_device *nvram_dev = fill->priv;
+
+	return bcm47xx_nvram_getenv(&nvram_dev->dev, name, val, val_len);
+};
+
+static int bcm47xx_sprom_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct ssb_sprom *sprom;
+	const __be32 *handle;
+	struct device_node *nvram_node;
+	struct platform_device *nvram_dev;
+	struct bcm47xx_sprom_fill fill;
+
+	/* Alloc */
+	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
+	if (!sprom)
+		return -ENOMEM;
+
+	handle = of_get_property(np, "nvram", NULL);
+	if (!handle)
+		return -ENOMEM;
+
+	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));
+	if (!nvram_node)
+		return -ENOMEM;
+
+	nvram_dev = of_find_device_by_node(nvram_node);
+	if (!nvram_dev)
+		return -ENOMEM;
+
+	fill.prefix = of_get_property(np, "prefix", NULL);
+
+	fill.fallback = false;
+	fill.getenv = bcm47xx_sprom_getenv;
+	fill.priv = nvram_dev;
+
+	bcm47xx_sprom_fill(sprom, &fill);
+
+	platform_set_drvdata(pdev, sprom);
+
+	return 0;
+}
+
+static const struct of_device_id bcm47xx_sprom_of_match_table[] = {
+	{ .compatible = "brcm,bcm47xx-sprom", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver bcm47xx_sprom_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "bcm47xx-sprom",
+		.of_match_table = bcm47xx_sprom_of_match_table,
+		/* driver unloading/unbinding currently not supported */
+		.suppress_bind_attrs = true,
+	},
+	.probe = bcm47xx_sprom_probe,
+};
+module_platform_driver(bcm47xx_sprom_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 4/7] bcma: register bcma as device tree driver
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

This driver is used by the bcm53xx ARM SoC code. Now it is possible to
give the address of the chipcommon core in device tree and bcma will
search for all the other cores.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
 drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
 include/linux/bcma/bcma.h                      |  2 +
 3 files changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt

diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
new file mode 100644
index 0000000..52fb929
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/bcma.txt
@@ -0,0 +1,46 @@
+Broadcom AIX bcma bus driver
+
+
+Required properties:
+
+- compatible : brcm,bus-aix
+
+- reg : iomem address range of chipcommon core
+
+Optional properties:
+
+- sprom: reference to a sprom driver. This is needed for sprom less devices.
+	 Use bcm47xx_sprom for example.
+
+
+The cores on the AIX bus are auto detected by bcma. Detection of the
+IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
+possible to provide the IRQ number over device tree. The IRQ number and
+the device tree child entry will be added to the core with the matching
+reg address.
+
+Example:
+
+	aix@18000000 {
+		compatible = "brcm,bus-aix";
+		reg = <0x18000000 0x1000>;
+		ranges = <0x00000000 0x18000000 0x00100000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		sprom = <&sprom0>;
+
+		gmac@0 {
+			reg = <0x18024000 0x1000>;
+			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@1 {
+			reg = <0x18025000 0x1000>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie@0 {
+			reg = <0x18012000 0x1000>;
+			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 3475e60..d009bc9 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -7,6 +7,9 @@
 
 #include "bcma_private.h"
 #include "scan.h"
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
 #include <linux/bcma/bcma.h>
 #include <linux/bcma/bcma_soc.h>
 
@@ -173,6 +176,7 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
 	/* Host specific */
 	bus->hosttype = BCMA_HOSTTYPE_SOC;
 	bus->ops = &bcma_host_soc_ops;
+	bus->host_pdev = NULL;
 
 	/* Register */
 	err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
@@ -181,3 +185,69 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
 
 	return err;
 }
+
+#ifdef CONFIG_OF
+static int bcma_host_soc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct bcma_bus *bus;
+	int err;
+
+	/* Alloc */
+	bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return -ENOMEM;
+
+	/* Map MMIO */
+	bus->mmio = of_iomap(np, 0);
+	if (!bus->mmio)
+		return -ENOMEM;
+
+	/* Host specific */
+	bus->hosttype = BCMA_HOSTTYPE_SOC;
+	bus->ops = &bcma_host_soc_ops;
+	bus->host_pdev = pdev;
+
+	/* Register */
+	err = bcma_bus_register(bus);
+	if (err)
+		goto err_unmap_mmio;
+
+	platform_set_drvdata(pdev, bus);
+
+	return err;
+
+err_unmap_mmio:
+	iounmap(bus->mmio);
+	return err;
+}
+
+static int bcma_host_soc_remove(struct platform_device *pdev)
+{
+	struct bcma_bus *bus = platform_get_drvdata(pdev);
+
+	bcma_bus_unregister(bus);
+	iounmap(bus->mmio);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id bcma_host_soc_of_match[] = {
+	{ .compatible = "brcm,bus-aix", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match);
+
+static struct platform_driver bcma_host_soc_driver = {
+	.driver = {
+		.name = "bcma-host-soc",
+		.owner = THIS_MODULE,
+		.of_match_table = bcma_host_soc_of_match,
+	},
+	.probe		= bcma_host_soc_probe,
+	.remove		= bcma_host_soc_remove,
+};
+module_platform_driver(bcma_host_soc_driver);
+#endif /* CONFIG_OF */
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 0272e49..7a10d6d 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -323,6 +323,8 @@ struct bcma_bus {
 		struct pci_dev *host_pci;
 		/* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
 		struct sdio_func *host_sdio;
+		/* Pointer to platform device (only for BCMA_HOSTTYPE_SOC) */
+		struct platform_device *host_pdev;
 	};
 
 	struct bcma_chipinfo chipinfo;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 4/7] bcma: register bcma as device tree driver
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

This driver is used by the bcm53xx ARM SoC code. Now it is possible to
give the address of the chipcommon core in device tree and bcma will
search for all the other cores.

Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
---
 Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
 drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
 include/linux/bcma/bcma.h                      |  2 +
 3 files changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt

diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
new file mode 100644
index 0000000..52fb929
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/bcma.txt
@@ -0,0 +1,46 @@
+Broadcom AIX bcma bus driver
+
+
+Required properties:
+
+- compatible : brcm,bus-aix
+
+- reg : iomem address range of chipcommon core
+
+Optional properties:
+
+- sprom: reference to a sprom driver. This is needed for sprom less devices.
+	 Use bcm47xx_sprom for example.
+
+
+The cores on the AIX bus are auto detected by bcma. Detection of the
+IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
+possible to provide the IRQ number over device tree. The IRQ number and
+the device tree child entry will be added to the core with the matching
+reg address.
+
+Example:
+
+	aix@18000000 {
+		compatible = "brcm,bus-aix";
+		reg = <0x18000000 0x1000>;
+		ranges = <0x00000000 0x18000000 0x00100000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		sprom = <&sprom0>;
+
+		gmac@0 {
+			reg = <0x18024000 0x1000>;
+			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@1 {
+			reg = <0x18025000 0x1000>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie@0 {
+			reg = <0x18012000 0x1000>;
+			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 3475e60..d009bc9 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -7,6 +7,9 @@
 
 #include "bcma_private.h"
 #include "scan.h"
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
 #include <linux/bcma/bcma.h>
 #include <linux/bcma/bcma_soc.h>
 
@@ -173,6 +176,7 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
 	/* Host specific */
 	bus->hosttype = BCMA_HOSTTYPE_SOC;
 	bus->ops = &bcma_host_soc_ops;
+	bus->host_pdev = NULL;
 
 	/* Register */
 	err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
@@ -181,3 +185,69 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
 
 	return err;
 }
+
+#ifdef CONFIG_OF
+static int bcma_host_soc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct bcma_bus *bus;
+	int err;
+
+	/* Alloc */
+	bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return -ENOMEM;
+
+	/* Map MMIO */
+	bus->mmio = of_iomap(np, 0);
+	if (!bus->mmio)
+		return -ENOMEM;
+
+	/* Host specific */
+	bus->hosttype = BCMA_HOSTTYPE_SOC;
+	bus->ops = &bcma_host_soc_ops;
+	bus->host_pdev = pdev;
+
+	/* Register */
+	err = bcma_bus_register(bus);
+	if (err)
+		goto err_unmap_mmio;
+
+	platform_set_drvdata(pdev, bus);
+
+	return err;
+
+err_unmap_mmio:
+	iounmap(bus->mmio);
+	return err;
+}
+
+static int bcma_host_soc_remove(struct platform_device *pdev)
+{
+	struct bcma_bus *bus = platform_get_drvdata(pdev);
+
+	bcma_bus_unregister(bus);
+	iounmap(bus->mmio);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id bcma_host_soc_of_match[] = {
+	{ .compatible = "brcm,bus-aix", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match);
+
+static struct platform_driver bcma_host_soc_driver = {
+	.driver = {
+		.name = "bcma-host-soc",
+		.owner = THIS_MODULE,
+		.of_match_table = bcma_host_soc_of_match,
+	},
+	.probe		= bcma_host_soc_probe,
+	.remove		= bcma_host_soc_remove,
+};
+module_platform_driver(bcma_host_soc_driver);
+#endif /* CONFIG_OF */
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 0272e49..7a10d6d 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -323,6 +323,8 @@ struct bcma_bus {
 		struct pci_dev *host_pci;
 		/* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
 		struct sdio_func *host_sdio;
+		/* Pointer to platform device (only for BCMA_HOSTTYPE_SOC) */
+		struct platform_device *host_pdev;
 	};
 
 	struct bcma_chipinfo chipinfo;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 4/7] bcma: register bcma as device tree driver
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

This driver is used by the bcm53xx ARM SoC code. Now it is possible to
give the address of the chipcommon core in device tree and bcma will
search for all the other cores.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
 drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
 include/linux/bcma/bcma.h                      |  2 +
 3 files changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt

diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
new file mode 100644
index 0000000..52fb929
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/bcma.txt
@@ -0,0 +1,46 @@
+Broadcom AIX bcma bus driver
+
+
+Required properties:
+
+- compatible : brcm,bus-aix
+
+- reg : iomem address range of chipcommon core
+
+Optional properties:
+
+- sprom: reference to a sprom driver. This is needed for sprom less devices.
+	 Use bcm47xx_sprom for example.
+
+
+The cores on the AIX bus are auto detected by bcma. Detection of the
+IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
+possible to provide the IRQ number over device tree. The IRQ number and
+the device tree child entry will be added to the core with the matching
+reg address.
+
+Example:
+
+	aix at 18000000 {
+		compatible = "brcm,bus-aix";
+		reg = <0x18000000 0x1000>;
+		ranges = <0x00000000 0x18000000 0x00100000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		sprom = <&sprom0>;
+
+		gmac at 0 {
+			reg = <0x18024000 0x1000>;
+			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac at 1 {
+			reg = <0x18025000 0x1000>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie at 0 {
+			reg = <0x18012000 0x1000>;
+			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 3475e60..d009bc9 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -7,6 +7,9 @@
 
 #include "bcma_private.h"
 #include "scan.h"
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
 #include <linux/bcma/bcma.h>
 #include <linux/bcma/bcma_soc.h>
 
@@ -173,6 +176,7 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
 	/* Host specific */
 	bus->hosttype = BCMA_HOSTTYPE_SOC;
 	bus->ops = &bcma_host_soc_ops;
+	bus->host_pdev = NULL;
 
 	/* Register */
 	err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
@@ -181,3 +185,69 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
 
 	return err;
 }
+
+#ifdef CONFIG_OF
+static int bcma_host_soc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct bcma_bus *bus;
+	int err;
+
+	/* Alloc */
+	bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return -ENOMEM;
+
+	/* Map MMIO */
+	bus->mmio = of_iomap(np, 0);
+	if (!bus->mmio)
+		return -ENOMEM;
+
+	/* Host specific */
+	bus->hosttype = BCMA_HOSTTYPE_SOC;
+	bus->ops = &bcma_host_soc_ops;
+	bus->host_pdev = pdev;
+
+	/* Register */
+	err = bcma_bus_register(bus);
+	if (err)
+		goto err_unmap_mmio;
+
+	platform_set_drvdata(pdev, bus);
+
+	return err;
+
+err_unmap_mmio:
+	iounmap(bus->mmio);
+	return err;
+}
+
+static int bcma_host_soc_remove(struct platform_device *pdev)
+{
+	struct bcma_bus *bus = platform_get_drvdata(pdev);
+
+	bcma_bus_unregister(bus);
+	iounmap(bus->mmio);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id bcma_host_soc_of_match[] = {
+	{ .compatible = "brcm,bus-aix", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match);
+
+static struct platform_driver bcma_host_soc_driver = {
+	.driver = {
+		.name = "bcma-host-soc",
+		.owner = THIS_MODULE,
+		.of_match_table = bcma_host_soc_of_match,
+	},
+	.probe		= bcma_host_soc_probe,
+	.remove		= bcma_host_soc_remove,
+};
+module_platform_driver(bcma_host_soc_driver);
+#endif /* CONFIG_OF */
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 0272e49..7a10d6d 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -323,6 +323,8 @@ struct bcma_bus {
 		struct pci_dev *host_pci;
 		/* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
 		struct sdio_func *host_sdio;
+		/* Pointer to platform device (only for BCMA_HOSTTYPE_SOC) */
+		struct platform_device *host_pdev;
 	};
 
 	struct bcma_chipinfo chipinfo;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 5/7] bcma: get IRQ numbers from dt
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

It is not possible to auto detect the irq numbers used by the cores on
an arm SoC. If bcma was registered with device tree it will search for
some device tree nodes with the irq number and add it to the core
configuration.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/main.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 0ff8d58..3f75776 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -10,6 +10,8 @@
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 #include <linux/slab.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
 MODULE_LICENSE("GPL");
@@ -120,6 +122,38 @@ static void bcma_release_core_dev(struct device *dev)
 	kfree(core);
 }
 
+static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
+						     struct bcma_device *core)
+{
+	struct device_node *node;
+	u64 size;
+	const __be32 *reg;
+
+	if (!parent || !parent->dev.of_node)
+		return NULL;
+
+	for_each_child_of_node(parent->dev.of_node, node) {
+		reg = of_get_address(node, 0, &size, NULL);
+		if (!reg)
+			continue;
+		if (be32_to_cpup(reg) == core->addr)
+			return node;
+	}
+	return NULL;
+}
+
+static void bcma_of_fill_device(struct platform_device *parent,
+				struct bcma_device *core)
+{
+	struct device_node *node;
+
+	node = bcma_of_find_child_device(parent, core);
+	if (!node)
+		return;
+	core->dev.of_node = node;
+	core->irq = irq_of_parse_and_map(node, 0);
+}
+
 static int bcma_register_cores(struct bcma_bus *bus)
 {
 	struct bcma_device *core;
@@ -155,7 +189,13 @@ static int bcma_register_cores(struct bcma_bus *bus)
 			break;
 		case BCMA_HOSTTYPE_SOC:
 			core->dev.dma_mask = &core->dev.coherent_dma_mask;
-			core->dma_dev = &core->dev;
+			if (bus->host_pdev) {
+				core->dma_dev = &bus->host_pdev->dev;
+				core->dev.parent = &bus->host_pdev->dev;
+				bcma_of_fill_device(bus->host_pdev, core);
+			} else {
+				core->dma_dev = &core->dev;
+			}
 			break;
 		case BCMA_HOSTTYPE_SDIO:
 			break;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 5/7] bcma: get IRQ numbers from dt
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

It is not possible to auto detect the irq numbers used by the cores on
an arm SoC. If bcma was registered with device tree it will search for
some device tree nodes with the irq number and add it to the core
configuration.

Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
---
 drivers/bcma/main.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 0ff8d58..3f75776 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -10,6 +10,8 @@
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 #include <linux/slab.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
 MODULE_LICENSE("GPL");
@@ -120,6 +122,38 @@ static void bcma_release_core_dev(struct device *dev)
 	kfree(core);
 }
 
+static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
+						     struct bcma_device *core)
+{
+	struct device_node *node;
+	u64 size;
+	const __be32 *reg;
+
+	if (!parent || !parent->dev.of_node)
+		return NULL;
+
+	for_each_child_of_node(parent->dev.of_node, node) {
+		reg = of_get_address(node, 0, &size, NULL);
+		if (!reg)
+			continue;
+		if (be32_to_cpup(reg) == core->addr)
+			return node;
+	}
+	return NULL;
+}
+
+static void bcma_of_fill_device(struct platform_device *parent,
+				struct bcma_device *core)
+{
+	struct device_node *node;
+
+	node = bcma_of_find_child_device(parent, core);
+	if (!node)
+		return;
+	core->dev.of_node = node;
+	core->irq = irq_of_parse_and_map(node, 0);
+}
+
 static int bcma_register_cores(struct bcma_bus *bus)
 {
 	struct bcma_device *core;
@@ -155,7 +189,13 @@ static int bcma_register_cores(struct bcma_bus *bus)
 			break;
 		case BCMA_HOSTTYPE_SOC:
 			core->dev.dma_mask = &core->dev.coherent_dma_mask;
-			core->dma_dev = &core->dev;
+			if (bus->host_pdev) {
+				core->dma_dev = &bus->host_pdev->dev;
+				core->dev.parent = &bus->host_pdev->dev;
+				bcma_of_fill_device(bus->host_pdev, core);
+			} else {
+				core->dma_dev = &core->dev;
+			}
 			break;
 		case BCMA_HOSTTYPE_SDIO:
 			break;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 5/7] bcma: get IRQ numbers from dt
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

It is not possible to auto detect the irq numbers used by the cores on
an arm SoC. If bcma was registered with device tree it will search for
some device tree nodes with the irq number and add it to the core
configuration.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/main.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 0ff8d58..3f75776 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -10,6 +10,8 @@
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 #include <linux/slab.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
 MODULE_LICENSE("GPL");
@@ -120,6 +122,38 @@ static void bcma_release_core_dev(struct device *dev)
 	kfree(core);
 }
 
+static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
+						     struct bcma_device *core)
+{
+	struct device_node *node;
+	u64 size;
+	const __be32 *reg;
+
+	if (!parent || !parent->dev.of_node)
+		return NULL;
+
+	for_each_child_of_node(parent->dev.of_node, node) {
+		reg = of_get_address(node, 0, &size, NULL);
+		if (!reg)
+			continue;
+		if (be32_to_cpup(reg) == core->addr)
+			return node;
+	}
+	return NULL;
+}
+
+static void bcma_of_fill_device(struct platform_device *parent,
+				struct bcma_device *core)
+{
+	struct device_node *node;
+
+	node = bcma_of_find_child_device(parent, core);
+	if (!node)
+		return;
+	core->dev.of_node = node;
+	core->irq = irq_of_parse_and_map(node, 0);
+}
+
 static int bcma_register_cores(struct bcma_bus *bus)
 {
 	struct bcma_device *core;
@@ -155,7 +189,13 @@ static int bcma_register_cores(struct bcma_bus *bus)
 			break;
 		case BCMA_HOSTTYPE_SOC:
 			core->dev.dma_mask = &core->dev.coherent_dma_mask;
-			core->dma_dev = &core->dev;
+			if (bus->host_pdev) {
+				core->dma_dev = &bus->host_pdev->dev;
+				core->dev.parent = &bus->host_pdev->dev;
+				bcma_of_fill_device(bus->host_pdev, core);
+			} else {
+				core->dma_dev = &core->dev;
+			}
 			break;
 		case BCMA_HOSTTYPE_SDIO:
 			break;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 6/7] bcma: get sprom from devicetree
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

This patch make it possible to device an sprom provider in device tree
and get the sprom from this driver. Every time there is such a provider
it gets asked for a sprom.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/sprom.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index efb037f..ebe495d 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -15,6 +15,8 @@
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
 
@@ -46,6 +48,46 @@ int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
+				   struct ssb_sprom *out)
+{
+	const __be32 *handle;
+	struct device_node *sprom_node;
+	struct platform_device *sprom_dev;
+	struct ssb_sprom *sprom;
+
+	if (!bus->host_pdev || !bus->host_pdev->dev.of_node)
+		return -ENOENT;
+
+	handle = of_get_property(bus->host_pdev->dev.of_node, "sprom", NULL);
+	if (!handle)
+		return -ENOENT;
+
+	sprom_node = of_find_node_by_phandle(be32_to_cpup(handle));
+	if (!sprom_node)
+		return -ENOENT;
+
+	sprom_dev = of_find_device_by_node(sprom_node);
+	if (!sprom_dev)
+		return -ENOENT;
+
+	sprom = platform_get_drvdata(sprom_dev);
+	if (!sprom)
+		return -ENOENT;
+
+	memcpy(out, sprom, sizeof(*out));
+
+	return 0;
+}
+#else
+static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
+				   struct ssb_sprom *out)
+{
+	return -ENOENT;
+}
+#endif
+
 static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
 					 struct ssb_sprom *out)
 {
@@ -580,7 +622,14 @@ int bcma_sprom_get(struct bcma_bus *bus)
 	u16 *sprom;
 	size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
 				 SSB_SPROMSIZE_WORDS_R10, };
-	int i, err = 0;
+	int i, err;
+
+	err = bcma_fill_sprom_with_dt(bus, &bus->sprom);
+	if (err == 0) {
+		bcma_info(bus, "Found sprom from device tree provider\n");
+		return 0;
+	}
+	err = 0;
 
 	if (!bus->drv_cc.core)
 		return -EOPNOTSUPP;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 6/7] bcma: get sprom from devicetree
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

This patch make it possible to device an sprom provider in device tree
and get the sprom from this driver. Every time there is such a provider
it gets asked for a sprom.

Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
---
 drivers/bcma/sprom.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index efb037f..ebe495d 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -15,6 +15,8 @@
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
 
@@ -46,6 +48,46 @@ int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
+				   struct ssb_sprom *out)
+{
+	const __be32 *handle;
+	struct device_node *sprom_node;
+	struct platform_device *sprom_dev;
+	struct ssb_sprom *sprom;
+
+	if (!bus->host_pdev || !bus->host_pdev->dev.of_node)
+		return -ENOENT;
+
+	handle = of_get_property(bus->host_pdev->dev.of_node, "sprom", NULL);
+	if (!handle)
+		return -ENOENT;
+
+	sprom_node = of_find_node_by_phandle(be32_to_cpup(handle));
+	if (!sprom_node)
+		return -ENOENT;
+
+	sprom_dev = of_find_device_by_node(sprom_node);
+	if (!sprom_dev)
+		return -ENOENT;
+
+	sprom = platform_get_drvdata(sprom_dev);
+	if (!sprom)
+		return -ENOENT;
+
+	memcpy(out, sprom, sizeof(*out));
+
+	return 0;
+}
+#else
+static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
+				   struct ssb_sprom *out)
+{
+	return -ENOENT;
+}
+#endif
+
 static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
 					 struct ssb_sprom *out)
 {
@@ -580,7 +622,14 @@ int bcma_sprom_get(struct bcma_bus *bus)
 	u16 *sprom;
 	size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
 				 SSB_SPROMSIZE_WORDS_R10, };
-	int i, err = 0;
+	int i, err;
+
+	err = bcma_fill_sprom_with_dt(bus, &bus->sprom);
+	if (err == 0) {
+		bcma_info(bus, "Found sprom from device tree provider\n");
+		return 0;
+	}
+	err = 0;
 
 	if (!bus->drv_cc.core)
 		return -EOPNOTSUPP;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 6/7] bcma: get sprom from devicetree
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

This patch make it possible to device an sprom provider in device tree
and get the sprom from this driver. Every time there is such a provider
it gets asked for a sprom.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/bcma/sprom.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index efb037f..ebe495d 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -15,6 +15,8 @@
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out);
 
@@ -46,6 +48,46 @@ int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
+				   struct ssb_sprom *out)
+{
+	const __be32 *handle;
+	struct device_node *sprom_node;
+	struct platform_device *sprom_dev;
+	struct ssb_sprom *sprom;
+
+	if (!bus->host_pdev || !bus->host_pdev->dev.of_node)
+		return -ENOENT;
+
+	handle = of_get_property(bus->host_pdev->dev.of_node, "sprom", NULL);
+	if (!handle)
+		return -ENOENT;
+
+	sprom_node = of_find_node_by_phandle(be32_to_cpup(handle));
+	if (!sprom_node)
+		return -ENOENT;
+
+	sprom_dev = of_find_device_by_node(sprom_node);
+	if (!sprom_dev)
+		return -ENOENT;
+
+	sprom = platform_get_drvdata(sprom_dev);
+	if (!sprom)
+		return -ENOENT;
+
+	memcpy(out, sprom, sizeof(*out));
+
+	return 0;
+}
+#else
+static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
+				   struct ssb_sprom *out)
+{
+	return -ENOENT;
+}
+#endif
+
 static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
 					 struct ssb_sprom *out)
 {
@@ -580,7 +622,14 @@ int bcma_sprom_get(struct bcma_bus *bus)
 	u16 *sprom;
 	size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
 				 SSB_SPROMSIZE_WORDS_R10, };
-	int i, err = 0;
+	int i, err;
+
+	err = bcma_fill_sprom_with_dt(bus, &bus->sprom);
+	if (err == 0) {
+		bcma_info(bus, "Found sprom from device tree provider\n");
+		return 0;
+	}
+	err = 0;
 
 	if (!bus->drv_cc.core)
 		return -EOPNOTSUPP;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 7/7] ARM: BCM5301X: register bcma bus
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5, Hauke Mehrtens

---
 arch/arm/boot/dts/bcm4708.dtsi | 58 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
index 31141e8..7c240ab 100644
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -31,4 +31,62 @@
 		};
 	};
 
+	nvram0: nvram@0 {
+		compatible = "brcm,bcm47xx-nvram";
+		reg = <0x1c000000 0x01000000>;
+	};
+
+	sprom0: sprom@0 {
+		compatible = "brcm,bcm47xx-sprom";
+		nvram = <&nvram0>;
+	};
+
+	aix@18000000 {
+		compatible = "brcm,bus-aix";
+		reg = <0x18000000 0x1000>;
+		ranges = <0x00000000 0x18000000 0x00100000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		sprom = <&sprom0>;
+
+		usb2@0 {
+			reg = <0x18021000 0x1000>;
+			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		usb3@0 {
+			reg = <0x18023000 0x1000>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@0 {
+			reg = <0x18024000 0x1000>;
+			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@1 {
+			reg = <0x18025000 0x1000>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@2 {
+			reg = <0x18026000 0x1000>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@3 {
+			reg = <0x18027000 0x1000>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie@0 {
+			reg = <0x18012000 0x1000>;
+			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie@1 {
+			reg = <0x18013000 0x1000>;
+			interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
 };
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 7/7] ARM: BCM5301X: register bcma bus
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w, Hauke Mehrtens

---
 arch/arm/boot/dts/bcm4708.dtsi | 58 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
index 31141e8..7c240ab 100644
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -31,4 +31,62 @@
 		};
 	};
 
+	nvram0: nvram@0 {
+		compatible = "brcm,bcm47xx-nvram";
+		reg = <0x1c000000 0x01000000>;
+	};
+
+	sprom0: sprom@0 {
+		compatible = "brcm,bcm47xx-sprom";
+		nvram = <&nvram0>;
+	};
+
+	aix@18000000 {
+		compatible = "brcm,bus-aix";
+		reg = <0x18000000 0x1000>;
+		ranges = <0x00000000 0x18000000 0x00100000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		sprom = <&sprom0>;
+
+		usb2@0 {
+			reg = <0x18021000 0x1000>;
+			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		usb3@0 {
+			reg = <0x18023000 0x1000>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@0 {
+			reg = <0x18024000 0x1000>;
+			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@1 {
+			reg = <0x18025000 0x1000>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@2 {
+			reg = <0x18026000 0x1000>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac@3 {
+			reg = <0x18027000 0x1000>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie@0 {
+			reg = <0x18012000 0x1000>;
+			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie@1 {
+			reg = <0x18013000 0x1000>;
+			interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
 };
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [RFC 7/7] ARM: BCM5301X: register bcma bus
@ 2014-08-24 21:24   ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-24 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

---
 arch/arm/boot/dts/bcm4708.dtsi | 58 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
index 31141e8..7c240ab 100644
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -31,4 +31,62 @@
 		};
 	};
 
+	nvram0: nvram at 0 {
+		compatible = "brcm,bcm47xx-nvram";
+		reg = <0x1c000000 0x01000000>;
+	};
+
+	sprom0: sprom at 0 {
+		compatible = "brcm,bcm47xx-sprom";
+		nvram = <&nvram0>;
+	};
+
+	aix at 18000000 {
+		compatible = "brcm,bus-aix";
+		reg = <0x18000000 0x1000>;
+		ranges = <0x00000000 0x18000000 0x00100000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		sprom = <&sprom0>;
+
+		usb2 at 0 {
+			reg = <0x18021000 0x1000>;
+			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		usb3 at 0 {
+			reg = <0x18023000 0x1000>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac at 0 {
+			reg = <0x18024000 0x1000>;
+			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac at 1 {
+			reg = <0x18025000 0x1000>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac at 2 {
+			reg = <0x18026000 0x1000>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		gmac at 3 {
+			reg = <0x18027000 0x1000>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie at 0 {
+			reg = <0x18012000 0x1000>;
+			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pcie at 1 {
+			reg = <0x18013000 0x1000>;
+			interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-24 21:45     ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-24 21:45 UTC (permalink / raw)
  To: Hauke Mehrtens; +Cc: linux-wireless, devicetree, linux-arm-kernel, linux-mips

On 24 August 2014 21:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> This was copied from arch/mips/bcm47xx/nvram.c and modified to interact
> with device tree. My plan is to make the MIPS bcm47xx also use this new
> driver some time later.

I don't like this.

First, you change API (_getenv call), without explanation why/if we
really need this. We decided we're very unlikely to ever find devices
with multiple (separated) NVRAMs. So what's the point of having nvram
per device?

Secondly, don't duplicate the code. If you're going to switch bcm47xx
to this new code, handle it smarter. Modify bcm47xx mode, move it to
the "misc" and re-use in bcm53xx.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-24 21:45     ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-24 21:45 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA

On 24 August 2014 21:24, Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org> wrote:
> This was copied from arch/mips/bcm47xx/nvram.c and modified to interact
> with device tree. My plan is to make the MIPS bcm47xx also use this new
> driver some time later.

I don't like this.

First, you change API (_getenv call), without explanation why/if we
really need this. We decided we're very unlikely to ever find devices
with multiple (separated) NVRAMs. So what's the point of having nvram
per device?

Secondly, don't duplicate the code. If you're going to switch bcm47xx
to this new code, handle it smarter. Modify bcm47xx mode, move it to
the "misc" and re-use in bcm53xx.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-24 21:45     ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-24 21:45 UTC (permalink / raw)
  To: Hauke Mehrtens; +Cc: linux-wireless, devicetree, linux-arm-kernel, linux-mips

On 24 August 2014 21:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> This was copied from arch/mips/bcm47xx/nvram.c and modified to interact
> with device tree. My plan is to make the MIPS bcm47xx also use this new
> driver some time later.

I don't like this.

First, you change API (_getenv call), without explanation why/if we
really need this. We decided we're very unlikely to ever find devices
with multiple (separated) NVRAMs. So what's the point of having nvram
per device?

Secondly, don't duplicate the code. If you're going to switch bcm47xx
to this new code, handle it smarter. Modify bcm47xx mode, move it to
the "misc" and re-use in bcm53xx.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-24 21:45     ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-24 21:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 24 August 2014 21:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> This was copied from arch/mips/bcm47xx/nvram.c and modified to interact
> with device tree. My plan is to make the MIPS bcm47xx also use this new
> driver some time later.

I don't like this.

First, you change API (_getenv call), without explanation why/if we
really need this. We decided we're very unlikely to ever find devices
with multiple (separated) NVRAMs. So what's the point of having nvram
per device?

Secondly, don't duplicate the code. If you're going to switch bcm47xx
to this new code, handle it smarter. Modify bcm47xx mode, move it to
the "misc" and re-use in bcm53xx.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-25  7:52     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  7:52 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Hauke Mehrtens, linux-wireless, devicetree, linux-mips, zajec5

On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
> This driver needs an nvram driver and fetches the sprom values from the
> nvram and provides it to any other driver. The calibration data for the
> wifi chip the mac address and some more board description data is
> stores in the sprom.
> 
> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
> make the bcm47xx MIPS SoCs also use this driver some time later.

> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> ---
>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +

I'd prefer not to list the binding in a 'misc' category. Maybe we can
have a new category and move the misc/sram.txt into the same?

>  drivers/misc/Kconfig                               |  14 +
>  drivers/misc/Makefile                              |   1 +
>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++

On a similar note, putting the driver into drivers/misc seems
suboptimal: misc drivers should by definition be something that
is for some odd hardware with no external dependencies on it,
whereas your driver seems to be used by multiple other drivers.

Would it make sense to put it into drivers/bcma when that is the
only bus it is used on?

>  4 files changed, 721 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>  create mode 100644 drivers/misc/bcm47xx-sprom.c
> 
> diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
> new file mode 100644
> index 0000000..eed2a4a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
> @@ -0,0 +1,16 @@
> +Broadcom bcm47xx/bcm53xx sprom converter
> +
> +This driver provbides an sprom based on a given nvram.
> +
> +Required properties:
> +
> +- compatible : brcm,bcm47xx-sprom

Please use a specific SoC here as the compatible string, not something
with 'x' in it as a wildcard.


> +#define NVRAM_READ_VAL(type)						\
> +static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
> +				 const char *postfix, const char *name, \
> +				 type *val, type allset)		\
> +{									\
> +	char buf[100];							\
> +	int err;							\
> +	type var;							\
> +									\
> +	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
> +	if (err < 0)							\
> +		return;							\
> +	err = kstrto ## type(strim(buf), 0, &var);			\
> +	if (err) {							\
> +		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
> +			fill->prefix, name, postfix, buf, err);		\
> +		return;							\
> +	}								\
> +	if (allset && var == allset)					\
> +		return;							\
> +	*val = var;							\
> +}
> +
> +NVRAM_READ_VAL(u8)
> +NVRAM_READ_VAL(s8)
> +NVRAM_READ_VAL(u16)
> +NVRAM_READ_VAL(u32)
> +
> +#undef NVRAM_READ_VAL

Hmm, multiline macros are ugly. How about using one function to read
into an s64 internally using kstrtoll, and simple inline wrappers around
that for the smaller types, doing the appropriate range check?

> +static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
> +					const struct bcm47xx_sprom_fill *fill)
> +{
> +	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
> +	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
> +	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
> +	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
> +	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
> +	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
> +	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
> +}

Rather than calling the same set of functions multiple times, can you
do this using a table driven approach for smaller code size and
improved readability?

> +static int bcm47xx_sprom_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct ssb_sprom *sprom;
> +	const __be32 *handle;
> +	struct device_node *nvram_node;
> +	struct platform_device *nvram_dev;
> +	struct bcm47xx_sprom_fill fill;
> +
> +	/* Alloc */
> +	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
> +	if (!sprom)
> +		return -ENOMEM;
> +
> +	handle = of_get_property(np, "nvram", NULL);
> +	if (!handle)
> +		return -ENOMEM;
> +
> +	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));

You can avoid the explicit be32_to_cpup here if you use
of_property_read_u32 above.

	Arnd

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-25  7:52     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  7:52 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Hauke Mehrtens, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA, zajec5-Re5JQEeQqe8AvxtiuMwx3w

On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
> This driver needs an nvram driver and fetches the sprom values from the
> nvram and provides it to any other driver. The calibration data for the
> wifi chip the mac address and some more board description data is
> stores in the sprom.
> 
> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
> make the bcm47xx MIPS SoCs also use this driver some time later.

> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
> ---
>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +

I'd prefer not to list the binding in a 'misc' category. Maybe we can
have a new category and move the misc/sram.txt into the same?

>  drivers/misc/Kconfig                               |  14 +
>  drivers/misc/Makefile                              |   1 +
>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++

On a similar note, putting the driver into drivers/misc seems
suboptimal: misc drivers should by definition be something that
is for some odd hardware with no external dependencies on it,
whereas your driver seems to be used by multiple other drivers.

Would it make sense to put it into drivers/bcma when that is the
only bus it is used on?

>  4 files changed, 721 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>  create mode 100644 drivers/misc/bcm47xx-sprom.c
> 
> diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
> new file mode 100644
> index 0000000..eed2a4a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
> @@ -0,0 +1,16 @@
> +Broadcom bcm47xx/bcm53xx sprom converter
> +
> +This driver provbides an sprom based on a given nvram.
> +
> +Required properties:
> +
> +- compatible : brcm,bcm47xx-sprom

Please use a specific SoC here as the compatible string, not something
with 'x' in it as a wildcard.


> +#define NVRAM_READ_VAL(type)						\
> +static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
> +				 const char *postfix, const char *name, \
> +				 type *val, type allset)		\
> +{									\
> +	char buf[100];							\
> +	int err;							\
> +	type var;							\
> +									\
> +	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
> +	if (err < 0)							\
> +		return;							\
> +	err = kstrto ## type(strim(buf), 0, &var);			\
> +	if (err) {							\
> +		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
> +			fill->prefix, name, postfix, buf, err);		\
> +		return;							\
> +	}								\
> +	if (allset && var == allset)					\
> +		return;							\
> +	*val = var;							\
> +}
> +
> +NVRAM_READ_VAL(u8)
> +NVRAM_READ_VAL(s8)
> +NVRAM_READ_VAL(u16)
> +NVRAM_READ_VAL(u32)
> +
> +#undef NVRAM_READ_VAL

Hmm, multiline macros are ugly. How about using one function to read
into an s64 internally using kstrtoll, and simple inline wrappers around
that for the smaller types, doing the appropriate range check?

> +static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
> +					const struct bcm47xx_sprom_fill *fill)
> +{
> +	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
> +	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
> +	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
> +	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
> +	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
> +	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
> +	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
> +}

Rather than calling the same set of functions multiple times, can you
do this using a table driven approach for smaller code size and
improved readability?

> +static int bcm47xx_sprom_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct ssb_sprom *sprom;
> +	const __be32 *handle;
> +	struct device_node *nvram_node;
> +	struct platform_device *nvram_dev;
> +	struct bcm47xx_sprom_fill fill;
> +
> +	/* Alloc */
> +	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
> +	if (!sprom)
> +		return -ENOMEM;
> +
> +	handle = of_get_property(np, "nvram", NULL);
> +	if (!handle)
> +		return -ENOMEM;
> +
> +	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));

You can avoid the explicit be32_to_cpup here if you use
of_property_read_u32 above.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-25  7:52     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
> This driver needs an nvram driver and fetches the sprom values from the
> nvram and provides it to any other driver. The calibration data for the
> wifi chip the mac address and some more board description data is
> stores in the sprom.
> 
> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
> make the bcm47xx MIPS SoCs also use this driver some time later.

> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> ---
>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +

I'd prefer not to list the binding in a 'misc' category. Maybe we can
have a new category and move the misc/sram.txt into the same?

>  drivers/misc/Kconfig                               |  14 +
>  drivers/misc/Makefile                              |   1 +
>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++

On a similar note, putting the driver into drivers/misc seems
suboptimal: misc drivers should by definition be something that
is for some odd hardware with no external dependencies on it,
whereas your driver seems to be used by multiple other drivers.

Would it make sense to put it into drivers/bcma when that is the
only bus it is used on?

>  4 files changed, 721 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>  create mode 100644 drivers/misc/bcm47xx-sprom.c
> 
> diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
> new file mode 100644
> index 0000000..eed2a4a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
> @@ -0,0 +1,16 @@
> +Broadcom bcm47xx/bcm53xx sprom converter
> +
> +This driver provbides an sprom based on a given nvram.
> +
> +Required properties:
> +
> +- compatible : brcm,bcm47xx-sprom

Please use a specific SoC here as the compatible string, not something
with 'x' in it as a wildcard.


> +#define NVRAM_READ_VAL(type)						\
> +static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
> +				 const char *postfix, const char *name, \
> +				 type *val, type allset)		\
> +{									\
> +	char buf[100];							\
> +	int err;							\
> +	type var;							\
> +									\
> +	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
> +	if (err < 0)							\
> +		return;							\
> +	err = kstrto ## type(strim(buf), 0, &var);			\
> +	if (err) {							\
> +		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
> +			fill->prefix, name, postfix, buf, err);		\
> +		return;							\
> +	}								\
> +	if (allset && var == allset)					\
> +		return;							\
> +	*val = var;							\
> +}
> +
> +NVRAM_READ_VAL(u8)
> +NVRAM_READ_VAL(s8)
> +NVRAM_READ_VAL(u16)
> +NVRAM_READ_VAL(u32)
> +
> +#undef NVRAM_READ_VAL

Hmm, multiline macros are ugly. How about using one function to read
into an s64 internally using kstrtoll, and simple inline wrappers around
that for the smaller types, doing the appropriate range check?

> +static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
> +					const struct bcm47xx_sprom_fill *fill)
> +{
> +	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
> +	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
> +	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
> +	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
> +	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
> +	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
> +	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
> +	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
> +}

Rather than calling the same set of functions multiple times, can you
do this using a table driven approach for smaller code size and
improved readability?

> +static int bcm47xx_sprom_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct ssb_sprom *sprom;
> +	const __be32 *handle;
> +	struct device_node *nvram_node;
> +	struct platform_device *nvram_dev;
> +	struct bcm47xx_sprom_fill fill;
> +
> +	/* Alloc */
> +	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
> +	if (!sprom)
> +		return -ENOMEM;
> +
> +	handle = of_get_property(np, "nvram", NULL);
> +	if (!handle)
> +		return -ENOMEM;
> +
> +	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));

You can avoid the explicit be32_to_cpup here if you use
of_property_read_u32 above.

	Arnd

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 4/7] bcma: register bcma as device tree driver
@ 2014-08-25  7:57     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  7:57 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Hauke Mehrtens, linux-wireless, devicetree, linux-mips, zajec5

On Sunday 24 August 2014 23:24:42 Hauke Mehrtens wrote:
> This driver is used by the bcm53xx ARM SoC code. Now it is possible to
> give the address of the chipcommon core in device tree and bcma will
> search for all the other cores.
> 
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

Looks good to me overall. Two small comments:

>  Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
>  drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
>  include/linux/bcma/bcma.h                      |  2 +
>  3 files changed, 118 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
> 
> diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
> new file mode 100644
> index 0000000..52fb929
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/bus/bcma.txt
> @@ -0,0 +1,46 @@
> +Broadcom AIX bcma bus driver
> +
> +
> +Required properties:
> +
> +- compatible : brcm,bus-aix
> +
> +- reg : iomem address range of chipcommon core
> +
> +Optional properties:
> +
> +- sprom: reference to a sprom driver. This is needed for sprom less devices.
> +        Use bcm47xx_sprom for example.
> +
> +
> +The cores on the AIX bus are auto detected by bcma. Detection of the
> +IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
> +possible to provide the IRQ number over device tree. The IRQ number and
> +the device tree child entry will be added to the core with the matching
> +reg address.

What is the problem with the interrupt numbers? Is that information
missing completely from the data available to the brcm bus, or is it
in an inconvenient format?

> +Example:
> +
> +       aix@18000000 {
> +               compatible = "brcm,bus-aix";
> +               reg = <0x18000000 0x1000>;
> +               ranges = <0x00000000 0x18000000 0x00100000>;
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               sprom = <&sprom0>;
> +
> +               gmac@0 {
> +                       reg = <0x18024000 0x1000>;
> +                       interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
> +               };

The @0 part seems wrong here: the address should generally match
the first entry in the reg property, which would be gmac@18024000.

Also, you probably mean ethernet@ not gmac@.

> +               gmac@1 {
> +                       reg = <0x18025000 0x1000>;
> +                       interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +               };
> +
> +               pcie@0 {
> +                       reg = <0x18012000 0x1000>;
> +                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> +               };
> +       };

We may require additional properties for the pcie node, depending on whether
we want to use the DT probing interfaces for it, or whether it should just
hardcode the settings used on brcm based on the ID.

	Arnd


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 4/7] bcma: register bcma as device tree driver
@ 2014-08-25  7:57     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  7:57 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Hauke Mehrtens, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA, zajec5-Re5JQEeQqe8AvxtiuMwx3w

On Sunday 24 August 2014 23:24:42 Hauke Mehrtens wrote:
> This driver is used by the bcm53xx ARM SoC code. Now it is possible to
> give the address of the chipcommon core in device tree and bcma will
> search for all the other cores.
> 
> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>

Looks good to me overall. Two small comments:

>  Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
>  drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
>  include/linux/bcma/bcma.h                      |  2 +
>  3 files changed, 118 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
> 
> diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
> new file mode 100644
> index 0000000..52fb929
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/bus/bcma.txt
> @@ -0,0 +1,46 @@
> +Broadcom AIX bcma bus driver
> +
> +
> +Required properties:
> +
> +- compatible : brcm,bus-aix
> +
> +- reg : iomem address range of chipcommon core
> +
> +Optional properties:
> +
> +- sprom: reference to a sprom driver. This is needed for sprom less devices.
> +        Use bcm47xx_sprom for example.
> +
> +
> +The cores on the AIX bus are auto detected by bcma. Detection of the
> +IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
> +possible to provide the IRQ number over device tree. The IRQ number and
> +the device tree child entry will be added to the core with the matching
> +reg address.

What is the problem with the interrupt numbers? Is that information
missing completely from the data available to the brcm bus, or is it
in an inconvenient format?

> +Example:
> +
> +       aix@18000000 {
> +               compatible = "brcm,bus-aix";
> +               reg = <0x18000000 0x1000>;
> +               ranges = <0x00000000 0x18000000 0x00100000>;
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               sprom = <&sprom0>;
> +
> +               gmac@0 {
> +                       reg = <0x18024000 0x1000>;
> +                       interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
> +               };

The @0 part seems wrong here: the address should generally match
the first entry in the reg property, which would be gmac@18024000.

Also, you probably mean ethernet@ not gmac@.

> +               gmac@1 {
> +                       reg = <0x18025000 0x1000>;
> +                       interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +               };
> +
> +               pcie@0 {
> +                       reg = <0x18012000 0x1000>;
> +                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> +               };
> +       };

We may require additional properties for the pcie node, depending on whether
we want to use the DT probing interfaces for it, or whether it should just
hardcode the settings used on brcm based on the ID.

	Arnd

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 4/7] bcma: register bcma as device tree driver
@ 2014-08-25  7:57     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  7:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday 24 August 2014 23:24:42 Hauke Mehrtens wrote:
> This driver is used by the bcm53xx ARM SoC code. Now it is possible to
> give the address of the chipcommon core in device tree and bcma will
> search for all the other cores.
> 
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

Looks good to me overall. Two small comments:

>  Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
>  drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
>  include/linux/bcma/bcma.h                      |  2 +
>  3 files changed, 118 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
> 
> diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
> new file mode 100644
> index 0000000..52fb929
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/bus/bcma.txt
> @@ -0,0 +1,46 @@
> +Broadcom AIX bcma bus driver
> +
> +
> +Required properties:
> +
> +- compatible : brcm,bus-aix
> +
> +- reg : iomem address range of chipcommon core
> +
> +Optional properties:
> +
> +- sprom: reference to a sprom driver. This is needed for sprom less devices.
> +        Use bcm47xx_sprom for example.
> +
> +
> +The cores on the AIX bus are auto detected by bcma. Detection of the
> +IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
> +possible to provide the IRQ number over device tree. The IRQ number and
> +the device tree child entry will be added to the core with the matching
> +reg address.

What is the problem with the interrupt numbers? Is that information
missing completely from the data available to the brcm bus, or is it
in an inconvenient format?

> +Example:
> +
> +       aix at 18000000 {
> +               compatible = "brcm,bus-aix";
> +               reg = <0x18000000 0x1000>;
> +               ranges = <0x00000000 0x18000000 0x00100000>;
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               sprom = <&sprom0>;
> +
> +               gmac at 0 {
> +                       reg = <0x18024000 0x1000>;
> +                       interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
> +               };

The @0 part seems wrong here: the address should generally match
the first entry in the reg property, which would be gmac at 18024000.

Also, you probably mean ethernet@ not gmac at .

> +               gmac at 1 {
> +                       reg = <0x18025000 0x1000>;
> +                       interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +               };
> +
> +               pcie at 0 {
> +                       reg = <0x18012000 0x1000>;
> +                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> +               };
> +       };

We may require additional properties for the pcie node, depending on whether
we want to use the DT probing interfaces for it, or whether it should just
hardcode the settings used on brcm based on the ID.

	Arnd

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 5/7] bcma: get IRQ numbers from dt
@ 2014-08-25  8:00     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  8:00 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: linux-wireless, devicetree, linux-arm-kernel, linux-mips, zajec5

On Sunday 24 August 2014 23:24:43 Hauke Mehrtens wrote:
> It is not possible to auto detect the irq numbers used by the cores on
> an arm SoC. If bcma was registered with device tree it will search for
> some device tree nodes with the irq number and add it to the core
> configuration.
> 
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> 

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 5/7] bcma: get IRQ numbers from dt
@ 2014-08-25  8:00     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  8:00 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA, zajec5-Re5JQEeQqe8AvxtiuMwx3w

On Sunday 24 August 2014 23:24:43 Hauke Mehrtens wrote:
> It is not possible to auto detect the irq numbers used by the cores on
> an arm SoC. If bcma was registered with device tree it will search for
> some device tree nodes with the irq number and add it to the core
> configuration.
> 
> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
> 

Acked-by: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 5/7] bcma: get IRQ numbers from dt
@ 2014-08-25  8:00     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  8:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday 24 August 2014 23:24:43 Hauke Mehrtens wrote:
> It is not possible to auto detect the irq numbers used by the cores on
> an arm SoC. If bcma was registered with device tree it will search for
> some device tree nodes with the irq number and add it to the core
> configuration.
> 
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> 

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 6/7] bcma: get sprom from devicetree
@ 2014-08-25  8:04     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  8:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Hauke Mehrtens, linux-wireless, devicetree, linux-mips, zajec5

On Sunday 24 August 2014 23:24:44 Hauke Mehrtens wrote:
> +#ifdef CONFIG_OF
> +static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
> +                                  struct ssb_sprom *out)
> +{
> +       const __be32 *handle;
> +       struct device_node *sprom_node;
> +       struct platform_device *sprom_dev;
> +       struct ssb_sprom *sprom;
> +
> +       if (!bus->host_pdev || !bus->host_pdev->dev.of_node)
> +               return -ENOENT;

You can remove the #ifdef above if you change this into

	if (!IS_ENABLED(CONFIG_OF) || !bus->host_pdev ||
	    !bus->host_pdev->dev.of_node)
		return -ENOENT;

> +       handle = of_get_property(bus->host_pdev->dev.of_node, "sprom", NULL);
> +       if (!handle)
> +               return -ENOENT;
> +
> +       sprom_node = of_find_node_by_phandle(be32_to_cpup(handle));
> +       if (!sprom_node)
> +               return -ENOENT;
> +
> +       sprom_dev = of_find_device_by_node(sprom_node);
> +       if (!sprom_dev)
> +               return -ENOENT;
> +
> +       sprom = platform_get_drvdata(sprom_dev);
> +       if (!sprom)
> +               return -ENOENT;
> +
> +       memcpy(out, sprom, sizeof(*out));
> +
> +       return 0;
> +}

missing of_node_put().

	Arnd

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 6/7] bcma: get sprom from devicetree
@ 2014-08-25  8:04     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  8:04 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Hauke Mehrtens, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA, zajec5-Re5JQEeQqe8AvxtiuMwx3w

On Sunday 24 August 2014 23:24:44 Hauke Mehrtens wrote:
> +#ifdef CONFIG_OF
> +static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
> +                                  struct ssb_sprom *out)
> +{
> +       const __be32 *handle;
> +       struct device_node *sprom_node;
> +       struct platform_device *sprom_dev;
> +       struct ssb_sprom *sprom;
> +
> +       if (!bus->host_pdev || !bus->host_pdev->dev.of_node)
> +               return -ENOENT;

You can remove the #ifdef above if you change this into

	if (!IS_ENABLED(CONFIG_OF) || !bus->host_pdev ||
	    !bus->host_pdev->dev.of_node)
		return -ENOENT;

> +       handle = of_get_property(bus->host_pdev->dev.of_node, "sprom", NULL);
> +       if (!handle)
> +               return -ENOENT;
> +
> +       sprom_node = of_find_node_by_phandle(be32_to_cpup(handle));
> +       if (!sprom_node)
> +               return -ENOENT;
> +
> +       sprom_dev = of_find_device_by_node(sprom_node);
> +       if (!sprom_dev)
> +               return -ENOENT;
> +
> +       sprom = platform_get_drvdata(sprom_dev);
> +       if (!sprom)
> +               return -ENOENT;
> +
> +       memcpy(out, sprom, sizeof(*out));
> +
> +       return 0;
> +}

missing of_node_put().

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 6/7] bcma: get sprom from devicetree
@ 2014-08-25  8:04     ` Arnd Bergmann
  0 siblings, 0 replies; 70+ messages in thread
From: Arnd Bergmann @ 2014-08-25  8:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday 24 August 2014 23:24:44 Hauke Mehrtens wrote:
> +#ifdef CONFIG_OF
> +static int bcma_fill_sprom_with_dt(struct bcma_bus *bus,
> +                                  struct ssb_sprom *out)
> +{
> +       const __be32 *handle;
> +       struct device_node *sprom_node;
> +       struct platform_device *sprom_dev;
> +       struct ssb_sprom *sprom;
> +
> +       if (!bus->host_pdev || !bus->host_pdev->dev.of_node)
> +               return -ENOENT;

You can remove the #ifdef above if you change this into

	if (!IS_ENABLED(CONFIG_OF) || !bus->host_pdev ||
	    !bus->host_pdev->dev.of_node)
		return -ENOENT;

> +       handle = of_get_property(bus->host_pdev->dev.of_node, "sprom", NULL);
> +       if (!handle)
> +               return -ENOENT;
> +
> +       sprom_node = of_find_node_by_phandle(be32_to_cpup(handle));
> +       if (!sprom_node)
> +               return -ENOENT;
> +
> +       sprom_dev = of_find_device_by_node(sprom_node);
> +       if (!sprom_dev)
> +               return -ENOENT;
> +
> +       sprom = platform_get_drvdata(sprom_dev);
> +       if (!sprom)
> +               return -ENOENT;
> +
> +       memcpy(out, sprom, sizeof(*out));
> +
> +       return 0;
> +}

missing of_node_put().

	Arnd

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
  2014-08-25  7:52     ` Arnd Bergmann
  (?)
@ 2014-08-25 15:01       ` Jonas Gorski
  -1 siblings, 0 replies; 70+ messages in thread
From: Jonas Gorski @ 2014-08-25 15:01 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Hauke Mehrtens, linux-wireless, devicetree,
	MIPS Mailing List, Rafał Miłecki

On Mon, Aug 25, 2014 at 9:52 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>> This driver needs an nvram driver and fetches the sprom values from the
>> nvram and provides it to any other driver. The calibration data for the
>> wifi chip the mac address and some more board description data is
>> stores in the sprom.
>>
>> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
>> make the bcm47xx MIPS SoCs also use this driver some time later.
>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>> ---
>>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
>
> I'd prefer not to list the binding in a 'misc' category. Maybe we can
> have a new category and move the misc/sram.txt into the same?
>
>>  drivers/misc/Kconfig                               |  14 +
>>  drivers/misc/Makefile                              |   1 +
>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
>
> On a similar note, putting the driver into drivers/misc seems
> suboptimal: misc drivers should by definition be something that
> is for some odd hardware with no external dependencies on it,
> whereas your driver seems to be used by multiple other drivers.
>
> Would it make sense to put it into drivers/bcma when that is the
> only bus it is used on?

If the driver will be used for bcm47xx/mips, it will be used for two
busses, bcma and ssb, so it will need to be at a common
location.


Jonas

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-25 15:01       ` Jonas Gorski
  0 siblings, 0 replies; 70+ messages in thread
From: Jonas Gorski @ 2014-08-25 15:01 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Hauke Mehrtens, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, MIPS Mailing List,
	Rafał Miłecki

On Mon, Aug 25, 2014 at 9:52 AM, Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> wrote:
> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>> This driver needs an nvram driver and fetches the sprom values from the
>> nvram and provides it to any other driver. The calibration data for the
>> wifi chip the mac address and some more board description data is
>> stores in the sprom.
>>
>> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
>> make the bcm47xx MIPS SoCs also use this driver some time later.
>
>> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
>> ---
>>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
>
> I'd prefer not to list the binding in a 'misc' category. Maybe we can
> have a new category and move the misc/sram.txt into the same?
>
>>  drivers/misc/Kconfig                               |  14 +
>>  drivers/misc/Makefile                              |   1 +
>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
>
> On a similar note, putting the driver into drivers/misc seems
> suboptimal: misc drivers should by definition be something that
> is for some odd hardware with no external dependencies on it,
> whereas your driver seems to be used by multiple other drivers.
>
> Would it make sense to put it into drivers/bcma when that is the
> only bus it is used on?

If the driver will be used for bcm47xx/mips, it will be used for two
busses, bcma and ssb, so it will need to be at a common
location.


Jonas
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-25 15:01       ` Jonas Gorski
  0 siblings, 0 replies; 70+ messages in thread
From: Jonas Gorski @ 2014-08-25 15:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Aug 25, 2014 at 9:52 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>> This driver needs an nvram driver and fetches the sprom values from the
>> nvram and provides it to any other driver. The calibration data for the
>> wifi chip the mac address and some more board description data is
>> stores in the sprom.
>>
>> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
>> make the bcm47xx MIPS SoCs also use this driver some time later.
>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>> ---
>>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
>
> I'd prefer not to list the binding in a 'misc' category. Maybe we can
> have a new category and move the misc/sram.txt into the same?
>
>>  drivers/misc/Kconfig                               |  14 +
>>  drivers/misc/Makefile                              |   1 +
>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
>
> On a similar note, putting the driver into drivers/misc seems
> suboptimal: misc drivers should by definition be something that
> is for some odd hardware with no external dependencies on it,
> whereas your driver seems to be used by multiple other drivers.
>
> Would it make sense to put it into drivers/bcma when that is the
> only bus it is used on?

If the driver will be used for bcm47xx/mips, it will be used for two
busses, bcma and ssb, so it will need to be at a common
location.


Jonas

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 4/7] bcma: register bcma as device tree driver
  2014-08-25  7:57     ` Arnd Bergmann
  (?)
@ 2014-08-26 21:25       ` Hauke Mehrtens
  -1 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-26 21:25 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel
  Cc: linux-wireless, devicetree, linux-mips, zajec5

On 08/25/2014 09:57 AM, Arnd Bergmann wrote:
> On Sunday 24 August 2014 23:24:42 Hauke Mehrtens wrote:
>> This driver is used by the bcm53xx ARM SoC code. Now it is possible to
>> give the address of the chipcommon core in device tree and bcma will
>> search for all the other cores.
>>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> 
> Looks good to me overall. Two small comments:
> 
>>  Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
>>  drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
>>  include/linux/bcma/bcma.h                      |  2 +
>>  3 files changed, 118 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
>>
>> diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
>> new file mode 100644
>> index 0000000..52fb929
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/bus/bcma.txt
>> @@ -0,0 +1,46 @@
>> +Broadcom AIX bcma bus driver
>> +
>> +
>> +Required properties:
>> +
>> +- compatible : brcm,bus-aix
>> +
>> +- reg : iomem address range of chipcommon core
>> +
>> +Optional properties:
>> +
>> +- sprom: reference to a sprom driver. This is needed for sprom less devices.
>> +        Use bcm47xx_sprom for example.
>> +
>> +
>> +The cores on the AIX bus are auto detected by bcma. Detection of the
>> +IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
>> +possible to provide the IRQ number over device tree. The IRQ number and
>> +the device tree child entry will be added to the core with the matching
>> +reg address.
> 
> What is the problem with the interrupt numbers? Is that information
> missing completely from the data available to the brcm bus, or is it
> in an inconvenient format?

I do not have access to the datasheet, only to the vendor source code.
The irq numbers are hard coded in the vendor code, see:
https://github.com/RMerl/asuswrt-merlin/blob/master/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/arm/plat-brcm/bcm5301x_pcie.c#L286

On the mips SoCs it was possible to read them from some register in the
mips core on the aix bus.

> 
>> +Example:
>> +
>> +       aix@18000000 {
>> +               compatible = "brcm,bus-aix";
>> +               reg = <0x18000000 0x1000>;
>> +               ranges = <0x00000000 0x18000000 0x00100000>;
>> +               #address-cells = <1>;
>> +               #size-cells = <1>;
>> +               sprom = <&sprom0>;
>> +
>> +               gmac@0 {
>> +                       reg = <0x18024000 0x1000>;
>> +                       interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
> 
> The @0 part seems wrong here: the address should generally match
> the first entry in the reg property, which would be gmac@18024000.
> 
> Also, you probably mean ethernet@ not gmac@.

Will change that.

>> +               gmac@1 {
>> +                       reg = <0x18025000 0x1000>;
>> +                       interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
>> +
>> +               pcie@0 {
>> +                       reg = <0x18012000 0x1000>;
>> +                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
>> +       };
> 
> We may require additional properties for the pcie node, depending on whether
> we want to use the DT probing interfaces for it, or whether it should just
> hardcode the settings used on brcm based on the ID.

I wrote a driver for the PCIe host controller and it also automatically
detects all needed memory addresses, it just had to provide the IRQ
number through device tree.

> 
> 	Arnd
> 


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 4/7] bcma: register bcma as device tree driver
@ 2014-08-26 21:25       ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-26 21:25 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA, zajec5-Re5JQEeQqe8AvxtiuMwx3w

On 08/25/2014 09:57 AM, Arnd Bergmann wrote:
> On Sunday 24 August 2014 23:24:42 Hauke Mehrtens wrote:
>> This driver is used by the bcm53xx ARM SoC code. Now it is possible to
>> give the address of the chipcommon core in device tree and bcma will
>> search for all the other cores.
>>
>> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
> 
> Looks good to me overall. Two small comments:
> 
>>  Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
>>  drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
>>  include/linux/bcma/bcma.h                      |  2 +
>>  3 files changed, 118 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
>>
>> diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
>> new file mode 100644
>> index 0000000..52fb929
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/bus/bcma.txt
>> @@ -0,0 +1,46 @@
>> +Broadcom AIX bcma bus driver
>> +
>> +
>> +Required properties:
>> +
>> +- compatible : brcm,bus-aix
>> +
>> +- reg : iomem address range of chipcommon core
>> +
>> +Optional properties:
>> +
>> +- sprom: reference to a sprom driver. This is needed for sprom less devices.
>> +        Use bcm47xx_sprom for example.
>> +
>> +
>> +The cores on the AIX bus are auto detected by bcma. Detection of the
>> +IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
>> +possible to provide the IRQ number over device tree. The IRQ number and
>> +the device tree child entry will be added to the core with the matching
>> +reg address.
> 
> What is the problem with the interrupt numbers? Is that information
> missing completely from the data available to the brcm bus, or is it
> in an inconvenient format?

I do not have access to the datasheet, only to the vendor source code.
The irq numbers are hard coded in the vendor code, see:
https://github.com/RMerl/asuswrt-merlin/blob/master/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/arm/plat-brcm/bcm5301x_pcie.c#L286

On the mips SoCs it was possible to read them from some register in the
mips core on the aix bus.

> 
>> +Example:
>> +
>> +       aix@18000000 {
>> +               compatible = "brcm,bus-aix";
>> +               reg = <0x18000000 0x1000>;
>> +               ranges = <0x00000000 0x18000000 0x00100000>;
>> +               #address-cells = <1>;
>> +               #size-cells = <1>;
>> +               sprom = <&sprom0>;
>> +
>> +               gmac@0 {
>> +                       reg = <0x18024000 0x1000>;
>> +                       interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
> 
> The @0 part seems wrong here: the address should generally match
> the first entry in the reg property, which would be gmac@18024000.
> 
> Also, you probably mean ethernet@ not gmac@.

Will change that.

>> +               gmac@1 {
>> +                       reg = <0x18025000 0x1000>;
>> +                       interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
>> +
>> +               pcie@0 {
>> +                       reg = <0x18012000 0x1000>;
>> +                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
>> +       };
> 
> We may require additional properties for the pcie node, depending on whether
> we want to use the DT probing interfaces for it, or whether it should just
> hardcode the settings used on brcm based on the ID.

I wrote a driver for the PCIe host controller and it also automatically
detects all needed memory addresses, it just had to provide the IRQ
number through device tree.

> 
> 	Arnd
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 4/7] bcma: register bcma as device tree driver
@ 2014-08-26 21:25       ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-26 21:25 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/25/2014 09:57 AM, Arnd Bergmann wrote:
> On Sunday 24 August 2014 23:24:42 Hauke Mehrtens wrote:
>> This driver is used by the bcm53xx ARM SoC code. Now it is possible to
>> give the address of the chipcommon core in device tree and bcma will
>> search for all the other cores.
>>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> 
> Looks good to me overall. Two small comments:
> 
>>  Documentation/devicetree/bindings/bus/bcma.txt | 46 +++++++++++++++++
>>  drivers/bcma/host_soc.c                        | 70 ++++++++++++++++++++++++++
>>  include/linux/bcma/bcma.h                      |  2 +
>>  3 files changed, 118 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/bus/bcma.txt
>>
>> diff --git a/Documentation/devicetree/bindings/bus/bcma.txt b/Documentation/devicetree/bindings/bus/bcma.txt
>> new file mode 100644
>> index 0000000..52fb929
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/bus/bcma.txt
>> @@ -0,0 +1,46 @@
>> +Broadcom AIX bcma bus driver
>> +
>> +
>> +Required properties:
>> +
>> +- compatible : brcm,bus-aix
>> +
>> +- reg : iomem address range of chipcommon core
>> +
>> +Optional properties:
>> +
>> +- sprom: reference to a sprom driver. This is needed for sprom less devices.
>> +        Use bcm47xx_sprom for example.
>> +
>> +
>> +The cores on the AIX bus are auto detected by bcma. Detection of the
>> +IRQ number is not supported on BCM47xx/BCM53xx ARM SoCs, so it is
>> +possible to provide the IRQ number over device tree. The IRQ number and
>> +the device tree child entry will be added to the core with the matching
>> +reg address.
> 
> What is the problem with the interrupt numbers? Is that information
> missing completely from the data available to the brcm bus, or is it
> in an inconvenient format?

I do not have access to the datasheet, only to the vendor source code.
The irq numbers are hard coded in the vendor code, see:
https://github.com/RMerl/asuswrt-merlin/blob/master/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/arm/plat-brcm/bcm5301x_pcie.c#L286

On the mips SoCs it was possible to read them from some register in the
mips core on the aix bus.

> 
>> +Example:
>> +
>> +       aix at 18000000 {
>> +               compatible = "brcm,bus-aix";
>> +               reg = <0x18000000 0x1000>;
>> +               ranges = <0x00000000 0x18000000 0x00100000>;
>> +               #address-cells = <1>;
>> +               #size-cells = <1>;
>> +               sprom = <&sprom0>;
>> +
>> +               gmac at 0 {
>> +                       reg = <0x18024000 0x1000>;
>> +                       interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
> 
> The @0 part seems wrong here: the address should generally match
> the first entry in the reg property, which would be gmac at 18024000.
> 
> Also, you probably mean ethernet@ not gmac at .

Will change that.

>> +               gmac at 1 {
>> +                       reg = <0x18025000 0x1000>;
>> +                       interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
>> +
>> +               pcie at 0 {
>> +                       reg = <0x18012000 0x1000>;
>> +                       interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
>> +               };
>> +       };
> 
> We may require additional properties for the pcie node, depending on whether
> we want to use the DT probing interfaces for it, or whether it should just
> hardcode the settings used on brcm based on the ID.

I wrote a driver for the PCIe host controller and it also automatically
detects all needed memory addresses, it just had to provide the IRQ
number through device tree.

> 
> 	Arnd
> 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
  2014-08-25  7:52     ` Arnd Bergmann
  (?)
@ 2014-08-26 21:32       ` Hauke Mehrtens
  -1 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-26 21:32 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel
  Cc: linux-wireless, devicetree, linux-mips, zajec5

On 08/25/2014 09:52 AM, Arnd Bergmann wrote:
> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>> This driver needs an nvram driver and fetches the sprom values from the
>> nvram and provides it to any other driver. The calibration data for the
>> wifi chip the mac address and some more board description data is
>> stores in the sprom.
>>
>> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
>> make the bcm47xx MIPS SoCs also use this driver some time later.
> 
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>> ---
>>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
> 
> I'd prefer not to list the binding in a 'misc' category. Maybe we can
> have a new category and move the misc/sram.txt into the same?
> 
>>  drivers/misc/Kconfig                               |  14 +
>>  drivers/misc/Makefile                              |   1 +
>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
> 
> On a similar note, putting the driver into drivers/misc seems
> suboptimal: misc drivers should by definition be something that
> is for some odd hardware with no external dependencies on it,
> whereas your driver seems to be used by multiple other drivers.
> 
> Would it make sense to put it into drivers/bcma when that is the
> only bus it is used on?

As Jonas already said this code should be used for the bcm53xx ARM code
and the bcm47xx MIPS code and it is needed for drivers/bcma/ and
drivers/ssb/ (ssb only for old mips devices). Do you have any better
idea than putting this to drivers/misc/ ? For the mips SoC we need the
code very early and will not use the driver interface but probably
directly call the function name.
> 
>>  4 files changed, 721 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>>  create mode 100644 drivers/misc/bcm47xx-sprom.c
>>
>> diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>> new file mode 100644
>> index 0000000..eed2a4a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>> @@ -0,0 +1,16 @@
>> +Broadcom bcm47xx/bcm53xx sprom converter
>> +
>> +This driver provbides an sprom based on a given nvram.
>> +
>> +Required properties:
>> +
>> +- compatible : brcm,bcm47xx-sprom
> 
> Please use a specific SoC here as the compatible string, not something
> with 'x' in it as a wildcard.

I will change that.

> 
>> +#define NVRAM_READ_VAL(type)						\
>> +static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
>> +				 const char *postfix, const char *name, \
>> +				 type *val, type allset)		\
>> +{									\
>> +	char buf[100];							\
>> +	int err;							\
>> +	type var;							\
>> +									\
>> +	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
>> +	if (err < 0)							\
>> +		return;							\
>> +	err = kstrto ## type(strim(buf), 0, &var);			\
>> +	if (err) {							\
>> +		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
>> +			fill->prefix, name, postfix, buf, err);		\
>> +		return;							\
>> +	}								\
>> +	if (allset && var == allset)					\
>> +		return;							\
>> +	*val = var;							\
>> +}
>> +
>> +NVRAM_READ_VAL(u8)
>> +NVRAM_READ_VAL(s8)
>> +NVRAM_READ_VAL(u16)
>> +NVRAM_READ_VAL(u32)
>> +
>> +#undef NVRAM_READ_VAL
> 
> Hmm, multiline macros are ugly. How about using one function to read
> into an s64 internally using kstrtoll, and simple inline wrappers around
> that for the smaller types, doing the appropriate range check?

Yes that should work I will try it.

>> +static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
>> +					const struct bcm47xx_sprom_fill *fill)
>> +{
>> +	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
>> +	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
>> +	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
>> +	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
>> +	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
>> +	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
>> +	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
>> +}
> 
> Rather than calling the same set of functions multiple times, can you
> do this using a table driven approach for smaller code size and
> improved readability?

I will try to change that.

>> +static int bcm47xx_sprom_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *np = dev->of_node;
>> +	struct ssb_sprom *sprom;
>> +	const __be32 *handle;
>> +	struct device_node *nvram_node;
>> +	struct platform_device *nvram_dev;
>> +	struct bcm47xx_sprom_fill fill;
>> +
>> +	/* Alloc */
>> +	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
>> +	if (!sprom)
>> +		return -ENOMEM;
>> +
>> +	handle = of_get_property(np, "nvram", NULL);
>> +	if (!handle)
>> +		return -ENOMEM;
>> +
>> +	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));
> 
> You can avoid the explicit be32_to_cpup here if you use
> of_property_read_u32 above.

Thanks for the hint.

Hauke


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-26 21:32       ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-26 21:32 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA, zajec5-Re5JQEeQqe8AvxtiuMwx3w

On 08/25/2014 09:52 AM, Arnd Bergmann wrote:
> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>> This driver needs an nvram driver and fetches the sprom values from the
>> nvram and provides it to any other driver. The calibration data for the
>> wifi chip the mac address and some more board description data is
>> stores in the sprom.
>>
>> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
>> make the bcm47xx MIPS SoCs also use this driver some time later.
> 
>> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
>> ---
>>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
> 
> I'd prefer not to list the binding in a 'misc' category. Maybe we can
> have a new category and move the misc/sram.txt into the same?
> 
>>  drivers/misc/Kconfig                               |  14 +
>>  drivers/misc/Makefile                              |   1 +
>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
> 
> On a similar note, putting the driver into drivers/misc seems
> suboptimal: misc drivers should by definition be something that
> is for some odd hardware with no external dependencies on it,
> whereas your driver seems to be used by multiple other drivers.
> 
> Would it make sense to put it into drivers/bcma when that is the
> only bus it is used on?

As Jonas already said this code should be used for the bcm53xx ARM code
and the bcm47xx MIPS code and it is needed for drivers/bcma/ and
drivers/ssb/ (ssb only for old mips devices). Do you have any better
idea than putting this to drivers/misc/ ? For the mips SoC we need the
code very early and will not use the driver interface but probably
directly call the function name.
> 
>>  4 files changed, 721 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>>  create mode 100644 drivers/misc/bcm47xx-sprom.c
>>
>> diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>> new file mode 100644
>> index 0000000..eed2a4a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>> @@ -0,0 +1,16 @@
>> +Broadcom bcm47xx/bcm53xx sprom converter
>> +
>> +This driver provbides an sprom based on a given nvram.
>> +
>> +Required properties:
>> +
>> +- compatible : brcm,bcm47xx-sprom
> 
> Please use a specific SoC here as the compatible string, not something
> with 'x' in it as a wildcard.

I will change that.

> 
>> +#define NVRAM_READ_VAL(type)						\
>> +static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
>> +				 const char *postfix, const char *name, \
>> +				 type *val, type allset)		\
>> +{									\
>> +	char buf[100];							\
>> +	int err;							\
>> +	type var;							\
>> +									\
>> +	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
>> +	if (err < 0)							\
>> +		return;							\
>> +	err = kstrto ## type(strim(buf), 0, &var);			\
>> +	if (err) {							\
>> +		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
>> +			fill->prefix, name, postfix, buf, err);		\
>> +		return;							\
>> +	}								\
>> +	if (allset && var == allset)					\
>> +		return;							\
>> +	*val = var;							\
>> +}
>> +
>> +NVRAM_READ_VAL(u8)
>> +NVRAM_READ_VAL(s8)
>> +NVRAM_READ_VAL(u16)
>> +NVRAM_READ_VAL(u32)
>> +
>> +#undef NVRAM_READ_VAL
> 
> Hmm, multiline macros are ugly. How about using one function to read
> into an s64 internally using kstrtoll, and simple inline wrappers around
> that for the smaller types, doing the appropriate range check?

Yes that should work I will try it.

>> +static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
>> +					const struct bcm47xx_sprom_fill *fill)
>> +{
>> +	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
>> +	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
>> +	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
>> +	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
>> +	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
>> +	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
>> +	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
>> +}
> 
> Rather than calling the same set of functions multiple times, can you
> do this using a table driven approach for smaller code size and
> improved readability?

I will try to change that.

>> +static int bcm47xx_sprom_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *np = dev->of_node;
>> +	struct ssb_sprom *sprom;
>> +	const __be32 *handle;
>> +	struct device_node *nvram_node;
>> +	struct platform_device *nvram_dev;
>> +	struct bcm47xx_sprom_fill fill;
>> +
>> +	/* Alloc */
>> +	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
>> +	if (!sprom)
>> +		return -ENOMEM;
>> +
>> +	handle = of_get_property(np, "nvram", NULL);
>> +	if (!handle)
>> +		return -ENOMEM;
>> +
>> +	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));
> 
> You can avoid the explicit be32_to_cpup here if you use
> of_property_read_u32 above.

Thanks for the hint.

Hauke

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-08-26 21:32       ` Hauke Mehrtens
  0 siblings, 0 replies; 70+ messages in thread
From: Hauke Mehrtens @ 2014-08-26 21:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/25/2014 09:52 AM, Arnd Bergmann wrote:
> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>> This driver needs an nvram driver and fetches the sprom values from the
>> nvram and provides it to any other driver. The calibration data for the
>> wifi chip the mac address and some more board description data is
>> stores in the sprom.
>>
>> This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
>> make the bcm47xx MIPS SoCs also use this driver some time later.
> 
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>> ---
>>  .../devicetree/bindings/misc/bcm47xx-sprom.txt     |  16 +
> 
> I'd prefer not to list the binding in a 'misc' category. Maybe we can
> have a new category and move the misc/sram.txt into the same?
> 
>>  drivers/misc/Kconfig                               |  14 +
>>  drivers/misc/Makefile                              |   1 +
>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
> 
> On a similar note, putting the driver into drivers/misc seems
> suboptimal: misc drivers should by definition be something that
> is for some odd hardware with no external dependencies on it,
> whereas your driver seems to be used by multiple other drivers.
> 
> Would it make sense to put it into drivers/bcma when that is the
> only bus it is used on?

As Jonas already said this code should be used for the bcm53xx ARM code
and the bcm47xx MIPS code and it is needed for drivers/bcma/ and
drivers/ssb/ (ssb only for old mips devices). Do you have any better
idea than putting this to drivers/misc/ ? For the mips SoC we need the
code very early and will not use the driver interface but probably
directly call the function name.
> 
>>  4 files changed, 721 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>>  create mode 100644 drivers/misc/bcm47xx-sprom.c
>>
>> diff --git a/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>> new file mode 100644
>> index 0000000..eed2a4a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
>> @@ -0,0 +1,16 @@
>> +Broadcom bcm47xx/bcm53xx sprom converter
>> +
>> +This driver provbides an sprom based on a given nvram.
>> +
>> +Required properties:
>> +
>> +- compatible : brcm,bcm47xx-sprom
> 
> Please use a specific SoC here as the compatible string, not something
> with 'x' in it as a wildcard.

I will change that.

> 
>> +#define NVRAM_READ_VAL(type)						\
>> +static void nvram_read_ ## type (const struct bcm47xx_sprom_fill *fill,	\
>> +				 const char *postfix, const char *name, \
>> +				 type *val, type allset)		\
>> +{									\
>> +	char buf[100];							\
>> +	int err;							\
>> +	type var;							\
>> +									\
>> +	err = get_nvram_var(fill, postfix, name, buf, sizeof(buf));	\
>> +	if (err < 0)							\
>> +		return;							\
>> +	err = kstrto ## type(strim(buf), 0, &var);			\
>> +	if (err) {							\
>> +		pr_warn("can not parse nvram name %s%s%s with value %s got %i\n",	\
>> +			fill->prefix, name, postfix, buf, err);		\
>> +		return;							\
>> +	}								\
>> +	if (allset && var == allset)					\
>> +		return;							\
>> +	*val = var;							\
>> +}
>> +
>> +NVRAM_READ_VAL(u8)
>> +NVRAM_READ_VAL(s8)
>> +NVRAM_READ_VAL(u16)
>> +NVRAM_READ_VAL(u32)
>> +
>> +#undef NVRAM_READ_VAL
> 
> Hmm, multiline macros are ugly. How about using one function to read
> into an s64 internally using kstrtoll, and simple inline wrappers around
> that for the smaller types, doing the appropriate range check?

Yes that should work I will try it.

>> +static void bcm47xx_sprom_fill_r1234589(struct ssb_sprom *sprom,
>> +					const struct bcm47xx_sprom_fill *fill)
>> +{
>> +	nvram_read_u16(fill, NULL, "devid", &sprom->dev_id, 0);
>> +	nvram_read_u8(fill, NULL, "ledbh0", &sprom->gpio0, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh1", &sprom->gpio1, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh2", &sprom->gpio2, 0xff);
>> +	nvram_read_u8(fill, NULL, "ledbh3", &sprom->gpio3, 0xff);
>> +	nvram_read_u8(fill, NULL, "aa2g", &sprom->ant_available_bg, 0);
>> +	nvram_read_u8(fill, NULL, "aa5g", &sprom->ant_available_a, 0);
>> +	nvram_read_s8(fill, NULL, "ag0", &sprom->antenna_gain.a0, 0);
>> +	nvram_read_s8(fill, NULL, "ag1", &sprom->antenna_gain.a1, 0);
>> +	nvram_read_alpha2(fill, "ccode", sprom->alpha2);
>> +}
> 
> Rather than calling the same set of functions multiple times, can you
> do this using a table driven approach for smaller code size and
> improved readability?

I will try to change that.

>> +static int bcm47xx_sprom_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *np = dev->of_node;
>> +	struct ssb_sprom *sprom;
>> +	const __be32 *handle;
>> +	struct device_node *nvram_node;
>> +	struct platform_device *nvram_dev;
>> +	struct bcm47xx_sprom_fill fill;
>> +
>> +	/* Alloc */
>> +	sprom = devm_kzalloc(dev, sizeof(*sprom), GFP_KERNEL);
>> +	if (!sprom)
>> +		return -ENOMEM;
>> +
>> +	handle = of_get_property(np, "nvram", NULL);
>> +	if (!handle)
>> +		return -ENOMEM;
>> +
>> +	nvram_node = of_find_node_by_phandle(be32_to_cpup(handle));
> 
> You can avoid the explicit be32_to_cpup here if you use
> of_property_read_u32 above.

Thanks for the hint.

Hauke

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27  5:54     ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-27  5:54 UTC (permalink / raw)
  To: Hauke Mehrtens; +Cc: linux-wireless, devicetree, linux-arm-kernel, linux-mips

On 24 August 2014 23:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> +On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
> +NOR flash is at 0x1e000000
> +
> +Example:
> +
> +nvram0: nvram@0 {
> +       compatible = "brcm,bcm47xx-nvram";
> +       reg = <0x1c000000 0x01000000>;
> +};

Could we avoid that? Type of flash can easily be checked in the code.
All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
core.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27  5:54     ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-27  5:54 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA

On 24 August 2014 23:24, Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org> wrote:
> +On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
> +NOR flash is at 0x1e000000
> +
> +Example:
> +
> +nvram0: nvram@0 {
> +       compatible = "brcm,bcm47xx-nvram";
> +       reg = <0x1c000000 0x01000000>;
> +};

Could we avoid that? Type of flash can easily be checked in the code.
All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
core.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27  5:54     ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-27  5:54 UTC (permalink / raw)
  To: Hauke Mehrtens; +Cc: linux-wireless, devicetree, linux-arm-kernel, linux-mips

On 24 August 2014 23:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> +On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
> +NOR flash is at 0x1e000000
> +
> +Example:
> +
> +nvram0: nvram@0 {
> +       compatible = "brcm,bcm47xx-nvram";
> +       reg = <0x1c000000 0x01000000>;
> +};

Could we avoid that? Type of flash can easily be checked in the code.
All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
core.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27  5:54     ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-27  5:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 24 August 2014 23:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> +On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
> +NOR flash is at 0x1e000000
> +
> +Example:
> +
> +nvram0: nvram at 0 {
> +       compatible = "brcm,bcm47xx-nvram";
> +       reg = <0x1c000000 0x01000000>;
> +};

Could we avoid that? Type of flash can easily be checked in the code.
All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
core.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
  2014-08-27  5:54     ` Rafał Miłecki
  (?)
@ 2014-08-27 18:20       ` Florian Fainelli
  -1 siblings, 0 replies; 70+ messages in thread
From: Florian Fainelli @ 2014-08-27 18:20 UTC (permalink / raw)
  To: Rafał Miłecki, Hauke Mehrtens
  Cc: devicetree, linux-wireless, linux-arm-kernel, linux-mips

On 08/26/2014 10:54 PM, Rafał Miłecki wrote:
> On 24 August 2014 23:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
>> +On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
>> +NOR flash is at 0x1e000000
>> +
>> +Example:
>> +
>> +nvram0: nvram@0 {
>> +       compatible = "brcm,bcm47xx-nvram";
>> +       reg = <0x1c000000 0x01000000>;
>> +};
> 
> Could we avoid that? Type of flash can easily be checked in the code.
> All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
> core.

So there is a boot status register you can read to tell what type of
flash you booted from, but does that also give you the resource ranges
for these type of flashes? Presumably they will be mapped into different
addresses (at least bcm63xx is like that), that information needs to be
listed somewhere.
--
Florian


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27 18:20       ` Florian Fainelli
  0 siblings, 0 replies; 70+ messages in thread
From: Florian Fainelli @ 2014-08-27 18:20 UTC (permalink / raw)
  To: Rafał Miłecki, Hauke Mehrtens
  Cc: devicetree, linux-wireless, linux-arm-kernel, linux-mips

On 08/26/2014 10:54 PM, Rafał Miłecki wrote:
> On 24 August 2014 23:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
>> +On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
>> +NOR flash is at 0x1e000000
>> +
>> +Example:
>> +
>> +nvram0: nvram@0 {
>> +       compatible = "brcm,bcm47xx-nvram";
>> +       reg = <0x1c000000 0x01000000>;
>> +};
> 
> Could we avoid that? Type of flash can easily be checked in the code.
> All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
> core.

So there is a boot status register you can read to tell what type of
flash you booted from, but does that also give you the resource ranges
for these type of flashes? Presumably they will be mapped into different
addresses (at least bcm63xx is like that), that information needs to be
listed somewhere.
--
Florian

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27 18:20       ` Florian Fainelli
  0 siblings, 0 replies; 70+ messages in thread
From: Florian Fainelli @ 2014-08-27 18:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/26/2014 10:54 PM, Rafa? Mi?ecki wrote:
> On 24 August 2014 23:24, Hauke Mehrtens <hauke@hauke-m.de> wrote:
>> +On NorthStar ARM SoCs the NAND flash is available at 0x1c000000 and the
>> +NOR flash is at 0x1e000000
>> +
>> +Example:
>> +
>> +nvram0: nvram at 0 {
>> +       compatible = "brcm,bcm47xx-nvram";
>> +       reg = <0x1c000000 0x01000000>;
>> +};
> 
> Could we avoid that? Type of flash can easily be checked in the code.
> All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
> core.

So there is a boot status register you can read to tell what type of
flash you booted from, but does that also give you the resource ranges
for these type of flashes? Presumably they will be mapped into different
addresses (at least bcm63xx is like that), that information needs to be
listed somewhere.
--
Florian

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 7/7] ARM: BCM5301X: register bcma bus
@ 2014-08-27 18:22     ` Florian Fainelli
  0 siblings, 0 replies; 70+ messages in thread
From: Florian Fainelli @ 2014-08-27 18:22 UTC (permalink / raw)
  To: Hauke Mehrtens, linux-wireless, devicetree, linux-arm-kernel, linux-mips
  Cc: zajec5

On 08/24/2014 02:24 PM, Hauke Mehrtens wrote:
> ---
>  arch/arm/boot/dts/bcm4708.dtsi | 58 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)

We probably want a compatible string for each of these aix subnodes you
are adding, so we can match them.

> 
> diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
> index 31141e8..7c240ab 100644
> --- a/arch/arm/boot/dts/bcm4708.dtsi
> +++ b/arch/arm/boot/dts/bcm4708.dtsi
> @@ -31,4 +31,62 @@
>  		};
>  	};
>  
> +	nvram0: nvram@0 {
> +		compatible = "brcm,bcm47xx-nvram";
> +		reg = <0x1c000000 0x01000000>;
> +	};
> +
> +	sprom0: sprom@0 {
> +		compatible = "brcm,bcm47xx-sprom";
> +		nvram = <&nvram0>;
> +	};
> +
> +	aix@18000000 {
> +		compatible = "brcm,bus-aix";
> +		reg = <0x18000000 0x1000>;
> +		ranges = <0x00000000 0x18000000 0x00100000>;
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		sprom = <&sprom0>;
> +
> +		usb2@0 {
> +			reg = <0x18021000 0x1000>;
> +			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		usb3@0 {
> +			reg = <0x18023000 0x1000>;
> +			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac@0 {
> +			reg = <0x18024000 0x1000>;
> +			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac@1 {
> +			reg = <0x18025000 0x1000>;
> +			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac@2 {
> +			reg = <0x18026000 0x1000>;
> +			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac@3 {
> +			reg = <0x18027000 0x1000>;
> +			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		pcie@0 {
> +			reg = <0x18012000 0x1000>;
> +			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		pcie@1 {
> +			reg = <0x18013000 0x1000>;
> +			interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +	};
>  };
> 


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 7/7] ARM: BCM5301X: register bcma bus
@ 2014-08-27 18:22     ` Florian Fainelli
  0 siblings, 0 replies; 70+ messages in thread
From: Florian Fainelli @ 2014-08-27 18:22 UTC (permalink / raw)
  To: Hauke Mehrtens, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
  Cc: zajec5-Re5JQEeQqe8AvxtiuMwx3w

On 08/24/2014 02:24 PM, Hauke Mehrtens wrote:
> ---
>  arch/arm/boot/dts/bcm4708.dtsi | 58 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)

We probably want a compatible string for each of these aix subnodes you
are adding, so we can match them.

> 
> diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
> index 31141e8..7c240ab 100644
> --- a/arch/arm/boot/dts/bcm4708.dtsi
> +++ b/arch/arm/boot/dts/bcm4708.dtsi
> @@ -31,4 +31,62 @@
>  		};
>  	};
>  
> +	nvram0: nvram@0 {
> +		compatible = "brcm,bcm47xx-nvram";
> +		reg = <0x1c000000 0x01000000>;
> +	};
> +
> +	sprom0: sprom@0 {
> +		compatible = "brcm,bcm47xx-sprom";
> +		nvram = <&nvram0>;
> +	};
> +
> +	aix@18000000 {
> +		compatible = "brcm,bus-aix";
> +		reg = <0x18000000 0x1000>;
> +		ranges = <0x00000000 0x18000000 0x00100000>;
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		sprom = <&sprom0>;
> +
> +		usb2@0 {
> +			reg = <0x18021000 0x1000>;
> +			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		usb3@0 {
> +			reg = <0x18023000 0x1000>;
> +			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac@0 {
> +			reg = <0x18024000 0x1000>;
> +			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac@1 {
> +			reg = <0x18025000 0x1000>;
> +			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac@2 {
> +			reg = <0x18026000 0x1000>;
> +			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac@3 {
> +			reg = <0x18027000 0x1000>;
> +			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		pcie@0 {
> +			reg = <0x18012000 0x1000>;
> +			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		pcie@1 {
> +			reg = <0x18013000 0x1000>;
> +			interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +	};
>  };
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 7/7] ARM: BCM5301X: register bcma bus
@ 2014-08-27 18:22     ` Florian Fainelli
  0 siblings, 0 replies; 70+ messages in thread
From: Florian Fainelli @ 2014-08-27 18:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/24/2014 02:24 PM, Hauke Mehrtens wrote:
> ---
>  arch/arm/boot/dts/bcm4708.dtsi | 58 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)

We probably want a compatible string for each of these aix subnodes you
are adding, so we can match them.

> 
> diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
> index 31141e8..7c240ab 100644
> --- a/arch/arm/boot/dts/bcm4708.dtsi
> +++ b/arch/arm/boot/dts/bcm4708.dtsi
> @@ -31,4 +31,62 @@
>  		};
>  	};
>  
> +	nvram0: nvram at 0 {
> +		compatible = "brcm,bcm47xx-nvram";
> +		reg = <0x1c000000 0x01000000>;
> +	};
> +
> +	sprom0: sprom at 0 {
> +		compatible = "brcm,bcm47xx-sprom";
> +		nvram = <&nvram0>;
> +	};
> +
> +	aix at 18000000 {
> +		compatible = "brcm,bus-aix";
> +		reg = <0x18000000 0x1000>;
> +		ranges = <0x00000000 0x18000000 0x00100000>;
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		sprom = <&sprom0>;
> +
> +		usb2 at 0 {
> +			reg = <0x18021000 0x1000>;
> +			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		usb3 at 0 {
> +			reg = <0x18023000 0x1000>;
> +			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac at 0 {
> +			reg = <0x18024000 0x1000>;
> +			interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac at 1 {
> +			reg = <0x18025000 0x1000>;
> +			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac at 2 {
> +			reg = <0x18026000 0x1000>;
> +			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		gmac at 3 {
> +			reg = <0x18027000 0x1000>;
> +			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		pcie at 0 {
> +			reg = <0x18012000 0x1000>;
> +			interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +
> +		pcie at 1 {
> +			reg = <0x18013000 0x1000>;
> +			interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +	};
>  };
> 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27 18:43         ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-27 18:43 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Hauke Mehrtens, devicetree, linux-wireless, linux-arm-kernel, linux-mips

On 27 August 2014 20:20, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 08/26/2014 10:54 PM, Rafał Miłecki wrote:
>> Could we avoid that? Type of flash can easily be checked in the code.
>> All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
>> core.
>
> So there is a boot status register you can read to tell what type of
> flash you booted from, but does that also give you the resource ranges
> for these type of flashes? Presumably they will be mapped into different
> addresses (at least bcm63xx is like that), that information needs to be
> listed somewhere.

Take a look at find_nvram in nvram_rw.c. It scans the whole region
which is up to 0x02000000 (SI_FLASH2_SZ) size.

In case of NAND limit is slightly different (nfl_boot_size function):
1) On ARM it's 0x800000 or 0x2600000
2) On MIPS it's 0x200000

-- 
Rafał

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27 18:43         ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-27 18:43 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Hauke Mehrtens, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA

On 27 August 2014 20:20, Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 08/26/2014 10:54 PM, Rafał Miłecki wrote:
>> Could we avoid that? Type of flash can easily be checked in the code.
>> All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
>> core.
>
> So there is a boot status register you can read to tell what type of
> flash you booted from, but does that also give you the resource ranges
> for these type of flashes? Presumably they will be mapped into different
> addresses (at least bcm63xx is like that), that information needs to be
> listed somewhere.

Take a look at find_nvram in nvram_rw.c. It scans the whole region
which is up to 0x02000000 (SI_FLASH2_SZ) size.

In case of NAND limit is slightly different (nfl_boot_size function):
1) On ARM it's 0x800000 or 0x2600000
2) On MIPS it's 0x200000

-- 
Rafał
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27 18:43         ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-27 18:43 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Hauke Mehrtens, devicetree, linux-wireless, linux-arm-kernel, linux-mips

On 27 August 2014 20:20, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 08/26/2014 10:54 PM, Rafał Miłecki wrote:
>> Could we avoid that? Type of flash can easily be checked in the code.
>> All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
>> core.
>
> So there is a boot status register you can read to tell what type of
> flash you booted from, but does that also give you the resource ranges
> for these type of flashes? Presumably they will be mapped into different
> addresses (at least bcm63xx is like that), that information needs to be
> listed somewhere.

Take a look at find_nvram in nvram_rw.c. It scans the whole region
which is up to 0x02000000 (SI_FLASH2_SZ) size.

In case of NAND limit is slightly different (nfl_boot_size function):
1) On ARM it's 0x800000 or 0x2600000
2) On MIPS it's 0x200000

-- 
Rafał

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support
@ 2014-08-27 18:43         ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-08-27 18:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 27 August 2014 20:20, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 08/26/2014 10:54 PM, Rafa? Mi?ecki wrote:
>> Could we avoid that? Type of flash can easily be checked in the code.
>> All we need to do is to read BCMA_IOST register of BCMA_CORE_NS_ROM
>> core.
>
> So there is a boot status register you can read to tell what type of
> flash you booted from, but does that also give you the resource ranges
> for these type of flashes? Presumably they will be mapped into different
> addresses (at least bcm63xx is like that), that information needs to be
> listed somewhere.

Take a look at find_nvram in nvram_rw.c. It scans the whole region
which is up to 0x02000000 (SI_FLASH2_SZ) size.

In case of NAND limit is slightly different (nfl_boot_size function):
1) On ARM it's 0x800000 or 0x2600000
2) On MIPS it's 0x200000

-- 
Rafa?

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-09-01  9:24         ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-09-01  9:24 UTC (permalink / raw)
  To: Hauke Mehrtens, Arnd Bergmann, Greg Kroah-Hartman
  Cc: linux-arm-kernel, linux-wireless, devicetree, linux-mips

On 26 August 2014 23:32, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> On 08/25/2014 09:52 AM, Arnd Bergmann wrote:
>> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>>>  drivers/misc/Kconfig                               |  14 +
>>>  drivers/misc/Makefile                              |   1 +
>>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
>>
>> On a similar note, putting the driver into drivers/misc seems
>> suboptimal: misc drivers should by definition be something that
>> is for some odd hardware with no external dependencies on it,
>> whereas your driver seems to be used by multiple other drivers.
>>
>> Would it make sense to put it into drivers/bcma when that is the
>> only bus it is used on?
>
> As Jonas already said this code should be used for the bcm53xx ARM code
> and the bcm47xx MIPS code and it is needed for drivers/bcma/ and
> drivers/ssb/ (ssb only for old mips devices). Do you have any better
> idea than putting this to drivers/misc/ ? For the mips SoC we need the
> code very early and will not use the driver interface but probably
> directly call the function name.

Ping? Does anyone have any better idea?

Both: nvram and sprom drivers will be used by bcm47xx (mips) and
bcm53xx (arm). They can't be put in drivers/bcma, as they are used by
drivers/ssb as well.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-09-01  9:24         ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-09-01  9:24 UTC (permalink / raw)
  To: Hauke Mehrtens, Arnd Bergmann, Greg Kroah-Hartman
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA

On 26 August 2014 23:32, Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org> wrote:
> On 08/25/2014 09:52 AM, Arnd Bergmann wrote:
>> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>>>  drivers/misc/Kconfig                               |  14 +
>>>  drivers/misc/Makefile                              |   1 +
>>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
>>
>> On a similar note, putting the driver into drivers/misc seems
>> suboptimal: misc drivers should by definition be something that
>> is for some odd hardware with no external dependencies on it,
>> whereas your driver seems to be used by multiple other drivers.
>>
>> Would it make sense to put it into drivers/bcma when that is the
>> only bus it is used on?
>
> As Jonas already said this code should be used for the bcm53xx ARM code
> and the bcm47xx MIPS code and it is needed for drivers/bcma/ and
> drivers/ssb/ (ssb only for old mips devices). Do you have any better
> idea than putting this to drivers/misc/ ? For the mips SoC we need the
> code very early and will not use the driver interface but probably
> directly call the function name.

Ping? Does anyone have any better idea?

Both: nvram and sprom drivers will be used by bcm47xx (mips) and
bcm53xx (arm). They can't be put in drivers/bcma, as they are used by
drivers/ssb as well.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-09-01  9:24         ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-09-01  9:24 UTC (permalink / raw)
  To: Hauke Mehrtens, Arnd Bergmann, Greg Kroah-Hartman
  Cc: linux-arm-kernel, linux-wireless, devicetree, linux-mips

On 26 August 2014 23:32, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> On 08/25/2014 09:52 AM, Arnd Bergmann wrote:
>> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>>>  drivers/misc/Kconfig                               |  14 +
>>>  drivers/misc/Makefile                              |   1 +
>>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
>>
>> On a similar note, putting the driver into drivers/misc seems
>> suboptimal: misc drivers should by definition be something that
>> is for some odd hardware with no external dependencies on it,
>> whereas your driver seems to be used by multiple other drivers.
>>
>> Would it make sense to put it into drivers/bcma when that is the
>> only bus it is used on?
>
> As Jonas already said this code should be used for the bcm53xx ARM code
> and the bcm47xx MIPS code and it is needed for drivers/bcma/ and
> drivers/ssb/ (ssb only for old mips devices). Do you have any better
> idea than putting this to drivers/misc/ ? For the mips SoC we need the
> code very early and will not use the driver interface but probably
> directly call the function name.

Ping? Does anyone have any better idea?

Both: nvram and sprom drivers will be used by bcm47xx (mips) and
bcm53xx (arm). They can't be put in drivers/bcma, as they are used by
drivers/ssb as well.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver
@ 2014-09-01  9:24         ` Rafał Miłecki
  0 siblings, 0 replies; 70+ messages in thread
From: Rafał Miłecki @ 2014-09-01  9:24 UTC (permalink / raw)
  To: linux-arm-kernel

On 26 August 2014 23:32, Hauke Mehrtens <hauke@hauke-m.de> wrote:
> On 08/25/2014 09:52 AM, Arnd Bergmann wrote:
>> On Sunday 24 August 2014 23:24:41 Hauke Mehrtens wrote:
>>>  drivers/misc/Kconfig                               |  14 +
>>>  drivers/misc/Makefile                              |   1 +
>>>  drivers/misc/bcm47xx-sprom.c                       | 690 +++++++++++++++++++++
>>
>> On a similar note, putting the driver into drivers/misc seems
>> suboptimal: misc drivers should by definition be something that
>> is for some odd hardware with no external dependencies on it,
>> whereas your driver seems to be used by multiple other drivers.
>>
>> Would it make sense to put it into drivers/bcma when that is the
>> only bus it is used on?
>
> As Jonas already said this code should be used for the bcm53xx ARM code
> and the bcm47xx MIPS code and it is needed for drivers/bcma/ and
> drivers/ssb/ (ssb only for old mips devices). Do you have any better
> idea than putting this to drivers/misc/ ? For the mips SoC we need the
> code very early and will not use the driver interface but probably
> directly call the function name.

Ping? Does anyone have any better idea?

Both: nvram and sprom drivers will be used by bcm47xx (mips) and
bcm53xx (arm). They can't be put in drivers/bcma, as they are used by
drivers/ssb as well.

^ permalink raw reply	[flat|nested] 70+ messages in thread

end of thread, other threads:[~2014-09-01  9:24 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-24 21:24 [RFC 0/7] bcma: add device tree support Hauke Mehrtens
2014-08-24 21:24 ` Hauke Mehrtens
2014-08-24 21:24 ` Hauke Mehrtens
2014-08-24 21:24 ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24 ` [RFC 1/7] MIPS: BCM47XX: move the nvram header file into common space Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24 ` [RFC 2/7] bcm47xx-nvram: add new broadcom nvram driver with dt support Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:45   ` Rafał Miłecki
2014-08-24 21:45     ` Rafał Miłecki
2014-08-24 21:45     ` Rafał Miłecki
2014-08-24 21:45     ` Rafał Miłecki
2014-08-27  5:54   ` Rafał Miłecki
2014-08-27  5:54     ` Rafał Miłecki
2014-08-27  5:54     ` Rafał Miłecki
2014-08-27  5:54     ` Rafał Miłecki
2014-08-27 18:20     ` Florian Fainelli
2014-08-27 18:20       ` Florian Fainelli
2014-08-27 18:20       ` Florian Fainelli
2014-08-27 18:43       ` Rafał Miłecki
2014-08-27 18:43         ` Rafał Miłecki
2014-08-27 18:43         ` Rafał Miłecki
2014-08-27 18:43         ` Rafał Miłecki
2014-08-24 21:24 ` [RFC 3/7] bcm47xx-sprom: add Broadcom sprom parser driver Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-25  7:52   ` Arnd Bergmann
2014-08-25  7:52     ` Arnd Bergmann
2014-08-25  7:52     ` Arnd Bergmann
2014-08-25 15:01     ` Jonas Gorski
2014-08-25 15:01       ` Jonas Gorski
2014-08-25 15:01       ` Jonas Gorski
2014-08-26 21:32     ` Hauke Mehrtens
2014-08-26 21:32       ` Hauke Mehrtens
2014-08-26 21:32       ` Hauke Mehrtens
2014-09-01  9:24       ` Rafał Miłecki
2014-09-01  9:24         ` Rafał Miłecki
2014-09-01  9:24         ` Rafał Miłecki
2014-09-01  9:24         ` Rafał Miłecki
2014-08-24 21:24 ` [RFC 4/7] bcma: register bcma as device tree driver Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-25  7:57   ` Arnd Bergmann
2014-08-25  7:57     ` Arnd Bergmann
2014-08-25  7:57     ` Arnd Bergmann
2014-08-26 21:25     ` Hauke Mehrtens
2014-08-26 21:25       ` Hauke Mehrtens
2014-08-26 21:25       ` Hauke Mehrtens
2014-08-24 21:24 ` [RFC 5/7] bcma: get IRQ numbers from dt Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-25  8:00   ` Arnd Bergmann
2014-08-25  8:00     ` Arnd Bergmann
2014-08-25  8:00     ` Arnd Bergmann
2014-08-24 21:24 ` [RFC 6/7] bcma: get sprom from devicetree Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-25  8:04   ` Arnd Bergmann
2014-08-25  8:04     ` Arnd Bergmann
2014-08-25  8:04     ` Arnd Bergmann
2014-08-24 21:24 ` [RFC 7/7] ARM: BCM5301X: register bcma bus Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-24 21:24   ` Hauke Mehrtens
2014-08-27 18:22   ` Florian Fainelli
2014-08-27 18:22     ` Florian Fainelli
2014-08-27 18:22     ` Florian Fainelli

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.