mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	Memory controller drivers for v5.16, part two
1. Convert LPDDR2 bindings to dtschema and extend them with new
    properties.
 2. Tegra 20 EMC: support matching timings by LPDDR2 configuration from
    devicetree.
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmFxMrMQHGtyemtAa2Vy
 bmVsLm9yZwAKCRDBN2bmhouD1zN4EACUUda2z/Ico+Y0J8ygDdHFa9CE2Q0rbWPc
 4cCeQSae+joWSTGxZUGIKd2SDCz2Ai0U2AOe4v9YqbmW4J6izdeUqaJHSorC7g+8
 /Or307HKwOi0kV8kwSC0AABPlkTFDTR5wjG908vAfEU4KfmkHXpKB7EJn2vpM/Km
 JzZ9K+v0Bm6VH5CLQZpcFiffXQJDeN1Cqve45g50BfpFITUche/TR8FRfJPJ90n0
 fJ2kjlMGT87U8tb4JKpYy6UoRCToxJq+uy/0nUAzUXAgBzM1zF9tVFGpw2WNUu1a
 j+PwFAA7eybX53BKFm0LfC/Z3PNJ+GYeDzUv+3VaSL+x5aNWRa1ffBBgWNAnnoWD
 QO0QGnZUxM+JEtTkgeByVblP4Aq4hmlSOJ3ErZ0NyH7iJyREqJEpJkXoSm0QIY4F
 TxiyrHJg0rSF4VTFU1qVBzn1m1VbfWR36RqOW29t8GJoMri8vCW7eyT0Z7xe4x8W
 er9kIGGpRQ2G3mtBRjHSXGjIztG5dVNbp5eEq7roJoQDcEcPnwox+8Au6NkA7JDS
 ednahUQ3qFEzS0vLXNgwvM1z77xPcgVFRRfdySfMUN0R3wBuhBp8EMTUNs2GrGSD
 KhxlK7WYcvwMy++o1M6Lmy7ukh40Tpgsmhg9CNr+eLTjJDs3rO/qdgteRnuQtsFd
 qh0PqiaX1w==
 =cTPK
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmFxwL0ACgkQmmx57+YA
 GNkfPw//ZFrn9+3SKYzXRgWKdPeGO9DfOrooEFe37DMsdCCDkTsZPxnKooidI61t
 g4UlgpPnnDEOas7glALgPwdFGqePzbocXgWtzgc/9kKNVNlJfE4OBVo8WykNSTOB
 Yqv38Z0Fz7XURfxzQCRHi9oMihkp0j9MaMmApO1/1ejYSueKnZ13OESPhmwrJBx0
 0oJCpkpOdxzfBlDaoaymSa0seWl1kAcWX6bya5dgDBGKKXhl69yLrqDSafmc57dx
 fOSgmpHSWPT+VavuGG6+p0daEk4vY3A37A/cVgaXl+Te02/O78luNHj0Wu1kjcxk
 lXhsBbb0iEyCUBRHpxwBm5cszm3yaN1GFnd0kW7vjV1kscnjwcDVJ8r9B/u1jIIj
 RQQq32QJ548c4eqSOT/OqhpI+r/R3z4pdFnaYiz6NDW5WY3UucKwoFCmhGRYk+T6
 Xp+5RreoUisDKg6rDDG6M6H/iTcYQw9W6NvLkf2HghokmcTG9cH1o/Q05COZe7dK
 yyZmb61fxS3SmsiWHrAtz2L8ztFibAjHjRfMV44TXX5JKp//hcMWg6HBMf+zD474
 wLsKGSimeKgSsy2NjqRwh3VSueA4ETrp4Iue2NaRCZ5ROnepCa6WzuUBPNTqXv+8
 HZTAHG7d7TAQ2O+hhShSGMP2tCkssuJ4OkmzbkPKDDe8xECaf9k=
 =NKAR
 -----END PGP SIGNATURE-----
Merge tag 'memory-controller-drv-5.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into arm/drivers
Memory controller drivers for v5.16, part two
1. Convert LPDDR2 bindings to dtschema and extend them with new
   properties.
2. Tegra 20 EMC: support matching timings by LPDDR2 configuration from
   devicetree.
* tag 'memory-controller-drv-5.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl:
  memory: tegra20-emc: Add runtime dependency on devfreq governor module
  memory: tegra20-emc: Support matching timings by LPDDR2 configuration
  memory: Add LPDDR2-info helpers
  dt-bindings: memory: tegra20: emc: Document new LPDDR2 sub-node
  dt-bindings: Add vendor prefix for Elpida Memory
  dt-bindings: memory: lpddr2: Document Elpida B8132B2PB-6D-F
  dt-bindings: memory: lpddr2: Add revision-id properties
  dt-bindings: memory: lpddr2: Convert to schema
  dt-bindings: Relocate DDR bindings
Link: https://lore.kernel.org/r/20211021093002.118192-1-krzysztof.kozlowski@canonical.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
			
			
This commit is contained in:
		
						commit
						bccb5d53e2
					
				
					 14 changed files with 622 additions and 121 deletions
				
			
		|  | @ -1,102 +0,0 @@ | |||
| * LPDDR2 SDRAM memories compliant to JEDEC JESD209-2 | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible : Should be one of - "jedec,lpddr2-nvm", "jedec,lpddr2-s2", | ||||
|   "jedec,lpddr2-s4" | ||||
| 
 | ||||
|   "ti,jedec-lpddr2-s2" should be listed if the memory part is LPDDR2-S2 type | ||||
| 
 | ||||
|   "ti,jedec-lpddr2-s4" should be listed if the memory part is LPDDR2-S4 type | ||||
| 
 | ||||
|   "ti,jedec-lpddr2-nvm" should be listed if the memory part is LPDDR2-NVM type | ||||
| 
 | ||||
| - density  : <u32> representing density in Mb (Mega bits) | ||||
| 
 | ||||
| - io-width : <u32> representing bus width. Possible values are 8, 16, and 32 | ||||
| 
 | ||||
