You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

342 lines
12 KiB

3 years ago
2 years ago
3 years ago
4 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. # SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
  2. #
  3. # SPDX-License-Identifier: MIT
  4. """
  5. `adafruit_platformdetect.chip`
  6. ================================================================================
  7. Attempt detection of current chip / CPU
  8. * Author(s): Melissa LeBlanc-Williams
  9. Implementation Notes
  10. --------------------
  11. **Software and Dependencies:**
  12. * Linux and Python 3.6 or Higher
  13. """
  14. # imports
  15. import os
  16. import sys
  17. from adafruit_platformdetect.constants import chips
  18. __version__ = "0.0.0-auto.0"
  19. __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PlatformDetect.git"
  20. class Chip:
  21. """Attempt detection of current chip / CPU."""
  22. def __init__(self, detector):
  23. self.detector = detector
  24. self._chip_id = None
  25. @property
  26. def id(
  27. self,
  28. ): # pylint: disable=invalid-name,too-many-branches,too-many-return-statements
  29. """Return a unique id for the detected chip, if any."""
  30. # There are some times we want to trick the platform detection
  31. # say if a raspberry pi doesn't have the right ID, or for testing
  32. # Caching
  33. if self._chip_id:
  34. return self._chip_id
  35. if getattr(os, "environ", None) is not None:
  36. try:
  37. return os.environ["BLINKA_FORCECHIP"]
  38. except KeyError: # no forced chip, continue with testing!
  39. pass
  40. # Special cases controlled by environment var
  41. if os.environ.get("BLINKA_FT232H"):
  42. from pyftdi.usbtools import UsbTools
  43. # look for it based on PID/VID
  44. count = len(UsbTools.find_all([(0x0403, 0x6014)]))
  45. if count == 0:
  46. raise RuntimeError(
  47. "BLINKA_FT232H environment variable "
  48. + "set, but no FT232H device found"
  49. )
  50. self._chip_id = chips.FT232H
  51. return self._chip_id
  52. if os.environ.get("BLINKA_FT2232H"):
  53. from pyftdi.usbtools import UsbTools
  54. # look for it based on PID/VID
  55. count = len(UsbTools.find_all([(0x0403, 0x6010)]))
  56. if count == 0:
  57. raise RuntimeError(
  58. "BLINKA_FT2232H environment variable "
  59. + "set, but no FT2232H device found"
  60. )
  61. self._chip_id = chips.FT2232H
  62. return self._chip_id
  63. if os.environ.get("BLINKA_MCP2221"):
  64. import hid
  65. # look for it based on PID/VID
  66. for dev in hid.enumerate():
  67. if dev["vendor_id"] == 0x04D8 and dev["product_id"] == 0x00DD:
  68. self._chip_id = chips.MCP2221
  69. return self._chip_id
  70. raise RuntimeError(
  71. "BLINKA_MCP2221 environment variable "
  72. + "set, but no MCP2221 device found"
  73. )
  74. if os.environ.get("BLINKA_U2IF"):
  75. import hid
  76. # look for it based on PID/VID
  77. for dev in hid.enumerate():
  78. vendor = dev["vendor_id"]
  79. product = dev["product_id"]
  80. # NOTE: If any products are added here, they need added
  81. # to _rp2040_u2if_id() in board.py as well.
  82. if (
  83. # Raspberry Pi Pico
  84. vendor == 0xCAFE
  85. and product == 0x4005
  86. ) or (
  87. # Feather RP2040
  88. # Itsy Bitsy RP2040
  89. # QT Py RP2040
  90. # QT2040 Trinkey
  91. # MacroPad RP2040
  92. vendor == 0x239A
  93. and product in (0x00F1, 0x00FD, 0x00F7, 0x0109, 0x0107)
  94. ):
  95. self._chip_id = chips.RP2040_U2IF
  96. return self._chip_id
  97. raise RuntimeError(
  98. "BLINKA_U2IF environment variable "
  99. + "set, but no compatible device found"
  100. )
  101. if os.environ.get("BLINKA_GREATFET"):
  102. import usb
  103. if usb.core.find(idVendor=0x1D50, idProduct=0x60E6) is not None:
  104. self._chip_id = chips.LPC4330
  105. return self._chip_id
  106. raise RuntimeError(
  107. "BLINKA_GREATFET environment variable "
  108. + "set, but no GreatFET device found"
  109. )
  110. if os.environ.get("BLINKA_NOVA"):
  111. self._chip_id = chips.BINHO
  112. return self._chip_id
  113. platform = sys.platform
  114. if platform in ("linux", "linux2"):
  115. self._chip_id = self._linux_id()
  116. return self._chip_id
  117. if platform == "esp8266":
  118. self._chip_id = chips.ESP8266
  119. return self._chip_id
  120. if platform == "samd21":
  121. self._chip_id = chips.SAMD21
  122. return self._chip_id
  123. if platform == "pyboard":
  124. self._chip_id = chips.STM32F405
  125. return self._chip_id
  126. if platform == "rp2":
  127. self._chip_id = chips.RP2040
  128. return self._chip_id
  129. # nothing found!
  130. return None
  131. # pylint: enable=invalid-name
  132. def _linux_id(self):
  133. # pylint: disable=too-many-branches,too-many-statements
  134. # pylint: disable=too-many-return-statements
  135. """Attempt to detect the CPU on a computer running the Linux kernel."""
  136. if self.detector.check_dt_compatible_value("sun8i-h3"):
  137. return chips.H3
  138. if self.detector.check_dt_compatible_value("qcom,apq8016"):
  139. return chips.APQ8016
  140. if self.detector.check_dt_compatible_value("fu500"):
  141. return chips.HFU540
  142. if self.detector.check_dt_compatible_value("sun20iw1p1"):
  143. return chips.C906
  144. # Older Builds
  145. if self.detector.check_dt_compatible_value("sifive"):
  146. return chips.JH71x0
  147. # Newer Builds
  148. if self.detector.check_dt_compatible_value("jh7100"):
  149. return chips.JH71x0
  150. if self.detector.check_dt_compatible_value("sun8i-a33"):
  151. return chips.A33
  152. if self.detector.check_dt_compatible_value("rockchip,rk3308"):
  153. return chips.RK3308
  154. if self.detector.check_dt_compatible_value("rockchip,rk3399"):
  155. return chips.RK3399
  156. if self.detector.check_dt_compatible_value("rockchip,rk3288"):
  157. return chips.RK3288
  158. if self.detector.check_dt_compatible_value("rockchip,rk3328"):
  159. return chips.RK3328
  160. if self.detector.check_dt_compatible_value("st,stm32mp157"):
  161. return chips.STM32MP157
  162. if self.detector.check_dt_compatible_value("sun50i-a64"):
  163. return chips.A64
  164. if self.detector.check_dt_compatible_value("sun50i-h5"):
  165. return chips.H5
  166. if self.detector.check_dt_compatible_value("sun50i-h616"):
  167. return chips.H616
  168. if self.detector.check_dt_compatible_value("sun50iw9"):
  169. return chips.H616
  170. if self.detector.check_dt_compatible_value("sun50i-h6"):
  171. return chips.H6
  172. if self.detector.check_dt_compatible_value("mediatek,mt8167"):
  173. return chips.MT8167
  174. if self.detector.check_dt_compatible_value("imx6ull"):
  175. return chips.IMX6ULL
  176. if self.detector.check_dt_compatible_value("ti,j721e"):
  177. return chips.TDA4VM
  178. linux_id = None
  179. hardware = self.detector.get_cpuinfo_field("Hardware")
  180. if hardware is None:
  181. vendor_id = self.detector.get_cpuinfo_field("vendor_id")
  182. if vendor_id == "AuthenticAMD":
  183. model_name = self.detector.get_cpuinfo_field("model name").upper()
  184. if "RYZEN EMBEDDED V1202B" in model_name:
  185. linux_id = chips.RYZEN_V1202B
  186. if "RYZEN EMBEDDED V1605B" in model_name:
  187. linux_id = chips.RYZEN_V1605B
  188. else:
  189. linux_id = chips.GENERIC_X86
  190. ## print("linux_id = ", linux_id)
  191. elif vendor_id == "GenuineIntel":
  192. model_name = self.detector.get_cpuinfo_field("model name").upper()
  193. ## print('model_name =', model_name)
  194. if "N3710" in model_name:
  195. linux_id = chips.PENTIUM_N3710
  196. elif "X5-Z8350" in model_name:
  197. linux_id = chips.ATOM_X5_Z8350
  198. else:
  199. linux_id = chips.GENERIC_X86
  200. ## print("linux_id = ", linux_id)
  201. compatible = self.detector.get_device_compatible()
  202. if compatible and "tegra" in compatible:
  203. compats = compatible.split("\x00")
  204. if "nvidia,tegra210" in compats:
  205. linux_id = chips.T210
  206. elif "nvidia,tegra186" in compats:
  207. linux_id = chips.T186
  208. elif "nvidia,tegra194" in compats:
  209. linux_id = chips.T194
  210. if compatible and "imx8m" in compatible:
  211. linux_id = chips.IMX8MX
  212. if compatible and "odroid-c2" in compatible:
  213. linux_id = chips.S905
  214. if compatible and "amlogic" in compatible:
  215. compatible_list = (
  216. compatible.replace("\x00", ",").replace(" ", "").split(",")
  217. )
  218. if "g12a" in compatible_list:
  219. # 'sm1' is correct for S905X3, but some kernels use 'g12a'
  220. return chips.S905X3
  221. if "g12b" in compatible_list:
  222. return chips.S922X
  223. if "sm1" in compatible_list:
  224. return chips.S905X3
  225. if compatible and "sun50i-a64" in compatible:
  226. linux_id = chips.A64
  227. if compatible and "sun50i-h6" in compatible:
  228. linux_id = chips.H6
  229. if compatible and "sun50i-h5" in compatible:
  230. linux_id = chips.H5
  231. if compatible and "odroid-xu4" in compatible:
  232. linux_id = chips.EXYNOS5422
  233. cpu_model = self.detector.get_cpuinfo_field("cpu model")
  234. if cpu_model is not None:
  235. if "MIPS 24Kc" in cpu_model:
  236. linux_id = chips.MIPS24KC
  237. elif "MIPS 24KEc" in cpu_model:
  238. linux_id = chips.MIPS24KEC
  239. # we still haven't identified the hardware, so
  240. # convert it to a list and let the remaining
  241. # conditions attempt.
  242. if not linux_id:
  243. hardware = [
  244. entry.replace("\x00", "") for entry in compatible.split(",")
  245. ]
  246. if not linux_id:
  247. if "AM33XX" in hardware:
  248. linux_id = chips.AM33XX
  249. elif "DRA74X" in hardware:
  250. linux_id = chips.DRA74X
  251. elif "sun8i" in hardware:
  252. linux_id = chips.SUN8I
  253. elif "ODROIDC" in hardware:
  254. linux_id = chips.S805
  255. elif "ODROID-C2" in hardware:
  256. linux_id = chips.S905
  257. elif "ODROID-N2" in hardware:
  258. linux_id = chips.S922X
  259. elif "ODROID-C4" in hardware:
  260. linux_id = chips.S905X3
  261. elif "ODROID-XU4" in hardware:
  262. linux_id = chips.EXYNOS5422
  263. elif "SAMA5" in hardware:
  264. linux_id = chips.SAMA5
  265. elif "Pinebook" in hardware:
  266. linux_id = chips.A64
  267. elif "ASUS_TINKER_BOARD" in hardware:
  268. linux_id = chips.RK3288
  269. elif "Xilinx Zynq" in hardware:
  270. compatible = self.detector.get_device_compatible()
  271. if compatible and "xlnx,zynq-7000" in compatible:
  272. linux_id = chips.ZYNQ7000
  273. else:
  274. if isinstance(hardware, str):
  275. if hardware.upper() in chips.BCM_RANGE:
  276. linux_id = chips.BCM2XXX
  277. elif isinstance(hardware, list):
  278. if {model.upper() for model in hardware} & chips.BCM_RANGE:
  279. linux_id = chips.BCM2XXX
  280. return linux_id
  281. def __getattr__(self, attr):
  282. """
  283. Detect whether the given attribute is the currently-detected chip. See
  284. list of constants at the top of this module for available options.
  285. """
  286. if self.id == attr:
  287. return True
  288. return False