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.

404 lines
15 KiB

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