| Optional properties: | ||||
| 
 | ||||
| The following optional properties represent the minimum value of some AC | ||||
| timing parameters of the DDR device in terms of number of clock cycles. | ||||
| These values shall be obtained from the device data-sheet. | ||||
| - tRRD-min-tck | ||||
| - tWTR-min-tck | ||||
| - tXP-min-tck | ||||
| - tRTP-min-tck | ||||
| - tCKE-min-tck | ||||
| - tRPab-min-tck | ||||
| - tRCD-min-tck | ||||
| - tWR-min-tck | ||||
| - tRASmin-min-tck | ||||
| - tCKESR-min-tck | ||||
| - tFAW-min-tck | ||||
| 
 | ||||
| Child nodes: | ||||
| - The lpddr2 node may have one or more child nodes of type "lpddr2-timings". | ||||
|   "lpddr2-timings" provides AC timing parameters of the device for | ||||
|   a given speed-bin. The user may provide the timings for as many | ||||
|   speed-bins as is required. Please see Documentation/devicetree/ | ||||
|   bindings/ddr/lpddr2-timings.txt for more information on "lpddr2-timings" | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| elpida_ECB240ABACN : lpddr2 { | ||||
| 	compatible	= "Elpida,ECB240ABACN","jedec,lpddr2-s4"; | ||||
| 	density		= <2048>; | ||||
| 	io-width	= <32>; | ||||
| 
 | ||||
| 	tRPab-min-tck	= <3>; | ||||
| 	tRCD-min-tck	= <3>; | ||||
| 	tWR-min-tck	= <3>; | ||||
| 	tRASmin-min-tck	= <3>; | ||||
| 	tRRD-min-tck	= <2>; | ||||
| 	tWTR-min-tck	= <2>; | ||||
| 	tXP-min-tck	= <2>; | ||||
| 	tRTP-min-tck	= <2>; | ||||
| 	tCKE-min-tck	= <3>; | ||||
| 	tCKESR-min-tck	= <3>; | ||||
| 	tFAW-min-tck	= <8>; | ||||
| 
 | ||||
| 	timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { | ||||
| 		compatible	= "jedec,lpddr2-timings"; | ||||
| 		min-freq	= <10000000>; | ||||
| 		max-freq	= <400000000>; | ||||
| 		tRPab		= <21000>; | ||||
| 		tRCD		= <18000>; | ||||
| 		tWR		= <15000>; | ||||
| 		tRAS-min	= <42000>; | ||||
| 		tRRD		= <10000>; | ||||
| 		tWTR		= <7500>; | ||||
| 		tXP		= <7500>; | ||||
| 		tRTP		= <7500>; | ||||
| 		tCKESR		= <15000>; | ||||
| 		tDQSCK-max	= <5500>; | ||||
| 		tFAW		= <50000>; | ||||
| 		tZQCS		= <90000>; | ||||
| 		tZQCL		= <360000>; | ||||
| 		tZQinit		= <1000000>; | ||||
| 		tRAS-max-ns	= <70000>; | ||||
| 	}; | ||||
| 
 | ||||
| 	timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 { | ||||
| 		compatible	= "jedec,lpddr2-timings"; | ||||
| 		min-freq	= <10000000>; | ||||
| 		max-freq	= <200000000>; | ||||
| 		tRPab		= <21000>; | ||||
| 		tRCD		= <18000>; | ||||
| 		tWR		= <15000>; | ||||
| 		tRAS-min	= <42000>; | ||||
| 		tRRD		= <10000>; | ||||
| 		tWTR		= <10000>; | ||||
| 		tXP		= <7500>; | ||||
| 		tRTP		= <7500>; | ||||
| 		tCKESR		= <15000>; | ||||
| 		tDQSCK-max	= <5500>; | ||||
| 		tFAW		= <50000>; | ||||
| 		tZQCS		= <90000>; | ||||
| 		tZQCL		= <360000>; | ||||
| 		tZQinit		= <1000000>; | ||||
| 		tRAS-max-ns	= <70000>; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,223 @@ | |||
| # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||
| %YAML 1.2 | ||||
| --- | ||||
| $id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr2.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: LPDDR2 SDRAM compliant to JEDEC JESD209-2 | ||||
| 
 | ||||
| maintainers: | ||||
|   - Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> | ||||
| 
 | ||||
| properties: | ||||
|   compatible: | ||||
|     oneOf: | ||||
|       - items: | ||||
|           - enum: | ||||
|               - elpida,ECB240ABACN | ||||
|               - elpida,B8132B2PB-6D-F | ||||
|           - enum: | ||||
|               - jedec,lpddr2-s4 | ||||
|       - items: | ||||
|           - enum: | ||||
|               - jedec,lpddr2-s2 | ||||
|       - items: | ||||
|           - enum: | ||||
|               - jedec,lpddr2-nvm | ||||
| 
 | ||||
|   revision-id1: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 255 | ||||
|     description: | | ||||
|       Revision 1 value of SDRAM chip. Obtained from device datasheet. | ||||
| 
 | ||||
|   revision-id2: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 255 | ||||
|     description: | | ||||
|       Revision 2 value of SDRAM chip. Obtained from device datasheet. | ||||
| 
 | ||||
|   density: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     description: | | ||||
|       Density in megabits of SDRAM chip. Obtained from device datasheet. | ||||
|     enum: | ||||
|       - 64 | ||||
|       - 128 | ||||
|       - 256 | ||||
|       - 512 | ||||
|       - 1024 | ||||
|       - 2048 | ||||
|       - 4096 | ||||
|       - 8192 | ||||
|       - 16384 | ||||
|       - 32768 | ||||
| 
 | ||||
|   io-width: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     description: | | ||||
|       IO bus width in bits of SDRAM chip. Obtained from device datasheet. | ||||
|     enum: | ||||
|       - 32 | ||||
|       - 16 | ||||
|       - 8 | ||||
| 
 | ||||
|   tRRD-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       Active bank a to active bank b in terms of number of clock cycles. | ||||
|       Obtained from device datasheet. | ||||
| 
 | ||||
|   tWTR-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       Internal WRITE-to-READ command delay in terms of number of clock cycles. | ||||
|       Obtained from device datasheet. | ||||
| 
 | ||||
|   tXP-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       Exit power-down to next valid command delay in terms of number of clock | ||||
|       cycles. Obtained from device datasheet. | ||||
| 
 | ||||
|   tRTP-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       Internal READ to PRECHARGE command delay in terms of number of clock | ||||
|       cycles. Obtained from device datasheet. | ||||
| 
 | ||||
|   tCKE-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       CKE minimum pulse width (HIGH and LOW pulse width) in terms of number | ||||
|       of clock cycles. Obtained from device datasheet. | ||||
| 
 | ||||
|   tRPab-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       Row precharge time (all banks) in terms of number of clock cycles. | ||||
|       Obtained from device datasheet. | ||||
| 
 | ||||
|   tRCD-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       RAS-to-CAS delay in terms of number of clock cycles. Obtained from | ||||
|       device datasheet. | ||||
| 
 | ||||
|   tWR-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       WRITE recovery time in terms of number of clock cycles. Obtained from | ||||
|       device datasheet. | ||||
| 
 | ||||
|   tRASmin-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       Row active time in terms of number of clock cycles. Obtained from device | ||||
|       datasheet. | ||||
| 
 | ||||
|   tCKESR-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       CKE minimum pulse width during SELF REFRESH (low pulse width during | ||||
|       SELF REFRESH) in terms of number of clock cycles. Obtained from device | ||||
|       datasheet. | ||||
| 
 | ||||
|   tFAW-min-tck: | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
|     maximum: 16 | ||||
|     description: | | ||||
|       Four-bank activate window in terms of number of clock cycles. Obtained | ||||
|       from device datasheet. | ||||
| 
 | ||||
| patternProperties: | ||||
|   "^lpddr2-timings": | ||||
|     type: object | ||||
|     description: | | ||||
|       The lpddr2 node may have one or more child nodes of type "lpddr2-timings". | ||||
|       "lpddr2-timings" provides AC timing parameters of the device for | ||||
|       a given speed-bin. The user may provide the timings for as many | ||||
|       speed-bins as is required. Please see Documentation/devicetree/ | ||||
|       bindings/memory-controllers/ddr/lpddr2-timings.txt for more information | ||||
|       on "lpddr2-timings". | ||||
| 
 | ||||
| required: | ||||
|   - compatible | ||||
|   - density | ||||
|   - io-width | ||||
| 
 | ||||
| additionalProperties: false | ||||
| 
 | ||||
| examples: | ||||
|   - | | ||||
|     elpida_ECB240ABACN: lpddr2 { | ||||
|         compatible = "elpida,ECB240ABACN", "jedec,lpddr2-s4"; | ||||
|         density = <2048>; | ||||
|         io-width = <32>; | ||||
|         revision-id1 = <1>; | ||||
|         revision-id2 = <0>; | ||||
| 
 | ||||
|         tRPab-min-tck = <3>; | ||||
|         tRCD-min-tck = <3>; | ||||
|         tWR-min-tck = <3>; | ||||
|         tRASmin-min-tck = <3>; | ||||
|         tRRD-min-tck = <2>; | ||||
|         tWTR-min-tck = <2>; | ||||
|         tXP-min-tck = <2>; | ||||
|         tRTP-min-tck = <2>; | ||||
|         tCKE-min-tck = <3>; | ||||
|         tCKESR-min-tck = <3>; | ||||
|         tFAW-min-tck = <8>; | ||||
| 
 | ||||
|         timings_elpida_ECB240ABACN_400mhz: lpddr2-timings0 { | ||||
|             compatible = "jedec,lpddr2-timings"; | ||||
|             min-freq = <10000000>; | ||||
|             max-freq = <400000000>; | ||||
|             tRPab = <21000>; | ||||
|             tRCD = <18000>; | ||||
|             tWR = <15000>; | ||||
|             tRAS-min = <42000>; | ||||
|             tRRD = <10000>; | ||||
|             tWTR = <7500>; | ||||
|             tXP = <7500>; | ||||
|             tRTP = <7500>; | ||||
|             tCKESR = <15000>; | ||||
|             tDQSCK-max = <5500>; | ||||
|             tFAW = <50000>; | ||||
|             tZQCS = <90000>; | ||||
|             tZQCL = <360000>; | ||||
|             tZQinit = <1000000>; | ||||
|             tRAS-max-ns = <70000>; | ||||
|         }; | ||||
| 
 | ||||
|         timings_elpida_ECB240ABACN_200mhz: lpddr2-timings1 { | ||||
|             compatible = "jedec,lpddr2-timings"; | ||||
|             min-freq = <10000000>; | ||||
|             max-freq = <200000000>; | ||||
|             tRPab = <21000>; | ||||
|             tRCD = <18000>; | ||||
|             tWR = <15000>; | ||||
|             tRAS-min = <42000>; | ||||
|             tRRD = <10000>; | ||||
|             tWTR = <10000>; | ||||
|             tXP = <7500>; | ||||
|             tRTP = <7500>; | ||||
|             tCKESR = <15000>; | ||||
|             tDQSCK-max = <5500>; | ||||
|             tFAW = <50000>; | ||||
|             tZQCS = <90000>; | ||||
|             tZQCL = <360000>; | ||||
|             tZQinit = <1000000>; | ||||
|             tRAS-max-ns = <70000>; | ||||
|         }; | ||||
|     }; | ||||
|  | @ -43,8 +43,9 @@ These values shall be obtained from the device data-sheet. | |||
| Child nodes: | ||||
| - The lpddr3 node may have one or more child nodes of type "lpddr3-timings". | ||||
|   "lpddr3-timings" provides AC timing parameters of the device for | ||||
|   a given speed-bin. Please see Documentation/devicetree/ | ||||
|   bindings/ddr/lpddr3-timings.txt for more information on "lpddr3-timings" | ||||
|   a given speed-bin. Please see | ||||
|   Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3-timings.txt | ||||
|   for more information on "lpddr3-timings" | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
|  | @ -164,12 +164,20 @@ patternProperties: | |||
|       "#size-cells": | ||||
|         const: 0 | ||||
| 
 | ||||
|       lpddr2: | ||||
|         $ref: "ddr/jedec,lpddr2.yaml#" | ||||
|         type: object | ||||
| 
 | ||||
|     patternProperties: | ||||
|       "^emc-table@[0-9]+$": | ||||
|         $ref: "#/$defs/emc-table" | ||||
| 
 | ||||
|     required: | ||||
|       - nvidia,ram-code | ||||
|     oneOf: | ||||
|       - required: | ||||
|           - nvidia,ram-code | ||||
| 
 | ||||
|       - required: | ||||
|           - lpddr2 | ||||
| 
 | ||||
|     additionalProperties: false | ||||
| 
 | ||||
|  | @ -227,4 +235,15 @@ examples: | |||
|                         0x00000000 0x00000000 0x00000000 0x00000000>; | ||||
|             }; | ||||
|         }; | ||||
| 
 | ||||
|         emc-tables@1 { | ||||
|             reg = <1>; | ||||
| 
 | ||||
|             lpddr2 { | ||||
|                 compatible = "elpida,B8132B2PB-6D-F", "jedec,lpddr2-s4"; | ||||
|                 revision-id1 = <1>; | ||||
|                 density = <2048>; | ||||
|                 io-width = <16>; | ||||
|             }; | ||||
|         }; | ||||
|     }; | ||||
|  |  | |||
|  | @ -51,7 +51,8 @@ properties: | |||
|     $ref: '/schemas/types.yaml#/definitions/phandle' | ||||
|     description: | | ||||
|       phandle of the connected DRAM memory device. For more information please | ||||
|       refer to documentation file: Documentation/devicetree/bindings/ddr/lpddr3.txt | ||||
|       refer to documentation file: | ||||
|       Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3.txt | ||||
| 
 | ||||
|   operating-points-v2: true | ||||
| 
 | ||||
|  |  | |||
|  | @ -353,6 +353,8 @@ patternProperties: | |||
|     description: Shenzhen Elida Technology Co., Ltd. | ||||
|   "^elimo,.*": | ||||
|     description: Elimo Engineering Ltd. | ||||
|   "^elpida,.*": | ||||
|     description: Elpida Memory, Inc. | ||||
|   "^embest,.*": | ||||
|     description: Shenzhen Embest Technology Co., Ltd. | ||||
|   "^emlid,.*": | ||||
|  |  | |||
|  | @ -112,6 +112,26 @@ | |||
| #define NUM_DDR_ADDR_TABLE_ENTRIES			11 | ||||
| #define NUM_DDR_TIMING_TABLE_ENTRIES			4 | ||||
| 
 | ||||
| #define LPDDR2_MANID_SAMSUNG				1 | ||||
| #define LPDDR2_MANID_QIMONDA				2 | ||||
| #define LPDDR2_MANID_ELPIDA				3 | ||||
| #define LPDDR2_MANID_ETRON				4 | ||||
| #define LPDDR2_MANID_NANYA				5 | ||||
| #define LPDDR2_MANID_HYNIX				6 | ||||
| #define LPDDR2_MANID_MOSEL				7 | ||||
| #define LPDDR2_MANID_WINBOND				8 | ||||
| #define LPDDR2_MANID_ESMT				9 | ||||
| #define LPDDR2_MANID_SPANSION				11 | ||||
| #define LPDDR2_MANID_SST				12 | ||||
| #define LPDDR2_MANID_ZMOS				13 | ||||
| #define LPDDR2_MANID_INTEL				14 | ||||
| #define LPDDR2_MANID_NUMONYX				254 | ||||
| #define LPDDR2_MANID_MICRON				255 | ||||
| 
 | ||||
| #define LPDDR2_TYPE_S4					0 | ||||
| #define LPDDR2_TYPE_S2					1 | ||||
| #define LPDDR2_TYPE_NVM					2 | ||||
| 
 | ||||
| /* Structure for DDR addressing info from the JEDEC spec */ | ||||
| struct lpddr2_addressing { | ||||
| 	u32 num_banks; | ||||
|  | @ -170,6 +190,33 @@ extern const struct lpddr2_timings | |||
| 	lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES]; | ||||
| extern const struct lpddr2_min_tck lpddr2_jedec_min_tck; | ||||
| 
 | ||||
| /* Structure of MR8 */ | ||||
| union lpddr2_basic_config4 { | ||||
| 	u32 value; | ||||
| 
 | ||||
| 	struct { | ||||
| 		unsigned int arch_type : 2; | ||||
| 		unsigned int density : 4; | ||||
| 		unsigned int io_width : 2; | ||||
| 	} __packed; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Structure for information about LPDDR2 chip. All parameters are | ||||
|  * matching raw values of standard mode register bitfields or set to | ||||
|  * -ENOENT if info unavailable. | ||||
|  */ | ||||
| struct lpddr2_info { | ||||
| 	int arch_type; | ||||
| 	int density; | ||||
| 	int io_width; | ||||
| 	int manufacturer_id; | ||||
| 	int revision_id1; | ||||
| 	int revision_id2; | ||||
| }; | ||||
| 
 | ||||
| const char *lpddr2_jedec_manufacturer(unsigned int manufacturer_id); | ||||
| 
 | ||||
| /*
 | ||||
|  * Structure for timings for LPDDR3 based on LPDDR2 plus additional fields. | ||||
|  * All parameters are in pico seconds(ps) excluding max_freq, min_freq which | ||||
|  |  | |||
|  | @ -131,3 +131,44 @@ const struct lpddr2_min_tck lpddr2_jedec_min_tck = { | |||
| 	.tFAW		= 8 | ||||
| }; | ||||
| EXPORT_SYMBOL_GPL(lpddr2_jedec_min_tck); | ||||
| 
 | ||||
| const char *lpddr2_jedec_manufacturer(unsigned int manufacturer_id) | ||||
| { | ||||
| 	switch (manufacturer_id) { | ||||
| 	case LPDDR2_MANID_SAMSUNG: | ||||
| 		return "Samsung"; | ||||
| 	case LPDDR2_MANID_QIMONDA: | ||||
| 		return "Qimonda"; | ||||
| 	case LPDDR2_MANID_ELPIDA: | ||||
| 		return "Elpida"; | ||||
| 	case LPDDR2_MANID_ETRON: | ||||
| 		return "Etron"; | ||||
| 	case LPDDR2_MANID_NANYA: | ||||
| 		return "Nanya"; | ||||
| 	case LPDDR2_MANID_HYNIX: | ||||
| 		return "Hynix"; | ||||
| 	case LPDDR2_MANID_MOSEL: | ||||
| 		return "Mosel"; | ||||
| 	case LPDDR2_MANID_WINBOND: | ||||
| 		return "Winbond"; | ||||
| 	case LPDDR2_MANID_ESMT: | ||||
| 		return "ESMT"; | ||||
| 	case LPDDR2_MANID_SPANSION: | ||||
| 		return "Spansion"; | ||||
| 	case LPDDR2_MANID_SST: | ||||
| 		return "SST"; | ||||
| 	case LPDDR2_MANID_ZMOS: | ||||
| 		return "ZMOS"; | ||||
| 	case LPDDR2_MANID_INTEL: | ||||
| 		return "Intel"; | ||||
| 	case LPDDR2_MANID_NUMONYX: | ||||
| 		return "Numonyx"; | ||||
| 	case LPDDR2_MANID_MICRON: | ||||
| 		return "Micron"; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return "invalid"; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(lpddr2_jedec_manufacturer); | ||||
|  |  | |||
|  | @ -298,3 +298,90 @@ default_timings: | |||
| 	return NULL; | ||||
| } | ||||
| EXPORT_SYMBOL(of_lpddr3_get_ddr_timings); | ||||
| 
 | ||||
| /**
 | ||||
|  * of_lpddr2_get_info() - extracts information about the lpddr2 chip. | ||||
|  * @np: Pointer to device tree node containing lpddr2 info | ||||
|  * @dev: Device requesting info | ||||
|  * | ||||
|  * Populates lpddr2_info structure by extracting data from device | ||||
|  * tree node. Returns pointer to populated structure. If error | ||||
|  * happened while populating, returns NULL. If property is missing | ||||
|  * in a device-tree, then the corresponding value is set to -ENOENT. | ||||
|  */ | ||||
| const struct lpddr2_info | ||||
| *of_lpddr2_get_info(struct device_node *np, struct device *dev) | ||||
| { | ||||
| 	struct lpddr2_info *ret_info, info = {}; | ||||
| 	struct property *prop; | ||||
| 	const char *cp; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = of_property_read_u32(np, "revision-id1", &info.revision_id1); | ||||
| 	if (err) | ||||
| 		info.revision_id1 = -ENOENT; | ||||
| 
 | ||||
| 	err = of_property_read_u32(np, "revision-id2", &info.revision_id2); | ||||
| 	if (err) | ||||
| 		info.revision_id2 = -ENOENT; | ||||
| 
 | ||||
| 	err = of_property_read_u32(np, "io-width", &info.io_width); | ||||
| 	if (err) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	info.io_width = 32 / info.io_width - 1; | ||||
| 
 | ||||
| 	err = of_property_read_u32(np, "density", &info.density); | ||||
| 	if (err) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	info.density = ffs(info.density) - 7; | ||||
| 
 | ||||
| 	if (of_device_is_compatible(np, "jedec,lpddr2-s4")) | ||||
| 		info.arch_type = LPDDR2_TYPE_S4; | ||||
| 	else if (of_device_is_compatible(np, "jedec,lpddr2-s2")) | ||||
| 		info.arch_type = LPDDR2_TYPE_S2; | ||||
| 	else if (of_device_is_compatible(np, "jedec,lpddr2-nvm")) | ||||
| 		info.arch_type = LPDDR2_TYPE_NVM; | ||||
| 	else | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	prop = of_find_property(np, "compatible", NULL); | ||||
| 	for (cp = of_prop_next_string(prop, NULL); cp; | ||||
| 	     cp = of_prop_next_string(prop, cp)) { | ||||
| 
 | ||||
| #define OF_LPDDR2_VENDOR_CMP(compat, ID) \ | ||||
| 		if (!of_compat_cmp(cp, compat ",", strlen(compat ","))) { \ | ||||
| 			info.manufacturer_id = LPDDR2_MANID_##ID; \ | ||||
| 			break; \ | ||||
| 		} | ||||
| 
 | ||||
| 		OF_LPDDR2_VENDOR_CMP("samsung", SAMSUNG) | ||||
| 		OF_LPDDR2_VENDOR_CMP("qimonda", QIMONDA) | ||||
| 		OF_LPDDR2_VENDOR_CMP("elpida", ELPIDA) | ||||
| 		OF_LPDDR2_VENDOR_CMP("etron", ETRON) | ||||
| 		OF_LPDDR2_VENDOR_CMP("nanya", NANYA) | ||||
| 		OF_LPDDR2_VENDOR_CMP("hynix", HYNIX) | ||||
| 		OF_LPDDR2_VENDOR_CMP("mosel", MOSEL) | ||||
| 		OF_LPDDR2_VENDOR_CMP("winbond", WINBOND) | ||||
| 		OF_LPDDR2_VENDOR_CMP("esmt", ESMT) | ||||
| 		OF_LPDDR2_VENDOR_CMP("spansion", SPANSION) | ||||
| 		OF_LPDDR2_VENDOR_CMP("sst", SST) | ||||
| 		OF_LPDDR2_VENDOR_CMP("zmos", ZMOS) | ||||
| 		OF_LPDDR2_VENDOR_CMP("intel", INTEL) | ||||
| 		OF_LPDDR2_VENDOR_CMP("numonyx", NUMONYX) | ||||
| 		OF_LPDDR2_VENDOR_CMP("micron", MICRON) | ||||
| 
 | ||||
| #undef OF_LPDDR2_VENDOR_CMP | ||||
| 	} | ||||
| 
 | ||||
| 	if (!info.manufacturer_id) | ||||
| 		info.manufacturer_id = -ENOENT; | ||||
| 
 | ||||
| 	ret_info = devm_kzalloc(dev, sizeof(*ret_info), GFP_KERNEL); | ||||
| 	if (ret_info) | ||||
| 		*ret_info = info; | ||||
| 
 | ||||
| 	return ret_info; | ||||
| } | ||||
| EXPORT_SYMBOL(of_lpddr2_get_info); | ||||
|  |  | |||
|  | @ -20,6 +20,9 @@ const struct lpddr3_min_tck *of_lpddr3_get_min_tck(struct device_node *np, | |||
| const struct lpddr3_timings * | ||||
| of_lpddr3_get_ddr_timings(struct device_node *np_ddr, | ||||
| 			  struct device *dev, u32 device_type, u32 *nr_frequencies); | ||||
| 
 | ||||
| const struct lpddr2_info *of_lpddr2_get_info(struct device_node *np, | ||||
| 					     struct device *dev); | ||||
| #else | ||||
| static inline const struct lpddr2_min_tck | ||||
| 	*of_get_min_tck(struct device_node *np, struct device *dev) | ||||
|  | @ -46,6 +49,12 @@ static inline const struct lpddr3_timings | |||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline const struct lpddr2_info | ||||
| 	*of_lpddr2_get_info(struct device_node *np, struct device *dev) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| #endif /* CONFIG_OF && CONFIG_DDR */ | ||||
| 
 | ||||
| #endif /* __LINUX_MEMORY_OF_REG_ */ | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ config TEGRA20_EMC | |||
| 	depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST | ||||
| 	select DEVFREQ_GOV_SIMPLE_ONDEMAND | ||||
| 	select PM_DEVFREQ | ||||
| 	select DDR | ||||
| 	help | ||||
| 	  This driver is for the External Memory Controller (EMC) found on | ||||
| 	  Tegra20 chips. The EMC controls the external DRAM on the board. | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
|  * Author: Dmitry Osipenko <digetx@gmail.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/bitfield.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/clk/tegra.h> | ||||
| #include <linux/debugfs.h> | ||||
|  | @ -27,11 +28,15 @@ | |||
| #include <soc/tegra/common.h> | ||||
| #include <soc/tegra/fuse.h> | ||||
| 
 | ||||
| #include "../jedec_ddr.h" | ||||
| #include "../of_memory.h" | ||||
| 
 | ||||
| #include "mc.h" | ||||
| 
 | ||||
| #define EMC_INTSTATUS				0x000 | ||||
| #define EMC_INTMASK				0x004 | ||||
| #define EMC_DBG					0x008 | ||||
| #define EMC_ADR_CFG_0				0x010 | ||||
| #define EMC_TIMING_CONTROL			0x028 | ||||
| #define EMC_RC					0x02c | ||||
| #define EMC_RFC					0x030 | ||||
|  | @ -68,6 +73,7 @@ | |||
| #define EMC_QUSE_EXTRA				0x0ac | ||||
| #define EMC_ODT_WRITE				0x0b0 | ||||
| #define EMC_ODT_READ				0x0b4 | ||||
| #define EMC_MRR					0x0ec | ||||
| #define EMC_FBIO_CFG5				0x104 | ||||
| #define EMC_FBIO_CFG6				0x114 | ||||
| #define EMC_STAT_CONTROL			0x160 | ||||
|  | @ -94,6 +100,7 @@ | |||
| 
 | ||||
| #define EMC_REFRESH_OVERFLOW_INT		BIT(3) | ||||
| #define EMC_CLKCHANGE_COMPLETE_INT		BIT(4) | ||||
| #define EMC_MRR_DIVLD_INT			BIT(5) | ||||
| 
 | ||||
| #define EMC_DBG_READ_MUX_ASSEMBLY		BIT(0) | ||||
| #define EMC_DBG_WRITE_MUX_ACTIVE		BIT(1) | ||||
|  | @ -102,11 +109,25 @@ | |||
| #define EMC_DBG_CFG_PRIORITY			BIT(24) | ||||
| 
 | ||||
| #define EMC_FBIO_CFG5_DRAM_WIDTH_X16		BIT(4) | ||||
| #define EMC_FBIO_CFG5_DRAM_TYPE			GENMASK(1, 0) | ||||
| 
 | ||||
| #define EMC_MRR_DEV_SELECTN			GENMASK(31, 30) | ||||
| #define EMC_MRR_MRR_MA				GENMASK(23, 16) | ||||
| #define EMC_MRR_MRR_DATA			GENMASK(15, 0) | ||||
| 
 | ||||
| #define EMC_ADR_CFG_0_EMEM_NUMDEV		GENMASK(25, 24) | ||||
| 
 | ||||
| #define EMC_PWR_GATHER_CLEAR			(1 << 8) | ||||
| #define EMC_PWR_GATHER_DISABLE			(2 << 8) | ||||
| #define EMC_PWR_GATHER_ENABLE			(3 << 8) | ||||
| 
 | ||||
| enum emc_dram_type { | ||||
| 	DRAM_TYPE_RESERVED, | ||||
| 	DRAM_TYPE_DDR1, | ||||
| 	DRAM_TYPE_LPDDR2, | ||||
| 	DRAM_TYPE_DDR2, | ||||
| }; | ||||
| 
 | ||||
| static const u16 emc_timing_registers[] = { | ||||
| 	EMC_RC, | ||||
| 	EMC_RFC, | ||||
|  | @ -201,6 +222,14 @@ struct tegra_emc { | |||
| 	struct mutex rate_lock; | ||||
| 
 | ||||
| 	struct devfreq_simple_ondemand_data ondemand_data; | ||||
| 
 | ||||
| 	/* memory chip identity information */ | ||||
| 	union lpddr2_basic_config4 basic_conf4; | ||||
| 	unsigned int manufacturer_id; | ||||
| 	unsigned int revision_id1; | ||||
| 	unsigned int revision_id2; | ||||
| 
 | ||||
| 	bool mrr_error; | ||||
| }; | ||||
| 
 | ||||
| static irqreturn_t tegra_emc_isr(int irq, void *data) | ||||
|  | @ -397,15 +426,19 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, | |||
| 	if (!emc->timings) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	emc->num_timings = child_count; | ||||
| 	timing = emc->timings; | ||||
| 
 | ||||
| 	for_each_child_of_node(node, child) { | ||||
| 		if (of_node_name_eq(child, "lpddr2")) | ||||
| 			continue; | ||||
| 
 | ||||
| 		err = load_one_timing_from_dt(emc, timing++, child); | ||||
| 		if (err) { | ||||
| 			of_node_put(child); | ||||
| 			return err; | ||||
| 		} | ||||
| 
 | ||||
| 		emc->num_timings++; | ||||
| 	} | ||||
| 
 | ||||
| 	sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, | ||||
|  | @ -422,12 +455,18 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, | |||
| } | ||||
| 
 | ||||
| static struct device_node * | ||||
| tegra_emc_find_node_by_ram_code(struct device *dev) | ||||
| tegra_emc_find_node_by_ram_code(struct tegra_emc *emc) | ||||
| { | ||||
| 	struct device *dev = emc->dev; | ||||
| 	struct device_node *np; | ||||
| 	u32 value, ram_code; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (emc->mrr_error) { | ||||
| 		dev_warn(dev, "memory timings skipped due to MRR error\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (of_get_child_count(dev->of_node) == 0) { | ||||
| 		dev_info_once(dev, "device-tree doesn't have memory timings\n"); | ||||
| 		return NULL; | ||||
|  | @ -442,8 +481,49 @@ tegra_emc_find_node_by_ram_code(struct device *dev) | |||
| 	     np = of_find_node_by_name(np, "emc-tables")) { | ||||
| 		err = of_property_read_u32(np, "nvidia,ram-code", &value); | ||||
| 		if (err || value != ram_code) { | ||||
| 			of_node_put(np); | ||||
| 			continue; | ||||
| 			struct device_node *lpddr2_np; | ||||
| 			bool cfg_mismatches = false; | ||||
| 
 | ||||
| 			lpddr2_np = of_find_node_by_name(np, "lpddr2"); | ||||
| 			if (lpddr2_np) { | ||||
| 				const struct lpddr2_info *info; | ||||
| 
 | ||||
| 				info = of_lpddr2_get_info(lpddr2_np, dev); | ||||
| 				if (info) { | ||||
| 					if (info->manufacturer_id >= 0 && | ||||
| 					    info->manufacturer_id != emc->manufacturer_id) | ||||
| 						cfg_mismatches = true; | ||||
| 
 | ||||
| 					if (info->revision_id1 >= 0 && | ||||
| 					    info->revision_id1 != emc->revision_id1) | ||||
| 						cfg_mismatches = true; | ||||
| 
 | ||||
| 					if (info->revision_id2 >= 0 && | ||||
| 					    info->revision_id2 != emc->revision_id2) | ||||
| 						cfg_mismatches = true; | ||||
| 
 | ||||
| 					if (info->density != emc->basic_conf4.density) | ||||
| 						cfg_mismatches = true; | ||||
| 
 | ||||
| 					if (info->io_width != emc->basic_conf4.io_width) | ||||
| 						cfg_mismatches = true; | ||||
| 
 | ||||
| 					if (info->arch_type != emc->basic_conf4.arch_type) | ||||
| 						cfg_mismatches = true; | ||||
| 				} else { | ||||
| 					dev_err(dev, "failed to parse %pOF\n", lpddr2_np); | ||||
| 					cfg_mismatches = true; | ||||
| 				} | ||||
| 
 | ||||
| 				of_node_put(lpddr2_np); | ||||
| 			} else { | ||||
| 				cfg_mismatches = true; | ||||
| 			} | ||||
| 
 | ||||
| 			if (cfg_mismatches) { | ||||
| 				of_node_put(np); | ||||
| 				continue; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return np; | ||||
|  | @ -455,10 +535,72 @@ tegra_emc_find_node_by_ram_code(struct device *dev) | |||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static int emc_read_lpddr_mode_register(struct tegra_emc *emc, | ||||
| 					unsigned int emem_dev, | ||||
| 					unsigned int register_addr, | ||||
| 					unsigned int *register_data) | ||||
| { | ||||
| 	u32 memory_dev = emem_dev + 1; | ||||
| 	u32 val, mr_mask = 0xff; | ||||
| 	int err; | ||||
| 
 | ||||
| 	/* clear data-valid interrupt status */ | ||||
| 	writel_relaxed(EMC_MRR_DIVLD_INT, emc->regs + EMC_INTSTATUS); | ||||
| 
 | ||||
| 	/* issue mode register read request */ | ||||
| 	val  = FIELD_PREP(EMC_MRR_DEV_SELECTN, memory_dev); | ||||
| 	val |= FIELD_PREP(EMC_MRR_MRR_MA, register_addr); | ||||
| 
 | ||||
| 	writel_relaxed(val, emc->regs + EMC_MRR); | ||||
| 
 | ||||
| 	/* wait for the LPDDR2 data-valid interrupt */ | ||||
| 	err = readl_relaxed_poll_timeout_atomic(emc->regs + EMC_INTSTATUS, val, | ||||
| 						val & EMC_MRR_DIVLD_INT, | ||||
| 						1, 100); | ||||
| 	if (err) { | ||||
| 		dev_err(emc->dev, "mode register %u read failed: %d\n", | ||||
| 			register_addr, err); | ||||
| 		emc->mrr_error = true; | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	/* read out mode register data */ | ||||
| 	val = readl_relaxed(emc->regs + EMC_MRR); | ||||
| 	*register_data = FIELD_GET(EMC_MRR_MRR_DATA, val) & mr_mask; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void emc_read_lpddr_sdram_info(struct tegra_emc *emc, | ||||
| 				      unsigned int emem_dev, | ||||
| 				      bool print_out) | ||||
| { | ||||
| 	/* these registers are standard for all LPDDR JEDEC memory chips */ | ||||
| 	emc_read_lpddr_mode_register(emc, emem_dev, 5, &emc->manufacturer_id); | ||||
| 	emc_read_lpddr_mode_register(emc, emem_dev, 6, &emc->revision_id1); | ||||
| 	emc_read_lpddr_mode_register(emc, emem_dev, 7, &emc->revision_id2); | ||||
| 	emc_read_lpddr_mode_register(emc, emem_dev, 8, &emc->basic_conf4.value); | ||||
| 
 | ||||
| 	if (!print_out) | ||||
| 		return; | ||||
| 
 | ||||
| 	dev_info(emc->dev, "SDRAM[dev%u]: manufacturer: 0x%x (%s) rev1: 0x%x rev2: 0x%x prefetch: S%u density: %uMbit iowidth: %ubit\n", | ||||
| 		 emem_dev, emc->manufacturer_id, | ||||
| 		 lpddr2_jedec_manufacturer(emc->manufacturer_id), | ||||
| 		 emc->revision_id1, emc->revision_id2, | ||||
| 		 4 >> emc->basic_conf4.arch_type, | ||||
| 		 64 << emc->basic_conf4.density, | ||||
| 		 32 >> emc->basic_conf4.io_width); | ||||
| } | ||||
| 
 | ||||
| static int emc_setup_hw(struct tegra_emc *emc) | ||||
| { | ||||
| 	u32 emc_cfg, emc_dbg, emc_fbio, emc_adr_cfg; | ||||
| 	u32 intmask = EMC_REFRESH_OVERFLOW_INT; | ||||
| 	u32 emc_cfg, emc_dbg, emc_fbio; | ||||
| 	static bool print_sdram_info_once; | ||||
| 	enum emc_dram_type dram_type; | ||||
| 	const char *dram_type_str; | ||||
| 	unsigned int emem_numdev; | ||||
| 
 | ||||
| 	emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2); | ||||
| 
 | ||||
|  | @ -496,7 +638,36 @@ static int emc_setup_hw(struct tegra_emc *emc) | |||
| 	else | ||||
| 		emc->dram_bus_width = 32; | ||||
| 
 | ||||
| 	dev_info_once(emc->dev, "%ubit DRAM bus\n", emc->dram_bus_width); | ||||
| 	dram_type = FIELD_GET(EMC_FBIO_CFG5_DRAM_TYPE, emc_fbio); | ||||
| 
 | ||||
| 	switch (dram_type) { | ||||
| 	case DRAM_TYPE_RESERVED: | ||||
| 		dram_type_str = "INVALID"; | ||||
| 		break; | ||||
| 	case DRAM_TYPE_DDR1: | ||||
| 		dram_type_str = "DDR1"; | ||||
| 		break; | ||||
| 	case DRAM_TYPE_LPDDR2: | ||||
| 		dram_type_str = "LPDDR2"; | ||||
| 		break; | ||||
| 	case DRAM_TYPE_DDR2: | ||||
| 		dram_type_str = "DDR2"; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	emc_adr_cfg = readl_relaxed(emc->regs + EMC_ADR_CFG_0); | ||||
| 	emem_numdev = FIELD_GET(EMC_ADR_CFG_0_EMEM_NUMDEV, emc_adr_cfg) + 1; | ||||
| 
 | ||||
| 	dev_info_once(emc->dev, "%ubit DRAM bus, %u %s %s attached\n", | ||||
| 		      emc->dram_bus_width, emem_numdev, dram_type_str, | ||||
| 		      emem_numdev == 2 ? "devices" : "device"); | ||||
| 
 | ||||
| 	if (dram_type == DRAM_TYPE_LPDDR2) { | ||||
| 		while (emem_numdev--) | ||||
| 			emc_read_lpddr_sdram_info(emc, emem_numdev, | ||||
| 						  !print_sdram_info_once); | ||||
| 		print_sdram_info_once = true; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -1049,14 +1220,6 @@ static int tegra_emc_probe(struct platform_device *pdev) | |||
| 	emc->clk_nb.notifier_call = tegra_emc_clk_change_notify; | ||||
| 	emc->dev = &pdev->dev; | ||||
| 
 | ||||
| 	np = tegra_emc_find_node_by_ram_code(&pdev->dev); | ||||
| 	if (np) { | ||||
| 		err = tegra_emc_load_timings_from_dt(emc, np); | ||||
| 		of_node_put(np); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 	} | ||||
| 
 | ||||
| 	emc->regs = devm_platform_ioremap_resource(pdev, 0); | ||||
| 	if (IS_ERR(emc->regs)) | ||||
| 		return PTR_ERR(emc->regs); | ||||
|  | @ -1065,6 +1228,14 @@ static int tegra_emc_probe(struct platform_device *pdev) | |||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	np = tegra_emc_find_node_by_ram_code(emc); | ||||
| 	if (np) { | ||||
| 		err = tegra_emc_load_timings_from_dt(emc, np); | ||||
| 		of_node_put(np); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 	} | ||||
| 
 | ||||
| 	err = devm_request_irq(&pdev->dev, irq, tegra_emc_isr, 0, | ||||
| 			       dev_name(&pdev->dev), emc); | ||||
| 	if (err) { | ||||
|  | @ -1117,4 +1288,5 @@ module_platform_driver(tegra_emc_driver); | |||
| 
 | ||||
| MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>"); | ||||
| MODULE_DESCRIPTION("NVIDIA Tegra20 EMC driver"); | ||||
| MODULE_SOFTDEP("pre: governor_simpleondemand"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Arnd Bergmann
						Arnd Bergmann